tree

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Apr 14, 2024 License: BSD-3-Clause Imports: 22 Imported by: 12

README

Trees in Go

The Tree is one of the most flexible, widely-used data structures in programming, including the DOM structure at the core of a web browser, scene graphs for 3D and 2D graphics systems, JSON, XML, SVG, filesystems, programs themselves, etc. This is because trees can capture most relevant forms of structure (hierarchical groupings, categories, relationships, etc) and are most powerful when they are fully generative -- arbitrary new types can be inserted flexibly.

Cogent Core provides a general-purpose tree container type, that can support all of these applications, by embedding and extending the NodeBase struct type that implements the Node interface. Unlike many cases in Go, the need to be able to arbitrarily extend the type space of nodes in the tree within a consistent API, means that the more traditional object-oriented model works best here, with a single common base type, and derived types that handle diverse cases (e.g., different types of widgets in a GUI). Cogent Core stores a Node interface of each node, enabling correct virtual function calling on these derived types.

A virtue of using an appropriate data representation is that some important operations can be performed particularly concisely and efficiently when they are naturally supported by the data structure. For example, matrices and vectors as supported by numpy or MATLAB provide a concise high-level language for expressing many algorithms.

In addition, Cogent Core provides functions that traverse the tree in the usual relevant ways and take a func function argument, so you can easily apply a common operation across the whole tree in a transparent and self-contained manner, like this:

func (mn *MyNode) DoSomethingOnMyTree() {
	mn.WalkPre(func(n tree.Node) bool {
		DoSomething(n)
		// ...
		return tree.Continue // return value determines whether tree traversal continues or not
	})
}

Many operations are naturally expressed in terms of these traversal algorithms.

Three core Cogent Core features include:

  • ConfigChildren uses a list of types and names and performs a minimal, efficient update of the children of a node to configure them to match (including no changes if already configured accordingly). This is used during loading from JSON, and extensively in the Cogent Core GUI system to efficiently re-use existing tree elements. There is often complex logic to determine what elements need to be present in a Widget, so separating that out from then configuring the elements that actually are present is efficient and simplifies the code.

Cogent Core Graphical Interface

The first and most important application of tree is the Cogent Core graphical interface system, in the core package. The scene graph of tree elements automatically drives minimal refresh updates, allowing Cogent Core to provide a complete interactive 2D and 3D GUI environment in native Go, in a compact codebase. Part of this is the natural elegance of Go, but Cogent Core enhances that by providing the robust natural primitives needed to express all the GUI functionality.

The parse interactive parsing framework also leverages Cogent Core trees to represent the AST (abstract syntax tree) of programs in different languages. Further, the parser grammar itself is written (in a GUI interactive way) as a tree of parsing elements using tree nodes.

Examples

See node_test.go for lots of simple usage examples.

Trick for fast finding in a slice

Cogent Core takes an extra starting index arg for all methods that lookup a value in a slice, such as ChildByName. The search for the item starts at that index, and goes up and down from there. Thus, if you have any idea where the item might be in the list, it can save (considerable for large lists) time finding it.

Furthermore, it enables a robust optimized lookup map that remembers these indexes for each item, but then always searches from the index, so it is always correct under list modifications, but if the list is unchanged, then it is very efficient, and does not require saving pointers, which minimizes any impact on the GC, prevents stale pointers, etc.

The IndexInParent() method uses this trick, using the cached Node.index value.

Here's example code for a separate Find method where the indexes are stored in a map:

// FindByName finds item by name, using cached indexes for speed
func (ob *Obj) FindByName(nm string) *Obj {
	if sv.FindIndexes == nil {
		ob.FindIndexes = make(map[string]int) // field on object
	}
	idx, has := ob.FindIndexes[nm]
	if !has {
		idx = len(ob.Kids) / 2 // start in middle first time
	}
	idx, has = ob.Kids.IndexByName(nm, idx)
	if has {
		ob.FindIndexes[nm] = idx
		return ob.Kids[idx].(*Obj)
  	}
	delete(ob.FindIndexes, nm) // must have been deleted
	return nil
}

Documentation

Overview

Package tree provides a powerful and extensible tree system, centered on the core Node interface.

Index

Constants

View Source
const (
	// Continue = true can be returned from tree iteration functions to continue
	// processing down the tree, as compared to Break = false which stops this branch.
	Continue = true

	// Break = false can be returned from tree iteration functions to stop processing
	// this branch of the tree.
	Break = false

	// Embeds is used for methods that look for children or parents of different types.
	// Passing this argument means to look for embedded types for matches.
	Embeds = true

	// NoEmbeds is used for methods that look for children or parents of different types.
	// Passing this argument means to NOT look for embedded types for matches.
	NoEmbeds = false
)

Named constants for bool args

Variables

View Source
var JSONTypePrefix = []byte("{\"tree.RootType\": ")

JSONTypePrefix is the first thing output in a tree JSON output file, specifying the type of the root node of the tree -- this info appears all on one { } bracketed line at the start of the file, and can also be used to identify the file as a tree JSON file

View Source
var JSONTypeSuffix = []byte("}\n")

JSONTypeSuffix is just the } and \n at the end of the prefix line

View Source
var NodeBaseType = types.AddType(&types.Type{Name: "cogentcore.org/core/tree.NodeBase", IDName: "node-base", Doc: "NodeBase implements the [Node] interface and provides the core functionality\nfor the Cogent Core tree system. You should use NodeBase as an embedded struct\nin higher-level tree types.", Fields: []types.Field{{Name: "Nm", Doc: "Nm is the user-supplied name of this node, which can be empty and/or non-unique.\nIt is typically accessed through [Node.Name]."}, {Name: "Flags", Doc: "Flags are bit flags for internal node state, which can be extended using\nthe enums package."}, {Name: "Props", Doc: "Props is a property map for arbitrary key-value properties.\nThey are typically accessed through the property methods on [Node]."}, {Name: "Par", Doc: "Par is the parent of this node, which is set automatically when this node is\nadded as a child of a parent. It is typically accessed through [Node.Parent]."}, {Name: "Kids", Doc: "Kids is the list of children of this node. All of them are set to have this node\nas their parent. They can be reordered, but you should generally use [Node]\nmethods when adding and deleting children to ensure everything gets updated.\nThey are typically accessed through [Node.Children]."}, {Name: "this", Doc: "this is a pointer to ourselves as a [Node]. It can always be used to extract the\ntrue underlying type of an object when [NodeBase] is embedded in other structs;\nfunction receivers do not have this ability, so this is necessary. This is set\nto nil when the node is deleted. It is typically accessed through [Node.This]."}, {Name: "numLifetimeChildren", Doc: "numLifetimeChildren is the number of children that have ever been added to this\nnode, which is used for automatic unique naming. It is typically accessed\nthrough [Node.NumLifetimeChildren]."}, {Name: "index", Doc: "index is the last value of our index, which is used as a starting point for\nfinding us in our parent next time. It is not guaranteed to be accurate;\nuse the [Node.IndexInParent] method."}, {Name: "depth", Doc: "depth is the depth of the node while using [Node.WalkDownBreadth]."}}, Instance: &NodeBase{}})

