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  }