nodeutil

package
v0.1.0-alpha Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2023 License: Apache-2.0 Imports: 19 Imported by: 24

Documentation

Overview

Different implementations of the node.Node interface either forming the building blocks of your management implemetations or usable as-is for utility functions.

Index

Examples

Constants

View Source
const (
	PipeSelect tok = iota + 1
	PipeListItem
	PipeLeaf
	PipeEnd
)
View Source
const QUOTE = '"'

Variables

This section is empty.

Functions

func Diff

func Diff(a, b node.Node) node.Node

Diff compares two nodeutil and returns only the difference. Use Selection constraints to control what is compared and how deep.

func Dump

func Dump(n node.Node, out io.Writer) node.Node

Dump will send useful information to writer while delegating reads/writes to the given node

func DumpBin

func DumpBin(out io.Writer) node.Node

DumpBin sends useful information to string when written to

func Dumpf

func Dumpf(n node.Node, fname string) node.Node

Dumpf will send useful information to file while delegating reads/writes to the given node

func GetFieldName

func GetFieldName(parent reflect.Value, in string) string

GetFieldName determines the Go fieldname of a struct field based on the YANG name It first checks if the exact name matches, then uses the MetaNameToFieldName() method to convert YANG names into a go-valid form and finally checks for a struct field with a JSON tag which name matches the YANG name.

func JsonContainerReader

func JsonContainerReader(container map[string]interface{}) node.Node

func JsonListReader

func JsonListReader(list []interface{}) node.Node

func MetaNameToFieldName

func MetaNameToFieldName(in string) string

func Null

func Null() node.Node

Null throws all data away when written to and always returns itself for reading, no data for fields

func OnSave

func OnSave(orig node.Selection, onSave func(*node.Selection) error) (node.Node, error)

func ReadField

func ReadField(m meta.Leafable, ptrVal reflect.Value) (val.Value, error)

func ReadFieldWithFieldName

func ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value) (v val.Value, err error)

func ReadJSON

func ReadJSON(data string) node.Node
Example
model := `
		list bird {

			key "name";

			leaf name {
				type string;
			}

			leaf wingSpan {
				type int32;
			}
		}

		container location {
			leaf continent {
				type enumeration {
					enum northAmerica;
					enum southAmerica;
					enum africa;
					enum antartica;
					enum europe;
					enum austrailia;
					enum asia;
				}
			}
		}
	`

myApp := make(map[string]interface{})
sel := exampleSelection(model, nodeutil.ReflectChild(myApp))
data := `{
		"bird" : [{
			"name": "swallow",
			"wingSpan" : 10
		}],
		"ignored" : "because it's not in model",
		"location" : {
			"continent" : "africa"
		}
	}
	`
if err := sel.InsertFrom(nodeutil.ReadJSON(data)); err != nil {
	fmt.Print(err.Error())
}
out, _ := nodeutil.WriteJSON(sel)
fmt.Printf(out)
Output:

{"bird":[{"name":"swallow","wingSpan":10}],"location":{"continent":"africa"}}

func ReadJSONIO

func ReadJSONIO(rdr io.Reader) node.Node

func ReadJSONValues

func ReadJSONValues(values map[string]interface{}) node.Node

func ReflectChild

func ReflectChild(obj interface{}) node.Node

func ReflectList

func ReflectList(obj interface{}) node.Node

func Schema

func Schema(yangModule *meta.Module, yourModule *meta.Module) *node.Browser

*

  • Schema is used to browse YANG models. If resolve is true all references like
  • groupings, uses typedefs are resolved, otherwise they are not.

func Trace

func Trace(target node.Node, out io.Writer) node.Node

Trace will record all calls and data into a target node and recursively wrap each level to effectively trace all operations on a node and it's children

func WriteField

func WriteField(m meta.Leafable, ptrVal reflect.Value, v val.Value) error

///////////////

func WriteFieldWithFieldName

func WriteFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value, v val.Value) error

func WriteJSON

func WriteJSON(s *node.Selection) (string, error)

func WritePrettyJSON

func WritePrettyJSON(s *node.Selection) (string, error)

Types

type Basic