NodeBaseType is the types.Type for NodeBase

Functions

func ChildByType

func ChildByType[T Node](k Node, embeds bool, startIndex ...int) T

ChildByType is a generic helper function for [Node.ChildByType].

func DecodeXMLCharData

func DecodeXMLCharData(d *xml.Decoder) (val string, err error)

DecodeXMLCharData reads char data..

func DecodeXMLCharEl

func DecodeXMLCharEl(d *xml.Decoder) (name, val string, err error)

DecodeXMLCharEl reads a start / chardata / end sequence of 3 elements, returning name, val

func DecodeXMLEndEl

func DecodeXMLEndEl(d *xml.Decoder, start xml.StartElement) error

DecodeXMLEndEl reads an end element

func DecodeXMLStartEl

func DecodeXMLStartEl(d *xml.Decoder) (start xml.StartElement, err error)

DecodeXMLStartEl reads a start element token

func EscapePathName

func EscapePathName(name string) string

EscapePathName returns a name that replaces any path delimiter symbols . or / with \, and \\ escaped versions.

func InsertNewChild

func InsertNewChild[T Node](parent Node, at int, name ...string) T

InsertNewChild is a generic helper function for [Node.InsertNewChild].

func IsNode

func IsNode(typ reflect.Type) bool

IsNode returns whether the given type or a pointer to it implements the Node interface.

func IsRoot

func IsRoot(n Node) bool

IsRoot tests whether the given node is the root node in its tree.

func MoveToParent

func MoveToParent(child Node, parent Node)

MoveToParent removes the given node from its current parent and adds it as a child of the given new parent. The old and new parents can be in different trees (or not).

func New

func New[T Node](parent Node, name ...string) T

New adds a new child of the given the type with the given name to the given parent. If the name is unspecified, it defaults to the ID (kebab-case) name of the type, plus the [Node.NumLifetimeChildren] of its parent. It is a generic helper function that calls [Node.NewChild].

func NewRoot

func NewRoot[T Node](name ...string) T

NewRoot returns a new root node of the given the type with the given name. If the name is unspecified, it defaults to the ID (kebab-case) name of the type. It is a generic helper function that calls [Node.InitName].

func ParentAllChildren

func ParentAllChildren(kn Node)

ParentAllChildren walks the tree down from current node and call SetParent on all children -- needed after an Unmarshal.

func ParentByType

func ParentByType[T Node](k Node, embeds bool) T

ParentByType is a generic helper function for [Node.ParentByType].

func ReadRootTypeJSON

func ReadRootTypeJSON(b []byte) (*types.Type, []byte, error)

ReadRootTypeJSON reads the type of the root node as encoded by WriteRootTypeJSON, returning the types.Type for the saved type name (error if not found), the remaining bytes to be decoded using a standard unmarshal, and an error.

func RootTypeJSON

func RootTypeJSON(k Node) []byte

RootTypeJSON returns the JSON encoding of the type of the root node (this node) which is written first using our custom JSONEncoder type, to enable a file to be loaded de-novo and recreate the proper root type for the tree.

func SaveNewJSON

func SaveNewJSON(k Node, filename string) error

SaveNewJSON writes JSON-encoded bytes to given writer including key type information at start of file so ReadNewJSON can create an object of the proper type.

func SetParent

func SetParent(child Node, parent Node)

SetParent sets the parent of the given node to the given parent node. This is only for nodes with no existing parent; see MoveToParent to move nodes that already have a parent. It does not add the node to the parent's list of children; see [Node.AddChild] for a version that does.

func SliceDeleteAtIndex

func SliceDeleteAtIndex(sl *[]Node, i int) error

SliceDeleteAtIndex deletes item at index; does not do any further management of deleted item. It is an optimized version for avoiding memory leaks. It returns an error if the index is invalid.

func SliceIndexByFunc

func SliceIndexByFunc(sl *[]Node, match func(k Node) bool, startIndex ...int) (int, bool)

SliceIndexByFunc finds index of item based on match function (which must return true for a find match, false for not). Returns false if not found. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func SliceIndexByName

func SliceIndexByName(sl *[]Node, name string, startIndex ...int) (int, bool)

SliceIndexByName returns index of first element that has given name, false if not found. See Slice.IndexOf for info on startIndex.

func SliceIndexOf

func SliceIndexOf(sl *[]Node, kid Node, startIndex ...int) (int, bool)

SliceIndexOf returns index of element in list, false if not there. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func SliceIsValidIndex

func SliceIsValidIndex(sl *[]Node, idx int) error

SliceIsValidIndex checks whether the given index is a valid index into slice, within range of 0..len-1. Returns error if not.

func SliceMove

func SliceMove(sl *[]Node, frm, to int) error

SliceMove moves element from one position to another. Returns error if either index is invalid.

func SliceSwap

func SliceSwap(sl *[]Node, i, j int) error

SliceSwap swaps elements between positions. Returns error if either index is invalid

func UnescapePathName

func UnescapePathName(name string) string

UnescapePathName returns a name that replaces any escaped path delimiter symbols \, or \\ with . and / unescaped versions.

func UnmarshalPost

func UnmarshalPost(kn Node)

UnmarshalPost must be called after an Unmarshal -- calls ParentAllChildren.

func WriteNewJSON

func WriteNewJSON(k Node, writer io.Writer) error

WriteNewJSON writes JSON-encoded bytes to given writer including key type information at start of file so ReadNewJSON can create an object of the proper type.

Types

type Config

type Config []TypeAndName

Config is a list of [TypeAndName]s used in [Node.ConfigChildren].

func (*Config) Add

func (t *Config) Add(typ *types.Type, name string)

Add adds a new configuration entry with the given type and name.

func (Config) GoString

func (t Config) GoString() string

type Flags

type Flags int64 //enums:bitflag

Flags are bit flags for efficient core state of nodes.

const (
	// Field indicates that a node is a field in
	// its parent node, not a child in children.
	Field Flags = iota
)
const FlagsN Flags = 1

FlagsN is the highest valid value for type Flags, plus one.

func FlagsValues

func FlagsValues() []Flags

FlagsValues returns all possible values for the type Flags.

func (Flags) BitIndexString

func (i Flags) BitIndexString() string

