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  }