type Basic struct {

	// What to return on calls to Peek().  Peek let's you return underlying objects
	// behind a node and frankly breaks encapsulation so you need not set anything here
	Peekable interface{}

	// Only if node is a list. Return a second data structure that breaks down each request
	// that can be make on each item in a list.
	//
	// If you impement this, you should not implement OnNext
	OnNextItem func(r node.ListRequest) BasicNextItem

	// Only if node is a list AND you don't implement OnNextItem
	//
	// If you impement this, you should not implement OnNextItem
	OnNext func(r node.ListRequest) (next node.Node, key []val.Value, err error)

	// Only if there are other containers or lists defined
	OnChild func(r node.ChildRequest) (child node.Node, err error)

	// Only if you have leafs defined
	OnField func(node.FieldRequest, *node.ValueHandle) error

	// Only if there one or more 'choice' definitions on a list or container and data is used
	// on a reading mode
	OnChoose func(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)

	// Only if there is one or more 'rpc' or 'action' defined in a model that could be
	// called.
	OnAction func(node.ActionRequest) (output node.Node, err error)

	// Only if there is one or more 'notification' defined in a model that could be subscribed to
	OnNotify func(r node.NotifyRequest) (node.NotifyCloser, error)

	// Peekable is often enough, but this always you to return an object dynamically
	OnPeek func(sel *node.Selection, consumer interface{}) interface{}

	// OnContext default implementation does nothing
	OnContext func(s *node.Selection) context.Context

	// OnBeginEdit default implementation does nothing
	OnBeginEdit func(r node.NodeRequest) error

	// OnEndEdit default implementation does nothing
	OnEndEdit func(r node.NodeRequest) error

	// OnRelease default implementation does nothing
	OnRelease func(s *node.Selection)
}

Basic stubs every method of node.Node interface so you only have to supply the functions for operations your data node needs to support.

Example (OnAction)

OnActions you just decode the input and encode the output and return it as response.

package main

import (
	"fmt"

	"github.com/freeconf/yang/node"
	"github.com/freeconf/yang/nodeutil"
	"github.com/freeconf/yang/parser"
)

func main() {

	// YANG 1.1 - 'rpc' is same as 'action' but only used at the top-level of a
	// module for backward compatibility with YANG 1.0
	model := `
			rpc sum {
			   input {
			     leaf a {
			       type int32;
			     }
			     leaf b {
			       type int32;
			     }
			   }
			   output {
			     leaf result {
			       type int32;
			     }
			   }
			}`

	// Data
	data := &nodeutil.Basic{
		OnAction: func(r node.ActionRequest) (out node.Node, err error) {
			switch r.Meta.Ident() {
			case "sum":
				var n nums
				if err := r.Input.InsertInto(nodeutil.ReflectChild(&n)); err != nil {
					return nil, err
				}
				result := map[string]interface{}{
					"result": n.Sum(),
				}
				return nodeutil.ReflectChild(result), nil
			}
			return
		},
	}

	sel, err := exampleSelection(model, data).Find("sum")
	if err != nil {
		panic(err)
	}

	// JSON is a useful format to use as input, but this can come from any node
	// that would return "a" and "b" leaves.
	result, err := sel.Action(nodeutil.ReadJSON(`{"a":10,"b":32}`))
	if err != nil {
		panic(err)
	}
	examplePrint(result)

}

type nums struct {
	A int
	B int
}

func (n nums) Sum() int {
	return n.A + n.B
}

func examplePrint(sel *node.Selection) {
	s, err := nodeutil.WriteJSON(sel)
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}

func exampleSelection(yangFragment string, n node.Node) *node.Selection {
	mstr := fmt.Sprintf(`module x {
		namespace "";
		prefix "";
		revision 0;

		%s
	}`, yangFragment)
	model, err := parser.LoadModuleFromString(nil, mstr)
	if err != nil {
		panic(err.Error())
	}
	brwsr := node.NewBrowser(model, n)
	return brwsr.Root()
}
Output:

{"result":42}
Example (OnChild)

TestReadingStruct expands on TestSimplestExample by wrapping a 'container' around the message. Containers are like a Golang struct.

package main

import (
	"fmt"

	"github.com/freeconf/yang/node"
	"github.com/freeconf/yang/nodeutil"
	"github.com/freeconf/yang/parser"
)

