go.charczuk.com@v0.0.0-20240327042549-bc490516bd1a/projects/nodes/pkg/incrutil/map2.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 "go.charczuk.com/sdk/errutil" 16 ) 17 18 // MapN applies a function to given list of input incrementals and returns 19 // a new incremental of the output type of that function. 20 func Map2[A, B, C any](scope incr.Scope, fn Map2Func[A, B, C]) Map2Incr[A, B, C] { 21 return incr.WithinScope(scope, &map2Incr[A, B, C]{ 22 n: incr.NewNode("map2"), 23 fn: fn, 24 }) 25 } 26 27 // Map2Func is the function that the ApplyN incremental applies. 28 type Map2Func[A, B, C any] func(context.Context, A, B) (C, error) 29 30 // MapNIncr is a type of incremental that can add inputs over time. 31 type Map2Incr[A, B, C any] interface { 32 incr.Incr[C] 33 ISetInput 34 IRemoveInput 35 IInputs 36 IRawFunction 37 ISetRawFunction 38 IRawValue 39 ISetRawValue 40 } 41 42 var ( 43 _ incr.Incr[bool] = (*map2Incr[int, string, bool])(nil) 44 _ Map2Incr[int, string, bool] = (*map2Incr[int, string, bool])(nil) 45 _ incr.INode = (*map2Incr[int, string, bool])(nil) 46 _ incr.IStabilize = (*map2Incr[int, string, bool])(nil) 47 _ fmt.Stringer = (*map2Incr[int, string, bool])(nil) 48 ) 49 50 type map2Incr[A, B, C any] struct { 51 n *incr.Node 52 a incr.Incr[A] 53 b incr.Incr[B] 54 fn Map2Func[A, B, C] 55 val C 56 } 57 58 func (m *map2Incr[A, B, C]) Parents() (out []incr.INode) { 59 if m.a != nil { 60 out = append(out, m.a) 61 } 62 if m.b != nil { 63 out = append(out, m.b) 64 } 65 return 66 } 67 68 func (m *map2Incr[A, B, C]) RawValue() any { 69 return m.val 70 } 71 72 func (m *map2Incr[A, B, C]) SetRawValue(value any) error { 73 var typed C 74 if err := CastAny(value, &typed); err != nil { 75 return err 76 } 77 m.val = typed 78 return nil 79 } 80 81 func (mn *map2Incr[A, B, C]) RawFunction() any { 82 return mn.fn 83 } 84 85 func (mn *map2Incr[A, B, C]) Inputs() map[string]incr.INode { 86 output := make(map[string]incr.INode) 87 if mn.a != nil { 88 output["a"] = mn.a 89 } 90 if mn.b != nil { 91 output["b"] = mn.b 92 } 93 return output 94 } 95 96 func (mn *map2Incr[A, B, C]) SetInput(name string, input incr.INode, _ bool) error { 97 if name == "0" || name == "a" { 98 typed, ok := input.(incr.Incr[A]) 99 if !ok { 100 return fmt.Errorf("set input; invalid input type for input %v: %T", name, input) 101 } 102 mn.a = typed 103 LinkNodes(mn, mn.a) 104 return nil 105 } else if name == "1" || name == "b" { 106 typed, ok := input.(incr.Incr[B]) 107 if !ok { 108 return fmt.Errorf("set input; invalid input type for input %v: %T", name, input) 109 } 110 mn.b = typed 111 LinkNodes(mn, mn.b) 112 return nil 113 } 114 return fmt.Errorf("set input; invalid input name: %v", name) 115 } 116 117 func (mn *map2Incr[A, B, C]) RemoveInput(name string) error { 118 if name == "0" || name == "a" { 119 if mn.a != nil { 120 UnlinkNodes(mn, mn.a) 121 mn.a = nil 122 return nil 123 } 124 return fmt.Errorf("remove input; input unset: %v", name) 125 } else if name == "1" || name == "b" { 126 if mn.b != nil { 127 UnlinkNodes(mn, mn.b) 128 mn.b = nil 129 return nil 130 } 131 return fmt.Errorf("remove input; input unset: %v", name) 132 } 133 return fmt.Errorf("remove input; invalid input name: %v", name) 134 } 135 136 func (mn *map2Incr[A, B, C]) SetRawFunction(fn any) error { 137 typed, ok := fn.(Map2Func[A, B, C]) 138 if !ok { 139 return fmt.Errorf("invalid function type for node: %T", fn) 140 } 141 mn.fn = typed 142 return nil 143 } 144 145 func (m *map2Incr[A, B, C]) Node() *incr.Node { return m.n } 146 147 func (m *map2Incr[A, B, C]) Value() C { return m.val } 148 149 func (m *map2Incr[A, B, C]) Stabilize(ctx context.Context) (err error) { 150 var val C 151 var mva A 152 var mvb B 153 if m.a != nil { 154 mva = m.a.Value() 155 } 156 if m.b != nil { 157 mvb = m.b.Value() 158 } 159 val, err = m.fn(ctx, mva, mvb) 160 if err != nil { 161 err = errutil.New(fmt.Errorf("%v; %w", m, err)) 162 return 163 } 164 m.val = val 165 return nil 166 } 167 168 func (m *map2Incr[A, B, C]) String() string { 169 return m.n.String() 170 }