BitIndexString returns the string representation of this Flags value if it is a bit index value (typically an enum constant), and not an actual bit flag value.

func (Flags) Desc

func (i Flags) Desc() string

Desc returns the description of the Flags value.

func (Flags) HasFlag

func (i Flags) HasFlag(f enums.BitFlag) bool

HasFlag returns whether these bit flags have the given bit flag set.

func (Flags) Int64

func (i Flags) Int64() int64

Int64 returns the Flags value as an int64.

func (Flags) MarshalText

func (i Flags) MarshalText() ([]byte, error)

MarshalText implements the encoding.TextMarshaler interface.

func (*Flags) SetFlag

func (i *Flags) SetFlag(on bool, f ...enums.BitFlag)

SetFlag sets the value of the given flags in these flags to the given value.

func (*Flags) SetInt64

func (i *Flags) SetInt64(in int64)

SetInt64 sets the Flags value from an int64.

func (*Flags) SetString

func (i *Flags) SetString(s string) error

SetString sets the Flags value from its string representation, and returns an error if the string is invalid.

func (*Flags) SetStringOr

func (i *Flags) SetStringOr(s string) error

SetStringOr sets the Flags value from its string representation while preserving any bit flags already set, and returns an error if the string is invalid.

func (Flags) String

func (i Flags) String() string

String returns the string representation of this Flags value.

func (*Flags) UnmarshalText

func (i *Flags) UnmarshalText(text []byte) error

UnmarshalText implements the encoding.TextUnmarshaler interface.

func (Flags) Values

func (i Flags) Values() []enums.Enum

Values returns all possible values for the type Flags.

type Node