type foo struct {
	Bar string
}

func main() {
	model := `
		container foo {
			leaf bar { 
				type string; 
			}
		}
		`

	f := &foo{
		Bar: "x",
	}
	data := &nodeutil.Basic{
		OnChild: func(r node.ChildRequest) (node.Node, error) {
			switch r.Meta.Ident() {
			case "foo":
				if r.New {
					f = &foo{}
				} else if r.Delete {
					f = nil
				}
				if f != nil {
					return nodeutil.ReflectChild(f), nil
				}
			}
			return nil, nil
		},
	}

	sel := exampleSelection(model, data)

	fmt.Println("Reading")
	examplePrint(sel)

	fmt.Println("Deleting")
	selFoo, err := sel.Find("foo")
	if err != nil {
		panic(err)
	}
	if err = selFoo.Delete(); err != nil {
		panic(err)
	}
	examplePrint(sel)

	fmt.Println("Creating")
	sel.InsertFrom(nodeutil.ReadJSON(`{"foo":{"bar":"y"}}`))
	examplePrint(sel)

}

func examplePrint(sel *node.Selection) {
	s, err := nodeutil.WriteJSON(sel)
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}

func exampleSelection(yangFragment string, n node.Node) *node.Selection {
	mstr := fmt.Sprintf(`module x {
		namespace "";
		prefix "";
		revision 0;

		%s
	}`, yangFragment)
	model, err := parser.LoadModuleFromString(nil, mstr)
	if err != nil {
		panic(err.Error())
	}
	brwsr := node.NewBrowser(model, n)
	return brwsr.Root()
}
Output:

Reading
{"foo":{"bar":"x"}}
Deleting
{}
Creating
{"foo":{"bar":"y"}}
Example (OnField)

Example defines a model with a single string called "message" as it's only allowed field (or 'leaf').

Models can be matched to a data for lot's of things including reading data, so we create a simple data source that always returns hello.

Models and Data come together as a browser. A browser is all you need to do anything with the data that confirms to the model.

package main

import (
	"fmt"

	"github.com/freeconf/yang/node"
	"github.com/freeconf/yang/nodeutil"
	"github.com/freeconf/yang/parser"
	"github.com/freeconf/yang/val"
)

func main() {
	model := `
	  leaf foo { 
		  type string; 
	  }`

	data := &nodeutil.Basic{

		// Custom implementations of reading and writing fields called "leafs" or
		// "leaf-lists" in YANG.
		OnField: func(r node.FieldRequest, hnd *node.ValueHandle) error {
			switch r.Meta.Ident() {
			case "foo":
				if r.Write {
					fmt.Println(hnd.Val.String())
				} else {
					hnd.Val = val.String("READ")
				}
			}
			return nil
		},
	}
	sel := exampleSelection(model, data)

	examplePrint(sel)

	sel.UpsertFrom(nodeutil.ReadJSON(`{"foo":"WRITE"}`))
}

func examplePrint(sel *node.Selection) {
	s, err := nodeutil.WriteJSON(sel)
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}

func exampleSelection(yangFragment string, n node.Node) *node.Selection {
	mstr := fmt.Sprintf(`module x {
		namespace "";
		prefix "";
		revision 0;

		%s
	}`, yangFragment)
	model, err := parser.LoadModuleFromString(nil, mstr)
	if err != nil {
		panic(err.Error())
	}
	brwsr := node.NewBrowser(model, n)
	return brwsr.Root()
}
Output:

{"foo":"READ"}
WRITE
Example (OnNext)

ExampleBasic_onNext We need to handle adding, removing and naviagtion thru a list both by key and sequentially. Because most lists have a key, Go's map is often most useful structure to store lists. node.Index helps navigating thru a map sequentally but you can use your own method.

package main

import (
	"fmt"

	"github.com/freeconf/yang/node"
	"github.com/freeconf/yang/nodeutil"
	"github.com/freeconf/yang/parser"
	"github.com/freeconf/yang/val"
)

type foo struct {
	Bar string
}

