diff options
Diffstat (limited to 'vendor/codeberg.org/gruf/go-kv/v2/format/struct.go')
| -rw-r--r-- | vendor/codeberg.org/gruf/go-kv/v2/format/struct.go | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-kv/v2/format/struct.go b/vendor/codeberg.org/gruf/go-kv/v2/format/struct.go new file mode 100644 index 000000000..cc1c8634d --- /dev/null +++ b/vendor/codeberg.org/gruf/go-kv/v2/format/struct.go @@ -0,0 +1,173 @@ +package format + +// field stores the minimum necessary +// data for iterating and formatting +// each field in a given struct. +type field struct { + format FormatFunc + name string + offset uintptr +} + +// iterStructType returns a FormatFunc capable of iterating +// and formatting the given struct type currently in typenode{}. +// note this will fetch sub-FormatFuncs for each struct field. +func (fmt *Formatter) iterStructType(t typenode) FormatFunc { + // Number of struct fields. + n := t.rtype.NumField() + + // Gather format functions. + fields := make([]field, n) + for i := 0; i < n; i++ { + + // Get struct field at index. + sfield := t.rtype.Field(i) + rtype := sfield.Type + + // Get nested field typenode with appropriate flags. + flags := reflect_struct_field_flags(t.flags, rtype) + ft := t.next(sfield.Type, flags) + + // Get field format func. + fn := fmt.loadOrGet(ft) + if fn == nil { + panic("unreachable") + } + + // Set field info. + fields[i] = field{ + format: fn, + name: sfield.Name, + offset: sfield.Offset, + } + } + + // Handle no. fields. + switch len(fields) { + case 0: + return emptyStructType(t) + case 1: + return iterSingleFieldStructType(t, fields[0]) + default: + return iterMultiFieldStructType(t, fields) + } +} + +func emptyStructType(t typenode) FormatFunc { + if !t.needs_typestr() { + return func(s *State) { + // Append empty object. + s.B = append(s.B, "{}"...) + } + } + + // Struct type string with refs. + typestr := t.typestr_with_refs() + + // Append empty object + // with type information. + return func(s *State) { + if s.A.WithType() { + s.B = append(s.B, typestr...) + } + s.B = append(s.B, "{}"...) + } +} + +func iterSingleFieldStructType(t typenode, field field) FormatFunc { + if field.format == nil { + panic("nil func") + } + + if !t.needs_typestr() { + return func(s *State) { + // Wrap 'fn' with braces + field name. + s.B = append(s.B, "{"+field.name+"="...) + field.format(s) + s.B = append(s.B, "}"...) + } + } + + // Struct type string with refs. + typestr := t.typestr_with_refs() + + return func(s *State) { + // Include type info. + if s.A.WithType() { + s.B = append(s.B, typestr...) + } + + // Wrap 'fn' with braces + field name. + s.B = append(s.B, "{"+field.name+"="...) + field.format(s) + s.B = append(s.B, "}"...) + } +} + +func iterMultiFieldStructType(t typenode, fields []field) FormatFunc { + for _, field := range fields { + if field.format == nil { + panic("nil func") + } + } + + if !t.needs_typestr() { + return func(s *State) { + ptr := s.P + + // Prepend object brace. + s.B = append(s.B, '{') + + for i := 0; i < len(fields); i++ { + // Get struct field ptr via offset. + s.P = add(ptr, fields[i].offset) + + // Append field name and value separator. + s.B = append(s.B, fields[i].name+"="...) + + // Format i'th field. + fields[i].format(s) + s.B = append(s.B, ',', ' ') + } + + // Drop final ", ". + s.B = s.B[:len(s.B)-2] + + // Append object brace. + s.B = append(s.B, '}') + } + } + + // Struct type string with refs. + typestr := t.typestr_with_refs() + + return func(s *State) { + ptr := s.P + + // Include type info. + if s.A.WithType() { + s.B = append(s.B, typestr...) + } + + // Prepend object brace. + s.B = append(s.B, '{') + + for i := 0; i < len(fields); i++ { + // Get struct field ptr via offset. + s.P = add(ptr, fields[i].offset) + + // Append field name and value separator. + s.B = append(s.B, fields[i].name+"="...) + + // Format i'th field. + fields[i].format(s) + s.B = append(s.B, ',', ' ') + } + + // Drop final ", ". + s.B = s.B[:len(s.B)-2] + + // Append object brace. + s.B = append(s.B, '}') + } +} |
