github.com/ipld/go-ipld-prime@v0.21.0/schema/gen/go/genUnionReprStringprefix.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 = &unionReprStringprefixGenerator{} 11 12 func NewUnionReprStringprefixGenerator(pkgName string, typ *schema.TypeUnion, adjCfg *AdjunctCfg) TypeGenerator { 13 return unionReprStringprefixGenerator{ 14 unionGenerator{ 15 AdjCfg: adjCfg, 16 MapTraits: mixins.MapTraits{ 17 PkgName: pkgName, 18 TypeName: string(typ.Name()), 19 TypeSymbol: adjCfg.TypeSymbol(typ), 20 }, 21 PkgName: pkgName, 22 Type: typ, 23 }, 24 } 25 } 26 27 type unionReprStringprefixGenerator struct { 28 unionGenerator 29 } 30 31 func (g unionReprStringprefixGenerator) GetRepresentationNodeGen() NodeGenerator { 32 return unionReprStringprefixReprGenerator{ 33 AdjCfg: g.AdjCfg, 34 StringTraits: mixins.StringTraits{ 35 PkgName: g.PkgName, 36 TypeName: string(g.Type.Name()) + ".Repr", 37 TypeSymbol: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 38 }, 39 PkgName: g.PkgName, 40 Type: g.Type, 41 } 42 } 43 44 type unionReprStringprefixReprGenerator struct { 45 AdjCfg *AdjunctCfg 46 mixins.StringTraits 47 PkgName string 48 Type *schema.TypeUnion 49 } 50 51 func (unionReprStringprefixReprGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 52 53 func (g unionReprStringprefixReprGenerator) 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 // We do also want some constants for our discriminant values; 60 // they'll make iterators able to work faster. 61 doTemplate(` 62 var ( 63 {{- range $member := .Type.Members }} 64 memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial = _String{"{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}"} 65 {{- end }} 66 ) 67 `, w, g.AdjCfg, g) 68 } 69 70 func (g unionReprStringprefixReprGenerator) EmitNodeTypeAssertions(w io.Writer) { 71 doTemplate(` 72 var _ datamodel.Node = &_{{ .Type | TypeSymbol }}__Repr{} 73 `, w, g.AdjCfg, g) 74 } 75 76 func (g unionReprStringprefixReprGenerator) EmitNodeMethodAsString(w io.Writer) { 77 // See comment block in structReprStringjoinReprGenerator.EmitNodeMethodAsString for a lot of philosophizing about this. 78 doTemplate(` 79 func (n *_{{ .Type | TypeSymbol }}__Repr) AsString() (string, error) { 80 return n.String(), nil 81 } 82 func (n *_{{ .Type | TypeSymbol }}__Repr) String() string { 83 {{- if (eq (.AdjCfg.UnionMemlayout .Type) "embedAll") }} 84 switch n.tag { 85 {{- range $i, $member := .Type.Members }} 86 case {{ add $i 1 }}: 87 return memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + "{{ dot.Type.RepresentationStrategy.GetDelim }}" + n.x{{ add $i 1 }}.String() 88 {{- end}} 89 {{- else if (eq (.AdjCfg.UnionMemlayout .Type) "interface") }} 90 switch n2 := n.x.(type) { 91 {{- range $member := .Type.Members }} 92 case {{ $member | TypeSymbol }}: 93 return memberName__{{ dot.Type | TypeSymbol }}_{{ $member.Name }}_serial.String() + "{{ dot.Type.RepresentationStrategy.GetDelim }}" + n2.String() 94 {{- end}} 95 {{- end}} 96 default: 97 panic("unreachable") 98 } 99 } 100 func (n {{ .Type | TypeSymbol }}) String() string { 101 return (*_{{ .Type | TypeSymbol }}__Repr)(n).String() 102 } 103 `, w, g.AdjCfg, g) 104 } 105 106 func (g unionReprStringprefixReprGenerator) EmitNodeMethodPrototype(w io.Writer) { 107 emitNodeMethodPrototype_typical(w, g.AdjCfg, g) 108 } 109 110 func (g unionReprStringprefixReprGenerator) EmitNodePrototypeType(w io.Writer) { 111 emitNodePrototypeType_typical(w, g.AdjCfg, g) 112 } 113 114 // --- NodeBuilder and NodeAssembler ---> 115 116 func (g unionReprStringprefixReprGenerator) GetNodeBuilderGenerator() NodeBuilderGenerator { 117 return unionReprStringprefixReprBuilderGenerator{ 118 g.AdjCfg, 119 mixins.StringAssemblerTraits{ 120 PkgName: g.PkgName, 121 TypeName: g.TypeName, 122 AppliedPrefix: "_" + g.AdjCfg.TypeSymbol(g.Type) + "__Repr", 123 }, 124 g.PkgName, 125 g.Type, 126 } 127 } 128 129 type unionReprStringprefixReprBuilderGenerator struct { 130 AdjCfg *AdjunctCfg 131 mixins.StringAssemblerTraits 132 PkgName string 133 Type *schema.TypeUnion 134 } 135 136 func (unionReprStringprefixReprBuilderGenerator) IsRepr() bool { return true } // hint used in some generalized templates. 137 138 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderType(w io.Writer) { 139 emitEmitNodeBuilderType_typical(w, g.AdjCfg, g) 140 } 141 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeBuilderMethods(w io.Writer) { 142 emitNodeBuilderMethods_typical(w, g.AdjCfg, g) 143 144 // Generate a single-step construction function -- this is easy to do for a scalar, 145 // and all representations of scalar kind can be expected to have a method like this. 146 // The function is attached to the NodePrototype for convenient namespacing; 147 // it needs no new memory, so it would be inappropriate to attach to the builder or assembler. 148 // The function is directly used internally by anything else that might involve recursive destructuring on the same scalar kind 149 // (for example, structs using stringjoin strategies that have one of this type as a field, etc). 150 // Since we're a representation of scalar kind, and can recurse, 151 // we ourselves presume this plain construction method must also exist for all our members. 152 // REVIEW: We could make an immut-safe verion of this and export it on the NodePrototype too, as `FromString(string)`. 153 doTemplate(` 154 func (_{{ .Type | TypeSymbol }}__ReprPrototype) fromString(w *_{{ .Type | TypeSymbol }}, v string) error { 155 ss := mixins.SplitN(v, "{{ .Type.RepresentationStrategy.GetDelim }}", 2) 156 if len(ss) != 2 { 157 return schema.ErrUnmatchable{TypeName:"{{ .PkgName }}.{{ .Type.Name }}.Repr"}.Reasonf("expecting a stringprefix union but found no delimiter in the value") 158 } 159 switch ss[0] { 160 {{- range $i, $member := .Type.Members }} 161 case "{{ $member | dot.Type.RepresentationStrategy.GetDiscriminant }}": 162 {{- if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "embedAll") }} 163 w.tag = {{ add $i 1 }} 164 if err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&w.x{{ add $i 1 }}, ss[1]); err != nil { 165 return schema.ErrUnmatchable{TypeName:"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr", Reason: err} 166 } 167 return nil 168 {{- else if (eq (dot.AdjCfg.UnionMemlayout dot.Type) "interface") }} 169 var n2 _{{ $member | TypeSymbol }} 170 if err := (_{{ $member | TypeSymbol }}__ReprPrototype{}).fromString(&n2, ss[1]); err != nil { 171 return schema.ErrUnmatchable{TypeName:"{{ dot.PkgName }}.{{ dot.Type.Name }}.Repr", Reason: err} 172 } 173 w.x = &n2 174 return nil 175 {{- end}} 176 {{- end}} 177 default: 178 return schema.ErrNoSuchField{Type: nil /*TODO*/, Field: datamodel.PathSegmentOfString(ss[0])} 179 } 180 } 181 `, w, g.AdjCfg, g) 182 } 183 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerType(w io.Writer) { 184 doTemplate(` 185 type _{{ .Type | TypeSymbol }}__ReprAssembler struct { 186 w *_{{ .Type | TypeSymbol }} 187 m *schema.Maybe 188 } 189 190 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) reset() {} 191 `, w, g.AdjCfg, g) 192 } 193 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNull(w io.Writer) { 194 emitNodeAssemblerMethodAssignNull_scalar(w, g.AdjCfg, g) 195 } 196 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignString(w io.Writer) { 197 // This method contains a branch to support MaybeUsesPtr because new memory may need to be allocated. 198 // This allocation only happens if the 'w' ptr is nil, which means we're being used on a Maybe; 199 // otherwise, the 'w' ptr should already be set, and we fill that memory location without allocating, as usual. 200 // TODO:DRY: this is identical to other string-repr-on-non-string-type. 201 doTemplate(` 202 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignString(v string) error { 203 switch *na.m { 204 case schema.Maybe_Value, schema.Maybe_Null: 205 panic("invalid state: cannot assign into assembler that's already finished") 206 } 207 {{- if .Type | MaybeUsesPtr }} 208 if na.w == nil { 209 na.w = &_{{ .Type | TypeSymbol }}{} 210 } 211 {{- end}} 212 if err := (_{{ .Type | TypeSymbol }}__ReprPrototype{}).fromString(na.w, v); err != nil { 213 return err 214 } 215 *na.m = schema.Maybe_Value 216 return nil 217 } 218 `, w, g.AdjCfg, g) 219 } 220 221 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerMethodAssignNode(w io.Writer) { 222 // AssignNode goes through three phases: 223 // 1. is it null? Jump over to AssignNull (which may or may not reject it). 224 // 2. is it our own type? Handle specially -- we might be able to do efficient things. 225 // 3. is it the right kind to morph into us? Do so. 226 // TODO:DRY: this is identical to other string-repr-on-non-string-type. 227 doTemplate(` 228 func (na *_{{ .Type | TypeSymbol }}__ReprAssembler) AssignNode(v datamodel.Node) error { 229 if v.IsNull() { 230 return na.AssignNull() 231 } 232 if v2, ok := v.(*_{{ .Type | TypeSymbol }}); ok { 233 switch *na.m { 234 case schema.Maybe_Value, schema.Maybe_Null: 235 panic("invalid state: cannot assign into assembler that's already finished") 236 } 237 {{- if .Type | MaybeUsesPtr }} 238 if na.w == nil { 239 na.w = v2 240 *na.m = schema.Maybe_Value 241 return nil 242 } 243 {{- end}} 244 *na.w = *v2 245 *na.m = schema.Maybe_Value 246 return nil 247 } 248 if v2, err := v.AsString(); err != nil { 249 return err 250 } else { 251 return na.AssignString(v2) 252 } 253 } 254 `, w, g.AdjCfg, g) 255 } 256 func (g unionReprStringprefixReprBuilderGenerator) EmitNodeAssemblerOtherBits(w io.Writer) { 257 // None for this. 258 }