type Node interface {

	// This returns the Node as its true underlying type.
	// It returns nil if the node is nil, has been destroyed,
	// or is improperly constructed.
	This() Node

	// AsTreeNode returns the [NodeBase] for this Node.
	AsTreeNode() *NodeBase

	// InitName initializes this node to the given actual object as a Node interface
	// and sets its name. The names should be unique among children of a node.
	// This is called automatically when adding child nodes and using [NewRoot].
	// If the name is unspecified, it defaults to the ID (kebab-case) name of the type.
	// Even though this is a method and gets the method receiver, it needs
	// an "external" version of itself passed as the first arg, from which
	// the proper Node interface pointer will be obtained. This is the only
	// way to get virtual functional calling to work within the Go language.
	InitName(this Node, name ...string)

	// Name returns the user-defined name of the Node, which can be
	// used for finding elements, generating paths, I/O, etc.
	Name() string

	// SetName sets the name of this node. Names should generally be unique
	// across children of each node. If the node requires some non-unique name,
	// add a separate Label field.
	SetName(name string)

	// NodeType returns the [types.Type] record for this Node.
	// This is auto-generated by the typegen generator Node types.
	NodeType() *types.Type

	// New returns a new token of the type of this Node.
	// This new Node must still be initialized.
	// This is auto-generated by the typegen generator for Node types.
	New() Node

	// BaseType returns the base node type for all elements within this tree.
	// This is used in the GUI for determining what types of children can be created.
	BaseType() *types.Type

	// Parent returns the parent of this Node.
	// Each Node can only have one parent.
	Parent() Node

	// IndexInParent returns our index within our parent node. It caches the
	// last value and uses that for an optimized search so subsequent calls
	// are typically quite fast. Returns -1 if we don't have a parent.
	IndexInParent() int

	// ParentLevel finds a given potential parent node recursively up the
	// hierarchy, returning the level above the current node that the parent was
	// found, and -1 if not found.
	ParentLevel(parent Node) int

	// ParentByName finds first parent recursively up hierarchy that matches
	// given name. Returns nil if not found.
	ParentByName(name string) Node

	// ParentByType finds parent recursively up hierarchy, by type, and
	// returns nil if not found. If embeds is true, then it looks for any
	// type that embeds the given type at any level of anonymous embedding.
	ParentByType(t *types.Type, embeds bool) Node

	// HasChildren returns whether this node has any children.
	HasChildren() bool

	// NumChildren returns the number of children this node has.
	NumChildren() int

	// NumLifetimeChildren returns the number of children that this node
	// has ever had added to it (it is not decremented when a child is removed).
	// It is used for unique naming of children.
	NumLifetimeChildren() uint64

	// Children returns a pointer to the slice of children of this node.
	// The resultant slice can be modified directly (e.g., sort, reorder),
	// but new children should be added via New/Add/Insert Child methods on
	// Node to ensure proper initialization.
	Children() *Slice

	// Child returns the child of this node at the given index and returns nil if
	// the index is out of range.
	Child(i int) Node

	// ChildByName returns the first child that has the given name, and nil
	// if no such element is found. startIndex arg allows for optimized
	// bidirectional find if you have an idea where it might be, which
	// can be a key speedup for large lists. If no value is specified for
	// startIndex, it starts in the middle, which is a good default.
	ChildByName(name string, startIndex ...int) Node

	// ChildByType returns the first child that has the given type, and nil
	// if not found. If embeds is true, then it also looks for any type that
	// embeds the given type at any level of anonymous embedding.
	// startIndex arg allows for optimized bidirectional find if you have an
	// idea where it might be, which can be a key speedup for large lists. If
	// no value is specified for startIndex, it starts in the middle, which is a
	// good default.
	ChildByType(t *types.Type, embeds bool, startIndex ...int) Node

	// Path returns the path to this node from the tree root,
	// using [Node.Name]s separated by / and fields by .
	// Path is only valid for finding items when child names
	// are unique. Any existing / and . characters in names
	// are escaped to \\ and \,
	Path() string

	// PathFrom returns path to this node from the given parent node, using
	// [Node.Name]s separated by / and fields by .
	// Path is only valid for finding items when child names
	// are unique. Any existing / and . characters in names
	// are escaped to \\ and \,
	//
	// The paths that it returns exclude the
	// name of the parent and the leading slash; for example, in the tree
	// a/b/c/d/e, the result of d.PathFrom(b) would be c/d. PathFrom
	// automatically gets the [Node.This] version of the given parent,
	// so a base type can be passed in without manually calling [Node.This].
	PathFrom(parent Node) string

	// FindPath returns the node at the given path, starting from this node.
	// If this node is not the root, then the path to this node is subtracted
	// from the start of the path if present there.
	// FindPath only works correctly when names are unique.
	// Path has [Node.Name]s separated by / and fields by .
	// Node names escape any existing / and . characters to \\ and \,
	// There is also support for [idx] index-based access for any given path
	// element, for cases when indexes are more useful than names.
	// Returns nil if not found.
	FindPath(path string) Node

	// FieldByName returns the node that is a direct field with the given name.
	// This must be implemented for any types that have Node fields that
	// are processed as part of the overall Node tree. This is only used
	// by [Node.FindPath]. Returns error if not found.
	FieldByName(field string) (Node, error)

	// AddChild adds given child at end of children list.
	// The kid node is assumed to not be on another tree (see [MoveToParent])
	// and the existing name should be unique among children.
	AddChild(kid Node) error

	// NewChild creates a new child of the given type and adds it at end
	// of children list. The name should be unique among children. If the
	// name is unspecified, it defaults to the ID (kebab-case) name of the
	// type, plus the [Ki.NumLifetimeChildren] of its parent.
	NewChild(typ *types.Type, name ...string) Node

	// SetChild sets child at given index to be the given item; if it is passed
	// a name, then it sets the name of the child as well; just calls Init
	// (or InitName) on the child, and SetParent. Names should be unique
	// among children.
	SetChild(kid Node, idx int, name ...string) error

	// InsertChild adds given child at position in children list.
	// The kid node is assumed to not be on another tree (see [MoveToParent])
	// and the existing name should be unique among children.
	InsertChild(kid Node, at int) error

	// InsertNewChild creates a new child of given type and add at position
	// in children list. The name should be unique among children. If the
	// name is unspecified, it defaults to the ID (kebab-case) name of the
	// type, plus the [Ki.NumLifetimeChildren] of its parent.
	InsertNewChild(typ *types.Type, at int, name ...string) Node

	// SetNChildren ensures that there are exactly n children, deleting any
	// extra, and creating any new ones, using NewChild with given type and
	// naming according to nameStubX where X is the index of the child.
	// If nameStub is not specified, it defaults to the ID (kebab-case)
	// name of the type. It returns whether any changes were made to the
	// children.
	//
	// Note that this does not ensure existing children are of given type, or
	// change their names, or call UniquifyNames; use ConfigChildren for
	// those cases; this function is for simpler cases where a parent uses
	// this function consistently to manage children all of the same type.
	SetNChildren(n int, typ *types.Type, nameStub ...string) bool

	// ConfigChildren configures children according to the given list of
	// [TypeAndName]s; it attempts to have minimal impact relative to existing
	// items that fit the type and name constraints (they are moved into the
	// corresponding positions), and any extra children are removed, and new
	// ones added, to match the specified config. It is important that names
	// are unique. It returns whether any changes were made to the children.
	ConfigChildren(config Config) bool

	// DeleteChildAtIndex deletes child at given index. It returns false
	// if there is no child at the given index.
	DeleteChildAtIndex(idx int) bool

	// DeleteChild deletes the given child node, returning false if
	// it can not find it.
	DeleteChild(child Node) bool

	// DeleteChildByName deletes child node by name, returning false
	// if it can not find it.
	DeleteChildByName(name string) bool

	// DeleteChildren deletes all children nodes.
	DeleteChildren()

	// Delete deletes this node from its parent's children list.
	Delete()

	// Destroy recursively deletes and destroys all children and
	// their children's children, etc.
	Destroy()

	// Is checks if the given flag is set, using atomic,
	// which is safe for concurrent access.
	Is(f enums.BitFlag) bool

	// SetFlag sets the given flag(s) to the given state
	// using atomic, which is safe for concurrent access.
	SetFlag(on bool, f ...enums.BitFlag)

	// FlagType returns the flags of the node as the true flag type of the node,
	// which may be a type that extends the standard [Flags]. Each node type
	// that extends the flag type should define this method; for example:
	//	func (wb *WidgetBase) FlagType() enums.BitFlagSetter {
	//		return (*WidgetFlags)(&wb.Flags)
	//	}
	FlagType() enums.BitFlagSetter

	// Properties returns the key-value properties set for this node.
	Properties() map[string]any

	// SetProperty sets given the given property to the given value.
	SetProperty(key string, value any)

	// Property returns the property value for the given key.
	// It returns nil if it doesn't exist.
	Property(key string) any

	// DeleteProperty deletes the property with the given key.
	DeleteProperty(key string)

	// WalkUp calls the given function on the node and all of its parents,
	// sequentially in the current goroutine (generally necessary for going up,
	// which is typically quite fast anyway). It stops walking if the function
	// returns [Break] and keeps walking if it returns [Continue]. It returns
	// whether walking was finished (false if it was aborted with [Break]).
	WalkUp(fun func(n Node) bool) bool

	// WalkUpParent calls the given function on all of the node's parents (but not
	// the node itself), sequentially in the current goroutine (generally necessary
	// for going up, which is typically quite fast anyway). It stops walking if the
	// function returns [Break] and keeps walking if it returns [Continue]. It returns
	// whether walking was finished (false if it was aborted with [Break]).
	WalkUpParent(fun func(n Node) bool) bool

	// WalkDown calls the given function on the node and all of its children
	// in a depth-first manner over all of the children, sequentially in the
	// current goroutine. It stops walking the current branch of the tree if
	// the function returns [Break] and keeps walking if it returns [Continue].
	// It is non-recursive and safe for concurrent calling. The [Node.NodeWalkDown]
	// method is called for every node after the given function, which enables nodes
	// to also traverse additional nodes, like widget parts.
	WalkDown(fun func(n Node) bool)

	// NodeWalkDown is a method that nodes can implement to traverse additional nodes
	// like widget parts during [Node.WalkDown]. It is called with the function passed
	// to [Node.WalkDown] after the function is called with the node itself.
	NodeWalkDown(fun func(n Node) bool)

	// WalkDownPost iterates in a depth-first manner over the children, calling
	// doChildTest on each node to test if processing should proceed (if it returns
	// [Break] then that branch of the tree is not further processed),
	// and then calls the given function after all of a node's children
	// have been iterated over. In effect, this means that the given function
	// is called for deeper nodes first. This uses node state information to manage
	// the traversal and is very fast, but can only be called by one goroutine at a
	// time, so you should use a Mutex if there is a chance of multiple threads
	// running at the same time. The nodes are processed in the current goroutine.
	WalkDownPost(doChildTest func(n Node) bool, fun func(n Node) bool)

	// WalkDownBreadth calls the given function on the node and all of its children
	// in breadth-first order. It stops walking the current branch of the tree if the
	// function returns [Break] and keeps walking if it returns [Continue]. It is
	// non-recursive, but not safe for concurrent calling.
	WalkDownBreadth(fun func(n Node) bool)

	// CopyFrom copies the data and children of the given node to this node.
	// It is essential that the source node has unique names. It is very efficient
	// by using the [Node.ConfigChildren] method which attempts to preserve any
	// existing nodes in the destination if they have the same name and type, so a
	// copy from a source to a target that only differ minimally will be
	// minimally destructive. Only copying to the same type is supported.
	// The struct field tag copier:"-" can be added for any fields that
	// should not be copied. Also, unexported fields are not copied.
	// See [Node.CopyFieldsFrom] for more information on field copying.
	CopyFrom(src Node)

	// Clone creates and returns a deep copy of the tree from this node down.
	// Any pointers within the cloned tree will correctly point within the new
	// cloned tree (see [Node.CopyFrom] for more information).
	Clone() Node

	// CopyFieldsFrom copies the fields of the node from the given node.
	// By default, it is [NodeBase.CopyFieldsFrom], which automatically does
	// a deep copy of all of the fields of the node that do not a have a
	// `copier:"-"` struct tag. Node types should only implement a custom
	// CopyFieldsFrom method when they have fields that need special copying
	// logic that can not be automatically handled. All custom CopyFieldsFrom
	// methods should call [NodeBase.CopyFieldsFrom] first and then only do manual
	// handling of specific fields that can not be automatically copied. See
	// [cogentcore.org/core/core.WidgetBase.CopyFieldsFrom] for an example of a
	// custom CopyFieldsFrom method.
	CopyFieldsFrom(from Node)

	// OnInit is called when the node is
	// initialized (ie: through [Node.InitName]).
	// It is called before the node is added to the tree,
	// so it will not have any parents or siblings.
	// It will be called only once in the lifetime of the node.
	// It does nothing by default, but it can be implemented
	// by higher-level types that want to do something.
	OnInit()

	// OnAdd is called when the node is added to a parent.
	// It will be called only once in the lifetime of the node,
	// unless the node is moved. It will not be called on root
	// nodes, as they are never added to a parent.
	// It does nothing by default, but it can be implemented
	// by higher-level types that want to do something.
	OnAdd()

	// OnChildAdded is called when a node is added to
	// this node or any of its children. When a node is added to
	// a tree, it calls [OnAdd] and then this function on each of its parents,
	// going in order from the closest parent to the furthest parent.
	// This function does nothing by default, but it can be
	// implemented by higher-level types that want to do something.
	OnChildAdded(child Node)
}

