github.com/ipld/go-ipld-prime@v0.21.0/schema/gen/go/genStructReprStringjoin.go (about) 1 package gengo 2 3 import ( 4 "io" 5 6 "github.com/ipld/go-ipld-prime/schema" 7 "github.com/ipld/go-ipld-prime/schema/gen/go/mixins" 8 ) 9 10 var _ TypeGenerator = &structReprStringjoinGenerator{} 11 12 func NewStructReprStringjoinGenerator(pkgName string, typ *schema.TypeStruct, adjCfg *AdjunctCfg) TypeGenerator { 13 return structReprStringjoinGenerator{ 14 structGenerator{ 15 adjCfg, 16 mixins.MapTraits{ 17 PkgName: pkgName, 18 TypeName: string(typ.Name()), 19 TypeSymbol: adjCfg.TypeSymbol(typ), 20 }, 21 pkgName, 22 typ, 23 }, 24 } 25 } 26 27 type structReprStringjoinGenerator struct { 28 structGenerator 29 } 30 31 func (g structReprStringjoinGenerator) GetRepresentationNodeGen() NodeGenerator { 32 return structReprStringjoinReprGenerator{ 33 g.AdjCfg, 34 mixins.StringTraits{ 35 PkgName: g.PkgName, 36 TypeName: string(g.Type.Name()) + ".Repr", 37 TypeSymbol: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 38 }, 39 g.PkgName, 40 g.Type, 41 } 42 } 43 44 type structReprStringjoinReprGenerator struct { 45 AdjCfg *AdjunctCfg 46 mixins.StringTraits 47 PkgName string 48 Type *schema.TypeStruct 49 } 50 51 func (structReprStringjoinReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 52 53 func (g structReprStringjoinReprGenerator) EmitNodeType(w io.Writer) { 54 // The type is structurally the same, but will have a different set of methods. 55 doTemplate(` 56 type _{{ .Type | TypeSymbol }}__Repr _{{ .Type | TypeSymbol }} 57 `, w, g.AdjCfg, g) 58 } 59 60 func (g structReprStringjoinReprGenerator) EmitNodeTypeAssertions(w io.Writer) { 61 doTemplate(` 62 var _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{} 63 `, w, g.AdjCfg, g) 64 } 65 66 func (g structReprStringjoinReprGenerator) EmitNodeMethodAsString(w io.Writer) { 67 // Prerequisites: 68 // - every field must be a string, or have string representation. 69 // - this should've been checked when compiling the type system info. 70 // - we're willing to imply a base-10 atoi/itoa for ints (but it's not currently supported). 71 // - there are NO sanity checks that your value doesn't contain the delimiter 72 // - you need to do this in validation hooks or some other way 73 // - optional or nullable fields are not supported with this representation strategy. 74 // - this should've been checked when compiling the type system info. 75 // - if support for this is added in the future, you can bet all optionals 76 // will be required to be *either* in a row at the start, or in a row at the end. 77 // (a 'direction' property might also be needed, so behavior is defined if every field is optional.) 78 // 79 // A speciated String method is also generated here. 80 // (Organization questionable: if this was at type level, it'd be in the 'EmitNativeAccessors' block, 81 // but we don't have that in the NodeGenerator interface so we don't have it here. Maybe that's a mistake.) 82 // 83 // A String method is *also* generated on the type-level node. 84 // This might be worth consistency review... 85 // It's a practical necessity in areas like stringifying for key error messages if used in map keys, for example. 86 doTemplate(` 87 func (n *_{{ .Type | TypeSymbol }}__Repr) AsString() (string, error) { 88 return n.String(), nil 89 } 90 func (n *_{{ .Type | TypeSymbol }}__Repr) String() string { 91 return {{ "" }} 92 {{- $type := .Type -}} {{- /* ranging modifies dot, unhelpfully */ -}} 93 {{- range $i, $field := .Type.Fields }} 94 {{- if $i }} + "{{ $type.RepresentationStrategy.GetDelim }}" + {{end -}} 95 (*_{{ $field.Type | TypeSymbol }}__Repr)(&n.{{ $field | FieldSymbolLower }}).String() 96 {{- end}} 97 } 98 func (n {{ .Type | TypeSymbol }}) String() string { 99 return (*_{{ .Type | TypeSymbol }}__Repr)(n).String() 100 } 101 `, w, g.AdjCfg, g) 102 } 103 104 func (g structReprStringjoinReprGenerator) EmitNodeMethodPrototype(w io.Writer) { 105 emitNodeMethodPrototype_typical(w, g.AdjCfg, g) 106 } 107 108 func (g structReprStringjoinReprGenerator) EmitNodePrototypeType(w io.Writer) { 109 emitNodePrototypeType_typical(w, g.AdjCfg, g) 110 } 111 112 // --- NodeBuilder and NodeAssembler ---> 113 114 func (g structReprStringjoinReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator { 115 return structReprStringjoinReprBuilderGenerator{ 116 g.AdjCfg, 117 mixins.StringAssemblerTraits{ 118 PkgName: g.PkgName, 119 TypeName: g.TypeName, 120 AppliedPrefix: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 121 }, 122 g.PkgName, 123 g.Type, 124 } 125 } 126 127 type structReprStringjoinReprBuilderGenerator struct { 128 AdjCfg *AdjunctCfg 129 mixins.StringAssemblerTraits 130 PkgName string 131 Type *schema.TypeStruct 132 } 133 134 func (structReprStringjoinReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 135 136 func (g structReprStringjoinReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) { 137 emitEmitNodeBuilderType_typical(w, g.AdjCfg, g) 138 } 139 func (g structReprStringjoinReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) { 140 emitNodeBuilderMethods_typical(w, g.AdjCfg, g) 141 142 // Generate a single-step construction function -- this is easy to do for a scalar, 143 // and all representations of scalar kind can be expected to have a method like this. 144 // The function is attached to the NodePrototype for convenient namespacing; 145 // it needs no new memory, so it would be inappropriate to attach to the builder or assembler. 146 // The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind 147 // (for example, structs using stringjoin strategies that have one of this type as a field, etc). 148 // Since we're a representation of scalar kind, and can recurse, 149 // we ourselves presume this plain construction method must also exist for all our members. 150 // REVIEW: We could make an immut-safe verion of this and export it on the NodePrototype too, as `FromString(string)`. 151 // FUTURE: should engage validation flow. 152 doTemplate(` 153 func (_{{ .Type | TypeSymbol }}__ReprPrototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error { 154 ss, err := mixins.SplitExact(v, "{{ .Type.RepresentationStrategy.GetDelim }}", {{ len .Type.Fields }}) 155 if err != nil { 156 return schema.ErrUnmatchable{TypeName:"{{ .PkgName }}.{{ .Type.Name }}.Repr", Reason: err} 157 } 158 {{- $dot := . -}} {{- /* ranging modifies dot, unhelpfully */ -}} 159 {{- range $i, $field := .Type.Fields }} 160 if err := (_{{ $field.Type | TypeSymbol }}__ReprPrototype{}).fromString(&w.{{ $field | FieldSymbolLower }}, ss[{{ $i }}]); err != nil { 161 return schema.ErrUnmatchable{TypeName:"{{ $dot.PkgName }}.{{ $dot.Type.Name }}.Repr", Reason: err} 162 } 163 {{- end}} 164 return nil 165 } 166 `, w, g.AdjCfg, g) 167 } 168 func (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) { 169 doTemplate(` 170 type _{{ .Type | TypeSymbol }}__ReprAssembler struct { 171 w *_{{ .Type | TypeSymbol }} 172 m *schema.Maybe 173 } 174 175 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {} 176 `, w, g.AdjCfg, g) 177 } 178 func (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) { 179 emitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g) 180 } 181 func (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) { 182 // This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated. 183 // This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe; 184 // otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual. 185 doTemplate(` 186 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignString(v string) error { 187 switch *na.m { 188 case schema.Maybe_Value, schema.Maybe_Null: 189 panic("invalid state: cannot assign into assembler that's already finished") 190 } 191 {{- if .Type | MaybeUsesPtr }} 192 if na.w == nil { 193 na.w = &_{{ .Type | TypeSymbol }}{} 194 } 195 {{- end}} 196 if err := (_{{ .Type | TypeSymbol }}__ReprPrototype{}).fromString(na.w, v); err != nil { 197 return err 198 } 199 *na.m = schema.Maybe_Value 200 return nil 201 } 202 `, w, g.AdjCfg, g) 203 } 204 205 func (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) { 206 // AssignNode goes through three phases: 207 // 1. is it null? Jump over to AssignNull (which may or may not reject it). 208 // 2. is it our own type? Handle specially -- we might be able to do efficient things. 209 // 3. is it the right kind to morph into us? Do so. 210 doTemplate(` 211 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error { 212 if v.IsNull() { 213 return na.AssignNull() 214 } 215 if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok { 216 switch *na.m { 217 case schema.Maybe_Value, schema.Maybe_Null: 218 panic("invalid state: cannot assign into assembler that's already finished") 219 } 220 {{- if .Type | MaybeUsesPtr }} 221 if na.w == nil { 222 na.w = v2 223 *na.m = schema.Maybe_Value 224 return nil 225 } 226 {{- end}} 227 *na.w = *v2 228 *na.m = schema.Maybe_Value 229 return nil 230 } 231 if v2, err := v.AsString(); err != nil { 232 return err 233 } else { 234 return na.AssignString(v2) 235 } 236 } 237 `, w, g.AdjCfg, g) 238 } 239 func (g structReprStringjoinReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) { 240 // None for this. 241 }