func main() {
	model := `
			list foo {
			   key "bar";
			   leaf bar { 
				   type string;
			   }
			}`

	// Data
	m := map[string]*foo{
		"a": {Bar: "a"},
	}
	dataList := func() node.Node {
		// helps navigate a map sequentially
		i := node.NewIndex(m)
		return &nodeutil.Basic{
			OnNextItem: func(r node.ListRequest) nodeutil.BasicNextItem {
				var f *foo
				return nodeutil.BasicNextItem{
					New: func() error {
						f = &foo{}
						m[r.Key[0].String()] = f
						return nil
					},

					GetByKey: func() error {
						f = m[r.Key[0].String()]
						return nil
					},

					GetByRow: func() ([]val.Value, error) {
						v := i.NextKey(r.Row)
						if v == node.NO_VALUE {
							return nil, nil
						}
						id := v.String()
						f = m[id]
						return []val.Value{val.String(id)}, nil
					},

					DeleteByKey: func() error {
						delete(m, r.Key[0].String())
						return nil
					},

					Node: func() (node.Node, error) {
						if f != nil {
							return nodeutil.ReflectChild(f), nil
						}
						return nil, nil
					},
				}
			},
		}
	}
	sel := exampleSelection(model, &nodeutil.Basic{
		OnChild: func(r node.ChildRequest) (node.Node, error) {
			return dataList(), nil
		},
	})

	fmt.Println("Reading")
	examplePrint(sel)

	fmt.Println("Deleting")
	aSel, err := sel.Find("foo=a")
	if err != nil || aSel == nil {
		panic(err)
	}
	aSel.Delete()
	examplePrint(sel)

	fmt.Println("Creating")
	err = sel.UpsertFrom(nodeutil.ReadJSON(`{"foo":[{"bar":"b"}]}`))
	if err != nil {
		panic(err)
	}
	examplePrint(sel)

}

func examplePrint(sel *node.Selection) {
	s, err := nodeutil.WriteJSON(sel)
	if err != nil {
		panic(err)
	}
	fmt.Println(s)
}

func exampleSelection(yangFragment string, n node.Node) *node.Selection {
	mstr := fmt.Sprintf(`module x {
		namespace "";
		prefix "";
		revision 0;

		%s
	}`, yangFragment)
	model, err := parser.LoadModuleFromString(nil, mstr)
	if err != nil {
		panic(err.Error())
	}
	brwsr := node.NewBrowser(model, n)
	return brwsr.Root()
}
Output:

Reading
{"foo":[{"bar":"a"}]}
Deleting
{"foo":[]}
Creating
{"foo":[{"bar":"b"}]}

func (*Basic) Action

func (s *Basic) Action(r node.ActionRequest) (output node.Node, err error)

func (*Basic) BeginEdit

func (s *Basic) BeginEdit(r node.NodeRequest) error

func (*Basic) Child

func (s *Basic) Child(r node.ChildRequest) (node.Node, error)

func (*Basic) Choose

func (s *Basic) Choose(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)

func (*Basic) Context

func (s *Basic) Context(sel *node.Selection) context.Context

func (*Basic) EndEdit

func (s *Basic) EndEdit(r node.NodeRequest) error

func (*Basic) Field

func (s *Basic) Field(r node.FieldRequest, hnd *node.ValueHandle) error

func (*Basic) Next

func (n *Basic) Next(r node.ListRequest) (node.Node, []val.Value, error)

func (*Basic) Notify

func (s *Basic) Notify(r node.NotifyRequest) (node.NotifyCloser, error)

func (*Basic) Peek

func (s *Basic) Peek(sel *node.Selection, consumer interface{}) interface{}

func (*Basic) Release

func (s *Basic) Release(sel *node.Selection)

type BasicNextItem

type BasicNextItem struct {

	// New when requested to create a new list item.  If you want to wait until all
	// fields are set before adding new item to list, then you can do that in OnEndEdit
	New func() error

	// Find item in list by it's key(s).  You will return found item in Node implementation
	GetByKey func() error

	// Find item in list by it's row position in list.  You will return found item in Node implementation
	GetByRow func() ([]val.Value, error)

	// Find item in list by it's row position in list.  You will return found item in Node implementation
	Node func() (node.Node, error)

	// Remove item. OnEndEdit will also be called if you want to finalize the delete
	DeleteByKey func() error
}

BasicNextItem is used to organize the function calls around individual list items and is returned from Basic.NextItem. You must implement all functions except DeleteByKey and New if list is not editable