Node is an interface that describes the core functionality of a tree node. Each Node is a node in a tree and can have child nodes, and no cycles are allowed (i.e., each node can only appear once in the tree). All the usual methods are included for accessing and managing Children, and efficiently traversing the tree and calling functions on the nodes.

When adding a new node, if you do not specify its name, it will automatically be assigned a unique name of the ID (kebab-case) name of the type, plus the [Node.NumLifetimeChildren] of the parent. In general, the names of the children of a given node should all be unique.

Use the MoveToParent function to move a node between trees or within a tree; otherwise, nodes are typically created and deleted but not moved.

Most Node functions are only implemented once, by the tree.NodeBase type. Other Node types extend tree.NodeBase and provide their own functionality, which can override methods defined by embedded types through a system of virtual method calling, as described below.

Each Node stores the Node interface version of itself, as [Node.This], which enables full virtual function calling by calling the method on that interface instead of directly on the receiver Node itself. This allows, for example, a WidgetBase type to call methods defined by higher-level Widgets. This requires proper initialization of nodes via [Node.InitName], which is called automatically when adding children and using NewRoot.

Nodes support children configuration through [Node.ConfigChildren]. They also support full JSON I/O.

All types that implement the Node interface will automatically be added to the Cogent Core type registry (types) in `core generate`, which is required for various pieces of core functionality.

func Last

func Last(nd Node) Node

Last returns the last node in the tree.

func LastChild

func LastChild(nd Node) Node

LastChild returns the last child under the given node, or the node itself if it has no children.

func NewOfType

func NewOfType(typ *types.Type) Node

NewOfType returns a new instance of the given Node type.

func Next

func Next(nd Node) Node

Next returns next node in the tree, or nil if this is the last node.

func NextSibling

func NextSibling(nd Node) Node

NextSibling returns the next sibling of this node, or nil if it has none.

func OpenNewJSON

func OpenNewJSON(filename string) (Node, error)

OpenNewJSON opens a new tree from a JSON-encoded file, using type information at start of file to create an object of the proper type

func Previous

func Previous(nd Node) Node

Previous returns the previous node in the tree, or nil if this is the root node.

func ReadNewJSON

func ReadNewJSON(reader io.Reader) (Node, error)

ReadNewJSON reads a new tree from a JSON-encoded byte string, using type information at start of file to create an object of the proper type

func Root

func Root(n Node) Node

Root returns the root node of the given node's tree.

type NodeBase

type NodeBase struct {

	// Nm is the user-supplied name of this node, which can be empty and/or non-unique.
	// It is typically accessed through [Node.Name].
	Nm string `copier:"-" set:"-" label:"Name"`

	// Flags are bit flags for internal node state, which can be extended using
	// the enums package.
	Flags Flags `tableview:"-" copier:"-" json:"-" xml:"-" set:"-" max-width:"80" height:"3"`

	// Props is a property map for arbitrary key-value properties.
	// They are typically accessed through the property methods on [Node].
	Props map[string]any `tableview:"-" xml:"-" copier:"-" set:"-" label:"Properties"`

	// Par is the parent of this node, which is set automatically when this node is
	// added as a child of a parent. It is typically accessed through [Node.Parent].
	Par Node `copier:"-" json:"-" xml:"-" view:"-" set:"-"`

	// Kids is the list of children of this node. All of them are set to have this node
	// as their parent. They can be reordered, but you should generally use [Node]
	// methods when adding and deleting children to ensure everything gets updated.
	// They are typically accessed through [Node.Children].
	Kids Slice `tableview:"-" copier:"-" set:"-" label:"Children"`
	// contains filtered or unexported fields
}

NodeBase implements the Node interface and provides the core functionality for the Cogent Core tree system. You should use NodeBase as an embedded struct in higher-level tree types.

func NewNodeBase

func NewNodeBase(parent Node, name ...string) *NodeBase

NewNodeBase adds a new NodeBase with the given name to the given parent: NodeBase implements the Node interface and provides the core functionality for the Cogent Core tree system. You should use NodeBase as an embedded struct in higher-level tree types.

func (*NodeBase) AddChild

func (n *NodeBase) AddChild(kid Node) error

AddChild adds given child at end of children list. The kid node is assumed to not be on another tree (see MoveToParent) and the existing name should be unique among children.

func (*NodeBase) AsTreeNode

func (n *NodeBase) AsTreeNode() *NodeBase

AsTreeNode returns the NodeBase for this Node.

func (*NodeBase) BaseType

func (n *NodeBase) BaseType() *types.Type

BaseType returns the base node type for all elements within this tree. This is used in the GUI for determining what types of children can be created.

