go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/pkg/incrutil/map.go (about)

     1  /*
     2  
     3  Copyright (c) 2023 - Present. Will Charczuk. All rights reserved.
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file at the root of the repository.
     5  
     6  */
     7  
     8  package incrutil
     9  
    10  import (
    11  	"context"
    12  	"fmt"
    13  
    14  	"github.com/wcharczuk/go-incr"
    15  )
    16  
    17  // MapN applies a function to given list of input incrementals and returns
    18  // a new incremental of the output type of that function.
    19  func Map[A, B any](scope incr.Scope, fn MapFunc[A, B]) MapIncr[A, B] {
    20  	return incr.WithinScope(scope, &mapIncr[A, B]{
    21  		n:  incr.NewNode("map"),
    22  		fn: fn,
    23  	})
    24  }
    25  
    26  // MapNFunc is the function that the ApplyN incremental applies.
    27  type MapFunc[A, B any] func(context.Context, A) (B, error)
    28  
    29  // MapNIncr is a type of incremental that can add inputs over time.
    30  type MapIncr[A, B any] interface {
    31  	incr.Incr[B]
    32  	ISetInput
    33  	IRemoveInput
    34  	IInputs
    35  	IRawValue
    36  	ISetRawValue
    37  	IRawFunction
    38  	ISetRawFunction
    39  	AddInput(incr.Incr[A])
    40  }
    41  
    42  var (
    43  	_ incr.Incr[string]    = (*mapIncr[int, string])(nil)
    44  	_ MapIncr[int, string] = (*mapIncr[int, string])(nil)
    45  	_ incr.INode           = (*mapIncr[int, string])(nil)
    46  	_ incr.IStabilize      = (*mapIncr[int, string])(nil)
    47  	_ fmt.Stringer         = (*mapIncr[int, string])(nil)
    48  )
    49  
    50  type mapIncr[A, B any] struct {
    51  	n     *incr.Node
    52  	input incr.Incr[A]
    53  	fn    MapFunc[A, B]
    54  	val   B
    55  }
    56  
    57  func (m *mapIncr[A, B]) Parents() []incr.INode {
    58  	if m.input != nil {
    59  		return []incr.INode{m.input}
    60  	}
    61  	return nil
    62  }
    63  
    64  func (m *mapIncr[A, B]) RawValue() any {
    65  	return m.val
    66  }
    67  
    68  func (m *mapIncr[A, B]) SetRawValue(value any) error {
    69  	var typed B
    70  	if err := CastAny(value, &typed); err != nil {
    71  		return err
    72  	}
    73  	m.val = typed
    74  	return nil
    75  }
    76  
    77  func (m *mapIncr[A, B]) AddInput(i incr.Incr[A]) {
    78  	m.input = i
    79  	LinkNodes(m, i)
    80  }
    81  
    82  func (m *mapIncr[A, B]) SetInput(name string, i incr.INode, _ bool) error {
    83  	typed, ok := i.(incr.Incr[A])
    84  	if !ok || typed == nil {
    85  		return fmt.Errorf("invalid untyped input for map node %T", i)
    86  	}
    87  	m.input = typed
    88  	LinkNodes(m, i)
    89  	return nil
    90  }
    91  
    92  func (m *mapIncr[A, B]) RemoveInput(name string) error {
    93  	if m.input != nil {
    94  		UnlinkNodes(m, m.input)
    95  		m.input = nil
    96  		return nil
    97  	}
    98  	return fmt.Errorf("remove input; input is unset")
    99  }
   100  
   101  func (m *mapIncr[A, B]) Inputs() map[string]incr.INode {
   102  	if m.input != nil {
   103  		return map[string]incr.INode{
   104  			"input": m.input,
   105  		}
   106  	}
   107  	return nil
   108  }
   109  
   110  func (m *mapIncr[A, B]) RawFunction() any {
   111  	return m.fn
   112  }
   113  
   114  func (m *mapIncr[A, B]) SetRawFunction(fn any) error {
   115  	typed, ok := fn.(MapFunc[A, B])
   116  	if !ok {
   117  		return fmt.Errorf("invalid function type for node: %T", fn)
   118  	}
   119  	m.fn = typed
   120  	return nil
   121  }
   122  
   123  func (m *mapIncr[A, B]) Node() *incr.Node { return m.n }
   124  
   125  func (m *mapIncr[A, B]) Value() B { return m.val }
   126  
   127  func (m *mapIncr[A, B]) Stabilize(ctx context.Context) (err error) {
   128  	if m.input != nil {
   129  		var val B
   130  		val, err = m.fn(ctx, m.input.Value())
   131  		if err != nil {
   132  			err = fmt.Errorf("%v; %w", m, err)
   133  			return
   134  		}
   135  		m.val = val
   136  	}
   137  	return nil
   138  }
   139  
   140  func (m *mapIncr[A, B]) String() string {
   141  	return m.n.String()
   142  }