type ConfigProxy

type ConfigProxy struct {
}

Proxy all but config prremoteties to a delegate node. For the config read prremoteties simply return local copy, for config writes send a copy to far end and if returns ok then trigger storage to save.

func (ConfigProxy) Node

func (self ConfigProxy) Node(local node.Node, remote node.Node) node.Node

type CopyOnWrite

type CopyOnWrite struct {
}

func (CopyOnWrite) Node

func (self CopyOnWrite) Node(s *node.Selection, read node.Node, write node.Node) node.Node

type Extend

type Extend struct {
	Base        node.Node
	OnNext      func(parent node.Node, r node.ListRequest) (next node.Node, key []val.Value, err error)
	OnChild     func(parent node.Node, r node.ChildRequest) (child node.Node, err error)
	OnField     func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error
	OnChoose    func(parent node.Node, sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)
	OnAction    func(parent node.Node, r node.ActionRequest) (output node.Node, err error)
	OnNotify    func(parent node.Node, r node.NotifyRequest) (closer node.NotifyCloser, err error)
	OnExtend    func(e *Extend, sel *node.Selection, m meta.HasDefinitions, child node.Node) (node.Node, error)
	OnPeek      func(parent node.Node, sel *node.Selection, consumer interface{}) interface{}
	OnBeginEdit func(parent node.Node, r node.NodeRequest) error
	OnEndEdit   func(parent node.Node, r node.NodeRequest) error
	OnContext   func(parent node.Node, s *node.Selection) context.Context
	OnRelease   func(parent node.Node, s *node.Selection)
}

Extend let's you alter any Node behavior including the nodeutil it creates.

Example
model := `
		leaf bar {
			type string;
		}
		leaf bleep {
			type string;
		}
	`
f := foo{
	Bar: "x",
}
bleep := "y"
data := &nodeutil.Extend{
	Base: nodeutil.ReflectChild(&f),
	OnField: func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error {
		switch r.Meta.Ident() {
		case "bleep":
			if r.Write {
				bleep = hnd.Val.String()
			} else {
				hnd.Val = val.String(bleep)
			}
		default:
			return parent.Field(r, hnd)
		}
		return nil
	},
}

sel := exampleSelection(model, data)

examplePrint(sel)
Output:

{"bar":"x","bleep":"y"}

func (*Extend) Action

func (e *Extend) Action(r node.ActionRequest) (output node.Node, err error)

func (*Extend) BeginEdit

func (e *Extend) BeginEdit(r node.NodeRequest) error

func (*Extend) Child

func (e *Extend) Child(r node.ChildRequest) (node.Node, error)

func (*Extend) Choose

func (e *Extend) Choose(sel *node.Selection, choice *meta.Choice) (*meta.ChoiceCase, error)

func (*Extend) Context

func (e *Extend) Context(sel *node.Selection) context.Context

func (*Extend) EndEdit

func (e *Extend) EndEdit(r node.NodeRequest) error

func (*Extend) Extend

func (e *Extend) Extend(n node.Node) node.Node

func (*Extend) Field

func (e *Extend) Field(r node.FieldRequest, hnd *node.ValueHandle) error

func (*Extend) Next

func (e *Extend) Next(r node.ListRequest) (child node.Node, key []val.Value, err error)

func (*Extend) Notify

func (e *Extend) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)

func (*Extend) Peek

func (e *Extend) Peek(sel *node.Selection, consumer interface{}) interface{}

func (*Extend) Release

func (e *Extend) Release(sel *node.Selection)

type JSONRdr

type JSONRdr struct {
	In io.Reader
	// contains filtered or unexported fields
}

func (*JSONRdr) Node

func (self *JSONRdr) Node() node.Node

type JSONWtr