func (*NodeBase) Child

func (n *NodeBase) Child(i int) Node

Child returns the child of this node at the given index and returns nil if the index is out of range.

func (*NodeBase) ChildByName

func (n *NodeBase) ChildByName(name string, startIndex ...int) Node

ChildByName returns the first child that has the given name, and nil if no such element is found. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be a key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func (*NodeBase) ChildByType

func (n *NodeBase) ChildByType(t *types.Type, embeds bool, startIndex ...int) Node

ChildByType returns the first child that has the given type, and nil if not found. If embeds is true, then it also looks for any type that embeds the given type at any level of anonymous embedding. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be a key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func (*NodeBase) Children

func (n *NodeBase) Children() *Slice

Children returns a pointer to the slice of children of this node. The resultant slice can be modified directly (e.g., sort, reorder), but new children should be added via New/Add/Insert Child methods on Node to ensure proper initialization.

func (*NodeBase) Clone

func (n *NodeBase) Clone() Node

Clone creates and returns a deep copy of the tree from this node down. Any pointers within the cloned tree will correctly point within the new cloned tree (see [Node.CopyFrom] for more information).

func (*NodeBase) ConfigChildren

func (n *NodeBase) ConfigChildren(config Config) bool

ConfigChildren configures children according to the given list of [TypeAndName]s; it attempts to have minimal impact relative to existing items that fit the type and name constraints (they are moved into the corresponding positions), and any extra children are removed, and new ones added, to match the specified config. It is important that names are unique. It returns whether any changes were made to the children.

func (*NodeBase) CopyFieldsFrom

func (n *NodeBase) CopyFieldsFrom(from Node)

CopyFieldsFrom copies the fields of the node from the given node. By default, it is NodeBase.CopyFieldsFrom, which automatically does a deep copy of all of the fields of the node that do not a have a `copier:"-"` struct tag. Node types should only implement a custom CopyFieldsFrom method when they have fields that need special copying logic that can not be automatically handled. All custom CopyFieldsFrom methods should call NodeBase.CopyFieldsFrom first and then only do manual handling of specific fields that can not be automatically copied. See cogentcore.org/core/core.WidgetBase.CopyFieldsFrom for an example of a custom CopyFieldsFrom method.

func (*NodeBase) CopyFrom

func (n *NodeBase) CopyFrom(src Node)

CopyFrom copies the data and children of the given node to this node. It is essential that the source node has unique names. It is very efficient by using the [Node.ConfigChildren] method which attempts to preserve any existing nodes in the destination if they have the same name and type, so a copy from a source to a target that only differ minimally will be minimally destructive. Only copying to the same type is supported. The struct field tag copier:"-" can be added for any fields that should not be copied. Also, unexported fields are not copied. See [Node.CopyFieldsFrom] for more information on field copying.

func (*NodeBase) Delete

func (n *NodeBase) Delete()

Delete deletes this node from its parent's children list.

func (*NodeBase) DeleteChild

func (n *NodeBase) DeleteChild(child Node) bool

DeleteChild deletes the given child node, returning false if it can not find it.

func (*NodeBase) DeleteChildAtIndex

func (n *NodeBase) DeleteChildAtIndex(idx int) bool

DeleteChildAtIndex deletes child at given index. It returns false if there is no child at the given index.

func (*NodeBase) DeleteChildByName

func (n *NodeBase) DeleteChildByName(name string) bool

DeleteChildByName deletes child node by name, returning false if it can not find it.

func (*NodeBase) DeleteChildren

func (n *NodeBase) DeleteChildren()

DeleteChildren deletes all children nodes.

func (*NodeBase) DeleteProperty

func (n *NodeBase) DeleteProperty(key string)

DeleteProperty deletes the property with the given key.

func (*NodeBase) Destroy

func (n *NodeBase) Destroy()

Destroy recursively deletes and destroys all children and their children's children, etc.

func (*NodeBase) FieldByName

func (n *NodeBase) FieldByName(field string) (Node, error)

FieldByName is a placeholder implementation of [Node.FieldByName] that returns an error.

func (*NodeBase) FindPath

func (n *NodeBase) FindPath(path string) Node

FindPath returns the node at the given path, starting from this node. If this node is not the root, then the path to this node is subtracted from the start of the path if present there. FindPath only works correctly when names are unique. Path has [Node.Name]s separated by / and fields by . Node names escape any existing / and . characters to \\ and \, There is also support for [idx] index-based access for any given path element, for cases when indexes are more useful than names. Returns nil if not found.

func (*NodeBase) FlagType

func (n *NodeBase) FlagType() enums.BitFlagSetter

FlagType returns the flags of the node as the true flag type of the node, which may be a type that extends the standard Flags. Each node type that extends the flag type should define this method; for example:

func (wb *WidgetBase) FlagType() enums.BitFlagSetter {
	return (*WidgetFlags)(&wb.Flags)
}

func (*NodeBase) HasChildren

func (n *NodeBase) HasChildren() bool

HasChildren returns whether this node has any children.

func (*NodeBase) IndexInParent

func (n *NodeBase) IndexInParent() int

IndexInParent returns our index within our parent node. It caches the last value and uses that for an optimized search so subsequent calls are typically quite fast. Returns -1 if we don't have a parent.

func (*NodeBase) InitName

func (n *NodeBase) InitName(k Node, name ...string)

InitName initializes this node to the given actual object as a Node interface and sets its name. The names should be unique among children of a node. This is called automatically when adding child nodes and using NewRoot. If the name is unspecified, it defaults to the ID (kebab-case) name of the type. Even though this is a method and gets the method receiver, it needs an "external" version of itself passed as the first arg, from which the proper Node interface pointer will be obtained. This is the only way to get virtual functional calling to work within the Go language.

func (*NodeBase) InsertChild

func (n *NodeBase) InsertChild(kid Node, at int) error

InsertChild adds given child at position in children list. The kid node is assumed to not be on another tree (see MoveToParent) and the existing name should be unique among children.

func (*NodeBase) InsertNewChild

func (n *NodeBase) InsertNewChild(typ *types.Type, at int, name ...string) Node

InsertNewChild creates a new child of given type and add at position in children list. The name should be unique among children. If the name is unspecified, it defaults to the ID (kebab-case) name of the type, plus the [Ki.NumLifetimeChildren] of its parent.

func (*NodeBase) Is

func (n *NodeBase) Is(f enums.BitFlag) bool

Is checks if the given flag is set, using atomic, which is safe for concurrent access.

func (*NodeBase) Name

func (n *NodeBase) Name() string

Name returns the user-defined name of the Node, which can be used for finding elements, generating paths, I/O, etc.

func (*NodeBase) New

