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 }