type JSONWtr struct {

	// stream to write contents.  contents will be flushed only at end of operation
	Out io.Writer

	// adds extra indenting and line feeds
	Pretty bool

	// otherwise enumerations are written as their labels.  it may be
	// useful to know that json reader can accept labels or values
	EnumAsIds bool

	// Namespaces pollute JSON with module name similar to XML namespaces
	// rules
	//    { "ns:key" : {...}}
	// where you add the module name to top-level object then qualify any
	// sub objects when the module changes. Not only does it make JSON even more
	// illegible, it means you cannot move common meta to a common yang module w/o
	// altering your resulting JSON.  #IETF-FAIL #rant
	//
	// See https://datatracker.ietf.org/doc/html/rfc7951
	//
	// I realize this is to protect against 2 or more keys in same line from different
	// modules but maybe if someone is insane enough to do that, then, and only then, do
	// you distinguish each key with ns
	//
	// To disable this, make this true and get simple JSON like this
	//
	//    { "key": {...}}
	QualifyNamespace bool
	// contains filtered or unexported fields
}

func NewJSONWtr

func NewJSONWtr(out io.Writer) *JSONWtr

func (JSONWtr) JSON

func (wtr JSONWtr) JSON(s *node.Selection) (string, error)

func (*JSONWtr) Node

func (wtr *JSONWtr) Node() node.Node

type OnListValueChange

type OnListValueChange func(update reflect.Value)

type OnReflectChild

type OnReflectChild func(Reflect, reflect.Value) node.Node

type OnReflectList

type OnReflectList func(Reflect, reflect.Value) node.Node

type Pipe

type Pipe struct {
	// contains filtered or unexported fields
}

func NewPipe

func NewPipe() *Pipe

func (*Pipe) Close

func (self *Pipe) Close(err error)

func (*Pipe) PullPush

func (self *Pipe) PullPush() (node.Node, node.Node)

type Reflect

type Reflect struct {

	// Reflect will use Reflect by default for child node. To override that, implement
	// this function
	OnChild OnReflectChild

	// Reflect will use Reflect by default for list node. To override that, implement
	// this function
	OnList OnReflectList

	// Override the conversion of reading and writing values using reflection
	OnField []ReflectField
}

Uses reflection to marshal data into go structs or maps. Structs fields need to be Public and names must match yang. Map keys must match yang as well.

Has limited ability to provide customer handing of data but you are encouraged to use this combination:

&nodeutil.Extend{
    Base: nodeutil.Reflect{}.Object(obj),
    OnChild:...
}
Example (Extend)
model := `
		leaf-list bleep {
			type string;
		}
		leaf len {
			type int32;
			config false;
		}
	`

data := struct {
	Bleep []string
}{
	Bleep: []string{
		"a", "b",
	},
}
n := &nodeutil.Extend{
	Base: nodeutil.ReflectChild(&data),
	OnField: func(parent node.Node, r node.FieldRequest, hnd *node.ValueHandle) error {
		switch r.Meta.Ident() {
		case "len":
			hnd.Val = val.Int32(len(data.Bleep))
		default:
			return parent.Field(r, hnd)
		}
		return nil
	},
}

sel := exampleSelection(model, n)

examplePrint(sel)
Output:

{"bleep":["a","b"],"len":2}
Example (Struct)
model := `
	    container foo {
			leaf bar {
				type string;
			}
		} 
		list foos {
			key "bar";
			leaf bar {
				type string;
			}	
		}
		leaf-list bleep {
			type string;
		}
		`
data := struct {
	Foo   *foo
	Foos  map[string]*foo
	Bleep []string
}{
	Foo: &foo{
		Bar: "x",
	},
	Foos: map[string]*foo{
		"y": {
			Bar: "y",
		},
	},
	Bleep: []string{
		"a", "b",
	},
}
sel := exampleSelection(model, nodeutil.ReflectChild(&data))
examplePrint(sel)
Output:

{"foo":{"bar":"x"},"foos":[{"bar":"y"}],"bleep":["a","b"]}

func (Reflect) Child

func (self Reflect) Child(v reflect.Value) node.Node

func (Reflect) List

func (self Reflect) List(o interface{}) node.Node

func (Reflect) Object

func (self Reflect) Object(obj interface{}) node.Node

func (Reflect) ReadField

func (self Reflect) ReadField(m meta.Leafable, ptrVal reflect.Value) (val.Value, error)

func (Reflect) ReadFieldWithFieldName

func (self Reflect) ReadFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value) (val.Value, error)

func (Reflect) ReflectList

func (self Reflect) ReflectList(v reflect.Value, onUpdate OnListValueChange) node.Node

