gotype/unfold_opts.go (45 lines of code) (raw):
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package gotype
import (
"reflect"
)
type initUnfoldOptions struct {
unfoldFns map[reflect.Type]reflUnfolder
}
type UnfoldOption func(*initUnfoldOptions) error
func applyUnfoldOpts(opts []UnfoldOption) (i initUnfoldOptions, err error) {
for _, o := range opts {
if err = o(&i); err != nil {
break
}
}
return i, err
}
// Unfolders accepts a list of primitive, processing, or stateful unfolders.
//
// Primitive unfolder must implement a function matching the type: func(to *Target, from P) error
// Where to is an arbitrary go type that the result should be written to and
// P must be one of: bool, string, uint(8|16|32|64), int(8|16|32|64), float(32|64)
//
// Processing unfolders first unfold a structure into a temporary structure, followed
// by a post-processing function used to fill in the original target. Processing unfolders
// for type T have the signature:
// func(to *T) (cell interface{}, process func(to *T, cell interface{}) error)
//
// A processing unfolder returns a temporary value for unfolding. The Unfolder will process
// the temporary value (held in cell), like any regular supported value.
// The process function is executed if the parsing step did succeed.
// The address to the target structure and the original cell are reported to the process function,
// reducing the need for allocation storage on the heap in most simple cases.
//
// Stateful unfolders have the function signature: func(to *T) UnfoldState.
// The state returned by the initialization function is used for parsing.
// Although stateful unfolders allow for the most complex unfolding possible,
// they add the most overhead in managing state and allocations. If possible
// prefer primitive unfolders, followed by processing unfolder.
func Unfolders(in ...interface{}) UnfoldOption {
unfolders, err := makeUserUnfolderFns(in)
if err != nil || len(unfolders) == 0 {
return func(_ *initUnfoldOptions) error { return err }
}
return func(o *initUnfoldOptions) error {
if o.unfoldFns == nil {
o.unfoldFns = map[reflect.Type]reflUnfolder{}
}
for k, v := range unfolders {
o.unfoldFns[k] = v
}
return nil
}
}
func makeUserUnfolderFns(in []interface{}) (map[reflect.Type]reflUnfolder, error) {
M := map[reflect.Type]reflUnfolder{}
for _, cur := range in {
if cur == nil {
continue
}
t, unfolder, err := makeUserUnfolder(reflect.ValueOf(cur))
if err != nil {
return nil, err
}
M[t] = unfolder
}
return M, nil
}