func (t *NodeBase) New() Node

New returns a new *NodeBase value

func (*NodeBase) NewChild

func (n *NodeBase) NewChild(typ *types.Type, name ...string) Node

NewChild creates a new child of the given type and adds it at end of children list. The name should be unique among children. If the name is unspecified, it defaults to the ID (kebab-case) name of the type, plus the [Ki.NumLifetimeChildren] of its parent.

func (*NodeBase) NodeType

func (t *NodeBase) NodeType() *types.Type

NodeType returns the *types.Type of NodeBase

func (*NodeBase) NodeWalkDown

func (n *NodeBase) NodeWalkDown(fun func(n Node) bool)

NodeWalkDown is a placeholder implementation of [Node.NodeWalkDown] that does nothing.

func (*NodeBase) NumChildren

func (n *NodeBase) NumChildren() int

NumChildren returns the number of children this node has.

func (*NodeBase) NumLifetimeChildren

func (n *NodeBase) NumLifetimeChildren() uint64

NumLifetimeChildren returns the number of children that this node has ever had added to it (it is not decremented when a child is removed). It is used for unique naming of children.

func (*NodeBase) OnAdd

func (n *NodeBase) OnAdd()

OnAdd is a placeholder implementation of [Node.OnAdd] that does nothing.

func (*NodeBase) OnChildAdded

func (n *NodeBase) OnChildAdded(child Node)

OnChildAdded is a placeholder implementation of [Node.OnChildAdded] that does nothing.

func (*NodeBase) OnInit

func (n *NodeBase) OnInit()

OnInit is a placeholder implementation of [Node.OnInit] that does nothing.

func (*NodeBase) Parent

func (n *NodeBase) Parent() Node

Parent returns the parent of this Node. Each Node can only have one parent.

func (*NodeBase) ParentByName

func (n *NodeBase) ParentByName(name string) Node

ParentByName finds first parent recursively up hierarchy that matches given name. Returns nil if not found.

func (*NodeBase) ParentByType

func (n *NodeBase) ParentByType(t *types.Type, embeds bool) Node

ParentByType finds parent recursively up hierarchy, by type, and returns nil if not found. If embeds is true, then it looks for any type that embeds the given type at any level of anonymous embedding.

func (*NodeBase) ParentLevel

func (n *NodeBase) ParentLevel(parent Node) int

ParentLevel finds a given potential parent node recursively up the hierarchy, returning the level above the current node that the parent was found, and -1 if not found.

func (*NodeBase) Path

func (n *NodeBase) Path() string

Path returns the path to this node from the tree root, using [Node.Name]s separated by / and fields by . Path is only valid for finding items when child names are unique. Any existing / and . characters in names are escaped to \\ and \,

func (*NodeBase) PathFrom

func (n *NodeBase) PathFrom(parent Node) string

PathFrom returns path to this node from the given parent node, using [Node.Name]s separated by / and fields by . Path is only valid for finding items when child names are unique. Any existing / and . characters in names are escaped to \\ and \,

The paths that it returns exclude the name of the parent and the leading slash; for example, in the tree a/b/c/d/e, the result of d.PathFrom(b) would be c/d. PathFrom automatically gets the [Node.This] version of the given parent, so a base type can be passed in without manually calling [Node.This].

func (*NodeBase) Properties

func (n *NodeBase) Properties() map[string]any

Properties returns the key-value properties set for this node.

func (*NodeBase) Property

func (n *NodeBase) Property(key string) any

Property returns the property value for the given key. It returns nil if it doesn't exist.

func (*NodeBase) ReadXML

func (n *NodeBase) ReadXML(reader io.Reader) error

ReadXML reads the tree from an XML-encoded byte string over io.Reader, calls UnmarshalPost to recover pointers from paths.

func (*NodeBase) SetChild

func (n *NodeBase) SetChild(kid Node, idx int, name ...string) error

SetChild sets child at given index to be the given item; if it is passed a name, then it sets the name of the child as well; just calls Init (or InitName) on the child, and SetParent. Names should be unique among children.

func (*NodeBase) SetFlag

func (n *NodeBase) SetFlag(on bool, f ...enums.BitFlag)

SetFlag sets the given flag(s) to the given state using atomic, which is safe for concurrent access.

func (*NodeBase) SetNChildren

func (n *NodeBase) SetNChildren(trgn int, typ *types.Type, nameStub ...string) bool

SetNChildren ensures that there are exactly n children, deleting any extra, and creating any new ones, using NewChild with given type and naming according to nameStubX where X is the index of the child. If nameStub is not specified, it defaults to the ID (kebab-case) name of the type. It returns whether any changes were made to the children.

Note that this does not ensure existing children are of given type, or change their names, or call UniquifyNames; use ConfigChildren for those cases; this function is for simpler cases where a parent uses this function consistently to manage children all of the same type.

func (*NodeBase) SetName

func (n *NodeBase) SetName(name string)

SetName sets the name of this node. Names should generally be unique across children of each node. If the node requires some non-unique name, add a separate Label field.

func (*NodeBase) SetProperty

func (n *NodeBase) SetProperty(key string, value any)

SetProperty sets given the given property to the given value.

func (*NodeBase) String

func (n *NodeBase) String() string

String implements the fmt.Stringer interface by returning the path of the node.

func (*NodeBase) This

func (n *NodeBase) This() Node

This returns the Node as its true underlying type. It returns nil if the node is nil, has been destroyed, or is improperly constructed.

func (*NodeBase) WalkDown

func (n *NodeBase) WalkDown(fun func(n Node) bool)

WalkDown calls the given function on the node and all of its children in a depth-first manner over all of the children, sequentially in the current goroutine. It stops walking the current branch of the tree if the function returns Break and keeps walking if it returns Continue. It is non-recursive and safe for concurrent calling. The [Node.NodeWalkDown] method is called for every node after the given function, which enables nodes to also traverse additional nodes, like widget parts.

func (*NodeBase) WalkDownBreadth

func (n *NodeBase) WalkDownBreadth(fun func(n Node) bool)

WalkDownBreadth calls the given function on the node and all of its children in breadth-first order. It stops walking the current branch of the tree if the function returns Break and keeps walking if it returns Continue. It is non-recursive, but not safe for concurrent calling.

func (*NodeBase) WalkDownPost

func (n *NodeBase) WalkDownPost(doChildTestFunc func(n Node) bool, fun func(n Node) bool)

WalkDownPost iterates in a depth-first manner over the children, calling doChildTest on each node to test if processing should proceed (if it returns Break then that branch of the tree is not further processed), and then calls the given function after all of a node's children have been iterated over. In effect, this means that the given function is called for deeper nodes first. This uses node state information to manage the traversal and is very fast, but can only be called by one goroutine at a time, so you should use a Mutex if there is a chance of multiple threads running at the same time. The nodes are processed in the current goroutine.

