github.com/ipld/go-ipld-prime@v0.21.0/datamodel/copy.go (about)

     1  package datamodel
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  )
     7  
     8  // Copy does an explicit shallow copy of a Node's data into a NodeAssembler.
     9  //
    10  // This can be used to flip data from one memory layout to another
    11  // (for example, from basicnode to using using bindnode,
    12  // or to codegenerated node implementations,
    13  // or to or from ADL nodes, etc).
    14  //
    15  // The copy is implemented by ranging over the contents if it's a recursive kind,
    16  // and for each of them, using `AssignNode` on the child values;
    17  // for scalars, it's just calling the appropriate `Assign*` method.
    18  //
    19  // Many NodeAssembler implementations use this as a fallback behavior in their
    20  // `AssignNode` method (that is, they call to this function after all other special
    21  // faster shortcuts they might prefer to employ, such as direct struct copying
    22  // if they share internal memory layouts, etc, have been tried already).
    23  func Copy(n Node, na NodeAssembler) error {
    24  	if n == nil {
    25  		return errors.New("cannot copy a nil node")
    26  	}
    27  	switch n.Kind() {
    28  	case Kind_Null:
    29  		if n.IsAbsent() {
    30  			return errors.New("copying an absent node makes no sense")
    31  		}
    32  		return na.AssignNull()
    33  	case Kind_Bool:
    34  		v, err := n.AsBool()
    35  		if err != nil {
    36  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsBool method returned %w", n.Kind(), err)
    37  		}
    38  		return na.AssignBool(v)
    39  	case Kind_Int:
    40  		v, err := n.AsInt()
    41  		if err != nil {
    42  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsInt method returned %w", n.Kind(), err)
    43  		}
    44  		return na.AssignInt(v)
    45  	case Kind_Float:
    46  		v, err := n.AsFloat()
    47  		if err != nil {
    48  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsFloat method returned %w", n.Kind(), err)
    49  		}
    50  		return na.AssignFloat(v)
    51  	case Kind_String:
    52  		v, err := n.AsString()
    53  		if err != nil {
    54  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsString method returned %w", n.Kind(), err)
    55  		}
    56  		return na.AssignString(v)
    57  	case Kind_Bytes:
    58  		v, err := n.AsBytes()
    59  		if err != nil {
    60  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsBytes method returned %w", n.Kind(), err)
    61  		}
    62  		return na.AssignBytes(v)
    63  	case Kind_Link:
    64  		v, err := n.AsLink()
    65  		if err != nil {
    66  			return fmt.Errorf("node violated contract: promised to be %v kind, but AsLink method returned %w", n.Kind(), err)
    67  		}
    68  		return na.AssignLink(v)
    69  	case Kind_Map:
    70  		ma, err := na.BeginMap(n.Length())
    71  		if err != nil {
    72  			return err
    73  		}
    74  		itr := n.MapIterator()
    75  		for !itr.Done() {
    76  			k, v, err := itr.Next()
    77  			if err != nil {
    78  				return err
    79  			}
    80  			if v.IsAbsent() {
    81  				continue
    82  			}
    83  			if err := ma.AssembleKey().AssignNode(k); err != nil {
    84  				return err
    85  			}
    86  			if err := ma.AssembleValue().AssignNode(v); err != nil {
    87  				return err
    88  			}
    89  		}
    90  		return ma.Finish()
    91  	case Kind_List:
    92  		la, err := na.BeginList(n.Length())
    93  		if err != nil {
    94  			return err
    95  		}
    96  		itr := n.ListIterator()
    97  		for !itr.Done() {
    98  			_, v, err := itr.Next()
    99  			if err != nil {
   100  				return err
   101  			}
   102  			if v.IsAbsent() {
   103  				continue
   104  			}
   105  			if err := la.AssembleValue().AssignNode(v); err != nil {
   106  				return err
   107  			}
   108  		}
   109  		return la.Finish()
   110  	default:
   111  		return fmt.Errorf("node has invalid kind %v", n.Kind())
   112  	}
   113  }