func (Reflect) WriteField

func (self Reflect) WriteField(m meta.Leafable, ptrVal reflect.Value, v val.Value) error

func (Reflect) WriteFieldWithFieldName

func (self Reflect) WriteFieldWithFieldName(fieldName string, m meta.Leafable, ptrVal reflect.Value, v val.Value) error

type ReflectField

type ReflectField struct {

	// Select when a field handling is used
	// This might be called with an invalid fieldElem, so if it depends on this parameters it has to check.
	When ReflectFieldSelector

	// Called just after reading the value using reflection to convert value
	// to freeconf value type.  Null means use default conversion
	// This might be called with an invalid fieldElem, so if it depends on this parameters it has to check.
	OnRead ReflectOnRead

	// Called just before setting the value using reflection to convert value
	// to native type.  Null means use default conversion
	// This might be called with an invalid fieldElem, so if it depends on this parameters it has to check.
	OnWrite ReflectOnWrite
}

ReflectField

type ReflectFieldSelector

type ReflectFieldSelector func(m meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value) bool

ReflectFieldSelector is a predicate to decide which fields are selected for custom handling.

func ReflectFieldByType

func ReflectFieldByType(target reflect.Type) ReflectFieldSelector

ReflectFieldByType is convienent field selection by Go data type. Example:

nodeutil.ReflectFieldByType(reflect.TypeOf(netip.Addr{}))

type ReflectOnRead

type ReflectOnRead func(leaf meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value) (val.Value, error)

ReflectOnRead converts native value to freeconf value Example: time.Duration to int of secs:

	     func(m meta.Leafable, fieldname string, elem reflect.Value) (val.Value, error) {
             secs := elem.FieldByName(fieldname).Int()
				return val.Int32(secs / int64(time.Second)), nil
			}

type ReflectOnWrite

type ReflectOnWrite func(leaf meta.Leafable, fieldname string, elem reflect.Value, fieldElem reflect.Value, v val.Value) error

ReflectOnWrite converts freeconf value to native value. Example: secs as int to time.Duration:

     func(_ meta.Leafable, v val.Value) (reflect.Value, error) {
			return reflect.ValueOf(time.Second * time.Duration(v.Value().(int))), nil
		},

type Subscription

type Subscription interface {
	Close() error
}

Subscription is handle into a list.List that when closed will automatically remove item from list. Useful for maintaining a set of listeners that can easily remove themselves.

Example
listeners := list.New()
listener := func() {}
sub := NewSubscription(listeners, listeners.PushBack(listener))
fmt.Printf("%d listeners before close\n", listeners.Len())
sub.Close()
fmt.Printf("%d listeners after close\n", listeners.Len())
Output:

1 listeners before close
0 listeners after close

func NewSubscription

func NewSubscription(l *list.List, e *list.Element) Subscription

NewSubscription is used by subscription managers to give a token to caller the can close to unsubscribe to events

type Tee

type Tee struct {
	A node.Node
	B node.Node
}

when writing values, splits output into two nodeutil. when reading, reads from secondary only when primary returns nil

func (Tee) Action

func (self Tee) Action(r node.ActionRequest) (output node.Node, err error)

func (Tee) BeginEdit

func (self Tee) BeginEdit(r node.NodeRequest) (err error)

func (Tee) Child

func (self Tee) Child(r node.ChildRequest) (node.Node, error)

func (Tee) Choose

func (self Tee) Choose(sel *node.Selection, choice *meta.Choice) (m *meta.ChoiceCase, err error)

func (Tee) Context

func (self Tee) Context(s *node.Selection) context.Context

func (Tee) EndEdit

func (self Tee) EndEdit(r node.NodeRequest) (err error)

func (Tee) Field

func (self Tee) Field(r node.FieldRequest, hnd *node.ValueHandle) (err error)

func (Tee) Next

func (self Tee) Next(r node.ListRequest) (node.Node, []val.Value, error)

func (Tee) Notify

func (self Tee) Notify(r node.NotifyRequest) (closer node.NotifyCloser, err error)

func (Tee) Peek

func (self Tee) Peek(sel *node.Selection, consumer interface{}) interface{}

func (Tee) Release

func (self Tee) Release(sel *node.Selection)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL