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