func (*NodeBase) WalkUp

func (n *NodeBase) WalkUp(fun func(n Node) bool) bool

WalkUp calls the given function on the node and all of its parents, sequentially in the current goroutine (generally necessary for going up, which is typically quite fast anyway). It stops walking if the function returns Break and keeps walking if it returns Continue. It returns whether walking was finished (false if it was aborted with Break).

func (*NodeBase) WalkUpParent

func (n *NodeBase) WalkUpParent(fun func(n Node) bool) bool

WalkUpParent calls the given function on all of the node's parents (but not the node itself), sequentially in the current goroutine (generally necessary for going up, which is typically quite fast anyway). It stops walking if the function returns Break and keeps walking if it returns Continue. It returns whether walking was finished (false if it was aborted with Break).

func (*NodeBase) WriteXML

func (n *NodeBase) WriteXML(writer io.Writer, indent bool) error

WriteXML writes the tree to an XML-encoded byte string over io.Writer using MarshalXML.

type Slice

type Slice []Node

Slice is just a slice of tree nodes: []Node, providing methods for accessing elements in the slice, and JSON marshal / unmarshal with encoding of underlying types

func (*Slice) Config

func (sl *Slice) Config(n Node, config Config) bool

Config is a major work-horse routine for minimally destructive reshaping of a tree structure to fit a target configuration, specified in terms of a type-and-name list. It returns whether any changes were made to the slice.

func (*Slice) ConfigCopy

func (sl *Slice) ConfigCopy(n Node, frm Slice)

ConfigCopy uses Config method to copy name / type config of Slice from source If n is != nil then Update etc is called properly. it is essential that child names are unique.

func (*Slice) CopyFrom

func (sl *Slice) CopyFrom(frm Slice)

CopyFrom another Slice. It is efficient by using the Config method which attempts to preserve any existing nodes in the destination if they have the same name and type -- so a copy from a source to a target that only differ minimally will be minimally destructive. it is essential that child names are unique.

func (*Slice) DeleteAtIndex

func (sl *Slice) DeleteAtIndex(idx int) error

DeleteAtIndex deletes item at index; does not do any further management of deleted item. It is an optimized version for avoiding memory leaks. It returns an error if the index is invalid.

func (*Slice) Elem

func (sl *Slice) Elem(idx int) Node

Elem returns element at index; panics if index is invalid.

func (*Slice) ElemByName

func (sl *Slice) ElemByName(name string, startIndex ...int) Node

ElemByName returns first element that has given name, nil if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) ElemByNameTry

func (sl *Slice) ElemByNameTry(name string, startIndex ...int) (Node, error)

ElemByNameTry returns first element that has given name, error if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) ElemByType

func (sl *Slice) ElemByType(t *types.Type, embeds bool, startIndex ...int) Node

ElemByType returns index of element that either is that type or embeds that type, nil if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) ElemByTypeTry

func (sl *Slice) ElemByTypeTry(t *types.Type, embeds bool, startIndex ...int) (Node, error)

ElemByTypeTry returns index of element that either is that type or embeds that type, error if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) ElemFromEnd

func (sl *Slice) ElemFromEnd(idx int) Node

ElemFromEnd returns element at index from end of slice (0 = last element, 1 = 2nd to last, etc). Panics if invalid index.

func (*Slice) ElemFromEndTry

func (sl *Slice) ElemFromEndTry(idx int) (Node, error)

ElemFromEndTry returns element at index from end of slice (0 = last element, 1 = 2nd to last, etc). Try version returns error on invalid index.

func (*Slice) ElemTry

func (sl *Slice) ElemTry(idx int) (Node, error)

ElemTry returns element at index; returns error if index is invalid.

func (*Slice) IndexByFunc

func (sl *Slice) IndexByFunc(match func(k Node) bool, startIndex ...int) (int, bool)

IndexByFunc finds index of item based on match function (which must return true for a find match, false for not). Returns false if not found. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func (*Slice) IndexByName

func (sl *Slice) IndexByName(name string, startIndex ...int) (int, bool)

IndexByName returns index of first element that has given name, false if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) IndexByType

func (sl *Slice) IndexByType(t *types.Type, embeds bool, startIndex ...int) (int, bool)

IndexByType returns index of element that either is that type or embeds that type, false if not found. See Slice.IndexOf for info on startIndex.

func (*Slice) IndexOf

func (sl *Slice) IndexOf(kid Node, startIndex ...int) (int, bool)

IndexOf returns index of element in list, false if not there. startIndex arg allows for optimized bidirectional find if you have an idea where it might be, which can be key speedup for large lists. If no value is specified for startIndex, it starts in the middle, which is a good default.

func (*Slice) Insert

func (sl *Slice) Insert(k Node, i int)

Insert item at index; does not do any parent updating etc; use the Node or NodeBase method unless you know what you are doing.

func (*Slice) IsValidIndex

func (sl *Slice) IsValidIndex(idx int) error

IsValidIndex checks whether the given index is a valid index into slice, within range of 0..len-1. Returns error if not.

func (Slice) MarshalJSON

func (sl Slice) MarshalJSON() ([]byte, error)

MarshalJSON saves the length and type, name information for each object in a slice, as a separate struct-like record at the start, followed by the structs for each element in the slice -- this allows the Unmarshal to first create all the elements and then load them

func (Slice) MarshalXML

func (sl Slice) MarshalXML(e *xml.Encoder, start xml.StartElement) error

MarshalXML saves the length and type information for each object in a slice, as a separate struct-like record at the start, followed by the structs for each element in the slice -- this allows the Unmarshal to first create all the elements and then load them

func (*Slice) Move

func (sl *Slice) Move(frm, to int) error

Move element from one position to another. Returns error if either index is invalid.

func (*Slice) Swap

func (sl *Slice) Swap(i, j int) error

Swap elements between positions. Returns error if either index is invalid

func (*Slice) UnmarshalJSON

func (sl *Slice) UnmarshalJSON(b []byte) error

UnmarshalJSON parses the length and type information for each object in the slice, creates the new slice with those elements, and then loads based on the remaining bytes which represent each element

func (*Slice) UnmarshalXML

func (sl *Slice) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error

UnmarshalXML parses the length and type information for each object in the slice, creates the new slice with those elements, and then loads based on the remaining bytes which represent each element

type TypeAndName

type TypeAndName struct {
	Type *types.Type
	Name string
}

TypeAndName holds a type and a name. It is used for specifying Config objects in [Node.ConfigChildren].

Jump to

Keyboard shortcuts

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