github.com/goki/ki@v1.1.17/ki/ki.go (about) 1 // Copyright (c) 2018, The GoKi Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ki 6 7 import ( 8 "io" 9 "log" 10 "reflect" 11 12 "github.com/goki/ki/kit" 13 ) 14 15 // The Ki interface provides the core functionality for a GoKi tree. 16 // Each Ki is a node in the tree and can have child nodes, and no cycles 17 // are allowed (i.e., each node can only appear once in the tree). 18 // All the usual methods are included for accessing and managing Children, 19 // and efficiently traversing the tree and calling functions on the nodes. 20 // In addition, Ki nodes can have Fields that are also Ki nodes that 21 // are included in all the automatic tree traversal methods -- they are 22 // effectively named fixed children that are automatically present. 23 // 24 // In general, the names of the children of a given node should all be unique. 25 // The following functions defined in ki package can be used: 26 // UniqueNameCheck(node) to check for unique names on node if uncertain. 27 // UniqueNameCheckAll(node) to check entire tree under given node. 28 // UniquifyNames(node) to add a suffix to name to ensure uniqueness. 29 // UniquifyNamesAll(node) to to uniquify all names in entire tree. 30 // 31 // Use function MoveChild to move a node between trees or within a tree -- 32 // otherwise nodes are typically created and deleted but not moved. 33 // 34 // The Ki interface is designed to support virtual method calling in Go 35 // and is only intended to be implemented once, by the ki.Node type 36 // (as opposed to interfaces that are used for hiding multiple different 37 // implementations of a common concept). Thus, all of the fields in ki.Node 38 // are exported (have captital names), to be accessed directly in types 39 // that embed and extend the ki.Node. The Ki interface has the "formal" name 40 // (e.g., Children) while the Node has the "nickname" (e.g., Kids). See the 41 // Naming Conventions on the GoKi Wiki for more details. 42 // 43 // Each Node stores the Ki interface version of itself, as This() / Ths 44 // which enables full virtual function calling by calling the method 45 // on that interface instead of directly on the receiver Node itself. 46 // This requires proper initialization via Init method of the Ki interface. 47 // 48 // Ki nodes also support the following core functionality: 49 // - UpdateStart() / UpdateEnd() to wrap around tree updating code, which then 50 // automatically triggers update signals at the highest level of the 51 // affected tree, resulting in efficient updating logic for arbitrary 52 // nested tree modifications. 53 // - Signal framework for sending messages such as the Update signals, used 54 // extensively in the GoGi GUI framework for sending event messages etc. 55 // - ConfigChildren system for minimally updating children to fit a given 56 // Name & Type template. 57 // - Automatic JSON I/O of entire tree including type information. 58 type Ki interface { 59 // InitName initializes this node to given actual object as a Ki interface 60 // and sets its name. The names should be unique among children of a node. 61 // This is needed for root nodes -- automatically done for other nodes 62 // when they are added to the Ki tree. 63 // Even though this is a method and gets the method receiver, it needs 64 // an "external" version of itself passed as the first arg, from which 65 // the proper Ki interface pointer will be obtained. This is the only 66 // way to get virtual functional calling to work within the Go language. 67 InitName(this Ki, name string) 68 69 // This returns the Ki interface that guarantees access to the Ki 70 // interface in a way that always reveals the underlying type 71 // (e.g., in reflect calls). Returns nil if node is nil, 72 // has been destroyed, or is improperly constructed. 73 This() Ki 74 75 // AsNode returns the *ki.Node base type for this node. 76 AsNode() *Node 77 78 // Embed returns the embedded struct of given type from this node (or nil 79 // if it does not embed that type, or the type is not a Ki type -- see 80 // kit.Embed for a generic interface{} version. 81 Embed(t reflect.Type) Ki 82 83 // BaseIface returns the base interface type for all elements 84 // within this tree. Use reflect.TypeOf((*<interface_type>)(nil)).Elem(). 85 // Used e.g., for determining what types of children 86 // can be created (see kit.EmbedImplements for test method) 87 BaseIface() reflect.Type 88 89 // Name returns the user-defined name of the object (Node.Nm), 90 // for finding elements, generating paths, IO, etc. 91 Name() string 92 93 // SetName sets the name of this node. 94 // Names should generally be unique across children of each node. 95 // See Unique* functions to check / fix. 96 // If node requires non-unique names, add a separate Label field. 97 // Does NOT wrap in UpdateStart / End. 98 SetName(name string) 99 100 ////////////////////////////////////////////////////////////////////////// 101 // Parents 102 103 // Parent returns the parent of this Ki (Node.Par) -- Ki has strict 104 // one-parent, no-cycles structure -- see SetParent. 105 Parent() Ki 106 107 // IndexInParent returns our index within our parent object -- caches the 108 // last value and uses that for an optimized search so subsequent calls 109 // are typically quite fast. Returns false if we don't have a parent. 110 IndexInParent() (int, bool) 111 112 // ParentLevel finds a given potential parent node recursively up the 113 // hierarchy, returning level above current node that the parent was 114 // found, and -1 if not found. 115 ParentLevel(par Ki) int 116 117 // ParentByName finds first parent recursively up hierarchy that matches 118 // given name. Returns nil if not found. 119 ParentByName(name string) Ki 120 121 // ParentByNameTry finds first parent recursively up hierarchy that matches 122 // given name -- Try version returns error on failure. 123 ParentByNameTry(name string) (Ki, error) 124 125 // ParentByType finds parent recursively up hierarchy, by type, and 126 // returns nil if not found. If embeds is true, then it looks for any 127 // type that embeds the given type at any level of anonymous embedding. 128 ParentByType(t reflect.Type, embeds bool) Ki 129 130 // ParentByTypeTry finds parent recursively up hierarchy, by type, and 131 // returns error if not found. If embeds is true, then it looks for any 132 // type that embeds the given type at any level of anonymous embedding. 133 ParentByTypeTry(t reflect.Type, embeds bool) (Ki, error) 134 135 ////////////////////////////////////////////////////////////////////////// 136 // Children 137 138 // HasChildren tests whether this node has children (i.e., non-terminal). 139 HasChildren() bool 140 141 // NumChildren returns the number of children 142 NumChildren() int 143 144 // Children returns a pointer to the slice of children (Node.Kids) -- use 145 // methods on ki.Slice for further ways to access (ByName, ByType, etc). 146 // Slice can be modified, deleted directly (e.g., sort, reorder) but Add 147 // method on parent node should be used to ensure proper init. 148 Children() *Slice 149 150 // Child returns the child at given index -- will panic if index is invalid. 151 // See methods on ki.Slice for more ways to access. 152 Child(idx int) Ki 153 154 // ChildTry returns the child at given index -- Try version returns 155 // error if index is invalid. 156 // See methods on ki.Slice for more ways to access. 157 ChildTry(idx int) (Ki, error) 158 159 // ChildByName returns first element that has given name, nil if not found. 160 // startIdx arg allows for optimized bidirectional find if you have 161 // an idea where it might be -- can be key speedup for large lists -- pass 162 // [ki.StartMiddle] to start in the middle (good default). 163 ChildByName(name string, startIdx int) Ki 164 165 // ChildByNameTry returns first element that has given name -- Try version 166 // returns error message if not found. 167 // startIdx arg allows for optimized bidirectional find if you have 168 // an idea where it might be -- can be key speedup for large lists -- pass 169 // [ki.StartMiddle] to start in the middle (good default). 170 ChildByNameTry(name string, startIdx int) (Ki, error) 171 172 // ChildByType returns first element that has given type, nil if not found. 173 // If embeds is true, then it looks for any type that embeds the given type 174 // at any level of anonymous embedding. 175 // startIdx arg allows for optimized bidirectional find if you have 176 // an idea where it might be -- can be key speedup for large lists -- pass 177 // [ki.StartMiddle] to start in the middle (good default). 178 ChildByType(t reflect.Type, embeds bool, startIdx int) Ki 179 180 // ChildByTypeTry returns first element that has given name -- Try version 181 // returns error message if not found. 182 // If embeds is true, then it looks for any type that embeds the given type 183 // at any level of anonymous embedding. 184 // startIdx arg allows for optimized bidirectional find if you have 185 // an idea where it might be -- can be key speedup for large lists -- pass 186 // [ki.StartMiddle] to start in the middle (good default). 187 ChildByTypeTry(t reflect.Type, embeds bool, startIdx int) (Ki, error) 188 189 ////////////////////////////////////////////////////////////////////////// 190 // Paths 191 192 // Path returns path to this node from the tree root, using node Names 193 // separated by / and fields by . 194 // Node names escape any existing / and . characters to \\ and \, 195 // Path is only valid when child names are unique (see Unique* functions) 196 Path() string 197 198 // PathFrom returns path to this node from given parent node, using 199 // node Names separated by / and fields by . 200 // Node names escape any existing / and . characters to \\ and \, 201 // Path is only valid when child names are unique (see Unique* functions) 202 PathFrom(par Ki) string 203 204 // FindPath returns Ki object at given path, starting from this node 205 // (e.g., the root). If this node is not the root, then the path 206 // to this node is subtracted from the start of the path if present there. 207 // FindPath only works correctly when names are unique. 208 // Path has node Names separated by / and fields by . 209 // Node names escape any existing / and . characters to \\ and \, 210 // There is also support for [idx] index-based access for any given path 211 // element, for cases when indexes are more useful than names. 212 // Returns nil if not found. 213 FindPath(path string) Ki 214 215 // FindPathTry returns Ki object at given path, starting from this node 216 // (e.g., the root). If this node is not the root, then the path 217 // to this node is subtracted from the start of the path if present there. 218 // FindPath only works correctly when names are unique. 219 // Path has node Names separated by / and fields by . 220 // Node names escape any existing / and . characters to \\ and \, 221 // There is also support for [idx] index-based access for any given path 222 // element, for cases when indexes are more useful than names. 223 // Returns error if not found. 224 FindPathTry(path string) (Ki, error) 225 226 ////////////////////////////////////////////////////////////////////////// 227 // Adding, Inserting Children 228 229 // AddChild adds given child at end of children list. 230 // The kid node is assumed to not be on another tree (see MoveToParent) 231 // and the existing name should be unique among children. 232 // No UpdateStart / End wrapping is done: do that externally as needed. 233 // Can also call SetFlag(ki.ChildAdded) if notification is needed. 234 AddChild(kid Ki) error 235 236 // AddNewChild creates a new child of given type and 237 // add at end of children list. 238 // The name should be unique among children. 239 // No UpdateStart / End wrapping is done: do that externally as needed. 240 // Can also call SetFlag(ki.ChildAdded) if notification is needed. 241 AddNewChild(typ reflect.Type, name string) Ki 242 243 // SetChild sets child at given index to be the given item -- if name is 244 // non-empty then it sets the name of the child as well -- just calls Init 245 // (or InitName) on the child, and SetParent. 246 // Names should be unique among children. 247 // No UpdateStart / End wrapping is done: do that externally as needed. 248 // Can also call SetFlag(ki.ChildAdded) if notification is needed. 249 SetChild(kid Ki, idx int, name string) error 250 251 // InsertChild adds given child at position in children list. 252 // The kid node is assumed to not be on another tree (see MoveToParent) 253 // and the existing name should be unique among children. 254 // No UpdateStart / End wrapping is done: do that externally as needed. 255 // Can also call SetFlag(ki.ChildAdded) if notification is needed. 256 InsertChild(kid Ki, at int) error 257 258 // InsertNewChild creates a new child of given type and 259 // add at position in children list. 260 // The name should be unique among children. 261 // No UpdateStart / End wrapping is done: do that externally as needed. 262 // Can also call SetFlag(ki.ChildAdded) if notification is needed. 263 InsertNewChild(typ reflect.Type, at int, name string) Ki 264 265 // SetNChildren ensures that there are exactly n children, deleting any 266 // extra, and creating any new ones, using AddNewChild with given type and 267 // naming according to nameStubX where X is the index of the child. 268 // 269 // IMPORTANT: returns whether any modifications were made (mods) AND if 270 // that is true, the result from the corresponding UpdateStart call -- 271 // UpdateEnd is NOT called, allowing for further subsequent updates before 272 // you call UpdateEnd(updt) 273 // 274 // Note that this does not ensure existing children are of given type, or 275 // change their names, or call UniquifyNames -- use ConfigChildren for 276 // those cases -- this function is for simpler cases where a parent uses 277 // this function consistently to manage children all of the same type. 278 SetNChildren(n int, typ reflect.Type, nameStub string) (mods, updt bool) 279 280 // ConfigChildren configures children according to given list of 281 // type-and-name's -- attempts to have minimal impact relative to existing 282 // items that fit the type and name constraints (they are moved into the 283 // corresponding positions), and any extra children are removed, and new 284 // ones added, to match the specified config. 285 // It is important that names are unique! 286 // 287 // IMPORTANT: returns whether any modifications were made (mods) AND if 288 // that is true, the result from the corresponding UpdateStart call -- 289 // UpdateEnd is NOT called, allowing for further subsequent updates before 290 // you call UpdateEnd(updt). 291 ConfigChildren(config kit.TypeAndNameList) (mods, updt bool) 292 293 ////////////////////////////////////////////////////////////////////////// 294 // Deleting Children 295 296 // DeleteChildAtIndex deletes child at given index (returns error for 297 // invalid index). 298 // Wraps delete in UpdateStart / End and sets ChildDeleted flag. 299 DeleteChildAtIndex(idx int, destroy bool) error 300 301 // DeleteChild deletes child node, returning error if not found in 302 // Children. 303 // Wraps delete in UpdateStart / End and sets ChildDeleted flag. 304 DeleteChild(child Ki, destroy bool) error 305 306 // DeleteChildByName deletes child node by name -- returns child, error 307 // if not found. 308 // Wraps delete in UpdateStart / End and sets ChildDeleted flag. 309 DeleteChildByName(name string, destroy bool) (Ki, error) 310 311 // DeleteChildren deletes all children nodes -- destroy will add removed 312 // children to deleted list, to be destroyed later -- otherwise children 313 // remain intact but parent is nil -- could be inserted elsewhere, but you 314 // better have kept a slice of them before calling this. 315 DeleteChildren(destroy bool) 316 317 // Delete deletes this node from its parent children list -- destroy will 318 // add removed child to deleted list, to be destroyed later -- otherwise 319 // child remains intact but parent is nil -- could be inserted elsewhere. 320 Delete(destroy bool) 321 322 // Destroy calls DisconnectAll to cut all signal connections, 323 // and remove all children and their childrens-children, etc. 324 Destroy() 325 326 ////////////////////////////////////////////////////////////////////////// 327 // Flags 328 329 // Flag returns an atomically safe copy of the bit flags for this node -- 330 // can use bitflag package to check lags. 331 // See Flags type for standard values used in Ki Node -- 332 // can be extended from FlagsN up to 64 bit capacity. 333 // Note that we must always use atomic access as *some* things need to be atomic, 334 // and with bits, that means that *all* access needs to be atomic, 335 // as you cannot atomically update just a single bit. 336 Flags() int64 337 338 // HasFlag checks if flag is set 339 // using atomic, safe for concurrent access 340 HasFlag(flag int) bool 341 342 // SetFlag sets the given flag(s) 343 // using atomic, safe for concurrent access 344 SetFlag(flag ...int) 345 346 // SetFlagState sets the given flag(s) to given state 347 // using atomic, safe for concurrent access 348 SetFlagState(on bool, flag ...int) 349 350 // SetFlagMask sets the given flags as a mask 351 // using atomic, safe for concurrent access 352 SetFlagMask(mask int64) 353 354 // ClearFlag clears the given flag(s) 355 // using atomic, safe for concurrent access 356 ClearFlag(flag ...int) 357 358 // ClearFlagMask clears the given flags as a bitmask 359 // using atomic, safe for concurrent access 360 ClearFlagMask(mask int64) 361 362 // IsField checks if this is a field on a parent struct (via IsField 363 // Flag), as opposed to a child in Children -- Ki nodes can be added as 364 // fields to structs and they are automatically parented and named with 365 // field name during Init function -- essentially they function as fixed 366 // children of the parent struct, and are automatically included in 367 // FuncDown* traversals, etc -- see also FunFields. 368 IsField() bool 369 370 // IsUpdating checks if node is currently updating. 371 IsUpdating() bool 372 373 // OnlySelfUpdate checks if this node only applies UpdateStart / End logic 374 // to itself, not its children (which is the default) (via Flag of same 375 // name) -- useful for a parent node that has a different function than 376 // its children. 377 OnlySelfUpdate() bool 378 379 // SetChildAdded sets the ChildAdded flag -- set when notification is needed 380 // for Add, Insert methods 381 SetChildAdded() 382 383 // SetValUpdated sets the ValUpdated flag -- set when notification is needed 384 // for modifying a value (field, prop, etc) 385 SetValUpdated() 386 387 // IsDeleted checks if this node has just been deleted (within last update 388 // cycle), indicated by the NodeDeleted flag which is set when the node is 389 // deleted, and is cleared at next UpdateStart call. 390 IsDeleted() bool 391 392 // IsDestroyed checks if this node has been destroyed -- the NodeDestroyed 393 // flag is set at start of Destroy function -- the Signal Emit process 394 // checks for destroyed receiver nodes and removes connections to them 395 // automatically -- other places where pointers to potentially destroyed 396 // nodes may linger should also check this flag and reset those pointers. 397 IsDestroyed() bool 398 399 ////////////////////////////////////////////////////////////////////////// 400 // Property interface with inheritance -- nodes can inherit props from parents 401 402 // Properties (Node.Props) tell the GoGi GUI or other frameworks operating 403 // on Trees about special features of each node -- functions below support 404 // inheritance up Tree -- see kit convert.go for robust convenience 405 // methods for converting interface{} values to standard types. 406 Properties() *Props 407 408 // SetProp sets given property key to value val -- initializes property 409 // map if nil. 410 SetProp(key string, val any) 411 412 // Prop returns property value for key that is known to exist. 413 // Returns nil if it actually doesn't -- this version allows 414 // direct conversion of return. See PropTry for version with 415 // error message if uncertain if property exists. 416 Prop(key string) any 417 418 // PropTry returns property value for key. Returns error message 419 // if property with that key does not exist. 420 PropTry(key string) (any, error) 421 422 // PropInherit gets property value from key with options for inheriting 423 // property from parents and / or type-level properties. If inherit, then 424 // checks all parents. If typ then checks property on type as well 425 // (registered via KiT type registry). Returns false if not set anywhere. 426 PropInherit(key string, inherit, typ bool) (any, bool) 427 428 // DeleteProp deletes property key on this node. 429 DeleteProp(key string) 430 431 // PropTag returns the name to look for in type properties, for types 432 // that are valid options for values that can be set in Props. For example 433 // in GoGi, it is "style-props" which is then set for all types that can 434 // be used in a style (colors, enum options, etc) 435 PropTag() string 436 437 ////////////////////////////////////////////////////////////////////////// 438 // Tree walking and Paths 439 // note: always put function args last -- looks better for inline functions 440 441 // FuncFields calls function on all Ki fields within this node. 442 FuncFields(level int, data any, fun Func) 443 444 // FuncUp calls function on given node and all the way up to its parents, 445 // and so on -- sequentially all in current go routine (generally 446 // necessary for going up, which is typically quite fast anyway) -- level 447 // is incremented after each step (starts at 0, goes up), and passed to 448 // function -- returns false if fun aborts with false, else true. 449 FuncUp(level int, data any, fun Func) bool 450 451 // FuncUpParent calls function on parent of node and all the way up to its 452 // parents, and so on -- sequentially all in current go routine (generally 453 // necessary for going up, which is typically quite fast anyway) -- level 454 // is incremented after each step (starts at 0, goes up), and passed to 455 // function -- returns false if fun aborts with false, else true. 456 FuncUpParent(level int, data any, fun Func) bool 457 458 // FuncDownMeFirst calls function on this node (MeFirst) and then iterates 459 // in a depth-first manner over all the children, including Ki Node fields, 460 // which are processed first before children. 461 // This uses node state information to manage the traversal and is very fast, 462 // but can only be called by one thread at a time -- use a Mutex if there is 463 // a chance of multiple threads running at the same time. 464 // Function calls are sequential all in current go routine. 465 // The level var tracks overall depth in the tree. 466 // If fun returns false then any further traversal of that branch of the tree is 467 // aborted, but other branches continue -- i.e., if fun on current node 468 // returns false, children are not processed further. 469 FuncDownMeFirst(level int, data any, fun Func) 470 471 // FuncDownMeLast iterates in a depth-first manner over the children, calling 472 // doChildTestFunc on each node to test if processing should proceed (if it returns 473 // false then that branch of the tree is not further processed), and then 474 // calls given fun function after all of a node's children (including fields) 475 // have been iterated over ("Me Last"). 476 // This uses node state information to manage the traversal and is very fast, 477 // but can only be called by one thread at a time -- use a Mutex if there is 478 // a chance of multiple threads running at the same time. 479 // Function calls are sequential all in current go routine. 480 // The level var tracks overall depth in the tree. 481 FuncDownMeLast(level int, data any, doChildTestFunc Func, fun Func) 482 483 // FuncDownBreadthFirst calls function on all children in breadth-first order 484 // using the standard queue strategy. This depends on and updates the 485 // Depth parameter of the node. If fun returns false then any further 486 // traversal of that branch of the tree is aborted, but other branches continue. 487 FuncDownBreadthFirst(level int, data any, fun Func) 488 489 ////////////////////////////////////////////////////////////////////////// 490 // State update signaling -- automatically consolidates all changes across 491 // levels so there is only one update at end (optionally per node or only 492 // at highest level) 493 // All modification starts with UpdateStart() and ends with UpdateEnd() 494 495 // NodeSignal returns the main signal for this node that is used for 496 // update, child signals. 497 NodeSignal() *Signal 498 499 // UpdateStart should be called when starting to modify the tree (state or 500 // structure) -- returns whether this node was first to set the Updating 501 // flag (if so, all children have their Updating flag set -- pass the 502 // result to UpdateEnd -- automatically determines the highest level 503 // updated, within the normal top-down updating sequence -- can be called 504 // multiple times at multiple levels -- it is essential to ensure that all 505 // such Start's have an End! Usage: 506 // 507 // updt := n.UpdateStart() 508 // ... code 509 // n.UpdateEnd(updt) 510 // or 511 // updt := n.UpdateStart() 512 // defer n.UpdateEnd(updt) 513 // ... code 514 UpdateStart() bool 515 516 // UpdateEnd should be called when done updating after an UpdateStart, and 517 // passed the result of the UpdateStart call -- if this is true, the 518 // NodeSignalUpdated signal will be emitted and the Updating flag will be 519 // cleared, and DestroyDeleted called -- otherwise it is a no-op. 520 UpdateEnd(updt bool) 521 522 // UpdateEndNoSig is just like UpdateEnd except it does not emit a 523 // NodeSignalUpdated signal -- use this for situations where updating is 524 // already known to be in progress and the signal would be redundant. 525 UpdateEndNoSig(updt bool) 526 527 // UpdateSig just emits a NodeSignalUpdated if the Updating flag is not 528 // set -- use this to trigger an update of a given node when there aren't 529 // any structural changes and you don't need to prevent any lower-level 530 // updates -- much more efficient than a pair of UpdateStart / 531 // UpdateEnd's. Returns true if an update signal was sent. 532 UpdateSig() bool 533 534 // Disconnect disconnects this node, by calling DisconnectAll() on 535 // any Signal fields. Any Node that adds a Signal must define an 536 // updated version of this method that calls its embedded parent's 537 // version and then calls DisconnectAll() on its Signal fields. 538 Disconnect() 539 540 // DisconnectAll disconnects all the way from me down the tree. 541 DisconnectAll() 542 543 ////////////////////////////////////////////////////////////////////////// 544 // Field Value setting with notification 545 546 // SetField sets given field name to given value, using very robust 547 // conversion routines to e.g., convert from strings to numbers, and 548 // vice-versa, automatically. Returns error if not successfully set. 549 // wrapped in UpdateStart / End and sets the ValUpdated flag. 550 SetField(field string, val any) error 551 552 ////////////////////////////////////////////////////////////////////////// 553 // Deep Copy of Trees 554 555 // CopyFrom another Ki node. It is essential that source has Unique names! 556 // The Ki copy function recreates the entire tree in the copy, duplicating 557 // children etc, copying Props too. It is very efficient by 558 // using the ConfigChildren method which attempts to preserve any existing 559 // nodes in the destination if they have the same name and type -- so a 560 // copy from a source to a target that only differ minimally will be 561 // minimally destructive. Only copies to same types are supported. 562 // Signal connections are NOT copied. No other Ki pointers are copied, 563 // and the field tag copy:"-" can be added for any other fields that 564 // should not be copied (unexported, lower-case fields are not copyable). 565 CopyFrom(frm Ki) error 566 567 // Clone creates and returns a deep copy of the tree from this node down. 568 // Any pointers within the cloned tree will correctly point within the new 569 // cloned tree (see Copy info). 570 Clone() Ki 571 572 // CopyFieldsFrom is the base-level copy method that any copy-intensive 573 // nodes should implement directly to explicitly copy relevant fields 574 // that should be copied, avoiding any internal pointers etc. 575 // This is the performance bottleneck in copying -- the Node version 576 // uses generic GenCopyFieldsFrom method using reflection etc 577 // which is very slow. It can be ~10x faster overall to use custom 578 // method that explicitly copies each field. When doing so, you 579 // must explicitly call the CopyFieldsFrom method on any embedded 580 // Ki types that you inherit from, and, critically, NONE of those 581 // can rely on the generic Node-level version. Furthermore, if the 582 // actual end type itself does not define a custom version of this method 583 // then the generic one will be called for everything. 584 CopyFieldsFrom(frm any) 585 586 ////////////////////////////////////////////////////////////////////////// 587 // IO: for JSON and XML formats -- see also Slice 588 // see https://github.com/goki/ki/wiki/Naming for IO naming conventions 589 590 // WriteJSON writes the tree to an io.Writer, using MarshalJSON -- also 591 // saves a critical starting record that allows file to be loaded de-novo 592 // and recreate the proper root type for the tree. 593 WriteJSON(writer io.Writer, indent bool) error 594 595 // SaveJSON saves the tree to a JSON-encoded file, using WriteJSON. 596 SaveJSON(filename string) error 597 598 // ReadJSON reads and unmarshals tree starting at this node, from a 599 // JSON-encoded byte stream via io.Reader. First element in the stream 600 // must be of same type as this node -- see ReadNewJSON function to 601 // construct a new tree. Uses ConfigureChildren to minimize changes from 602 // current tree relative to loading one -- wraps UnmarshalJSON and calls 603 // UnmarshalPost to recover pointers from paths. 604 ReadJSON(reader io.Reader) error 605 606 // OpenJSON opens file over this tree from a JSON-encoded file -- see 607 // ReadJSON for details, and OpenNewJSON for opening an entirely new tree. 608 OpenJSON(filename string) error 609 610 // WriteXML writes the tree to an XML-encoded byte string over io.Writer 611 // using MarshalXML. 612 WriteXML(writer io.Writer, indent bool) error 613 614 // ReadXML reads the tree from an XML-encoded byte string over io.Reader, calls 615 // UnmarshalPost to recover pointers from paths. 616 ReadXML(reader io.Reader) error 617 618 ////////////////////////////////////////////////////////////////////////// 619 // Init events 620 621 // OnInit is called when the node is 622 // initialized (ie: through InitName). 623 // It is called before the node is added to the tree, 624 // so it will not have any parents or siblings. 625 // It will be called only once in the lifetime of the node. 626 // It does nothing by default, but it can be implemented 627 // by higher-level types that want to do something. 628 OnInit() 629 630 // OnAdd is called when the node is added to a parent. 631 // It will be called only once in the lifetime of the node, 632 // unless the node is moved. It will not be called on root 633 // nodes, as they are never added to a parent. 634 // It does nothing by default, but it can be implemented 635 // by higher-level types that want to do something. 636 OnAdd() 637 638 // OnChildAdded is called when a node is added to 639 // this node or any of its children. When a node is added to 640 // a tree, it calls [OnAdd] and then this function on each of its parents, 641 // going in order from the closest parent to the furthest parent. 642 // This function does nothing by default, but it can be 643 // implemented by higher-level types that want to do something. 644 OnChildAdded(child Ki) 645 } 646 647 // see node.go for struct implementing this interface 648 649 // IMPORTANT: all types should initialize entry in package kit Types Registry 650 651 // var KiT_TypeName = kit.Types.AddType(&TypeName{}) 652 653 // Func is a function to call on ki objects walking the tree -- return Break 654 // = false means don't continue processing this branch of the tree, but other 655 // branches can continue. return Continue = true continues down the tree. 656 type Func func(k Ki, level int, data any) bool 657 658 // KiType is a Ki reflect.Type, suitable for checking for Type.Implements. 659 var KiType = reflect.TypeOf((*Ki)(nil)).Elem() 660 661 // IsKi returns true if the given type implements the Ki interface at any 662 // level of embedded structure. 663 func IsKi(typ reflect.Type) bool { 664 if typ == nil { 665 return false 666 } 667 return kit.EmbedImplements(typ, KiType) 668 } 669 670 // NewOfType makes a new Ki struct of given type -- must be a Ki type -- will 671 // return nil if not. 672 func NewOfType(typ reflect.Type) Ki { 673 nkid := reflect.New(typ).Interface() 674 kid, ok := nkid.(Ki) 675 if !ok { 676 log.Printf("ki.NewOfType: type %v cannot be converted into a Ki interface type\n", typ.String()) 677 return nil 678 } 679 return kid 680 } 681 682 // Type returns the underlying struct type of given node 683 func Type(k Ki) reflect.Type { 684 return reflect.TypeOf(k.This()).Elem() 685 } 686 687 // TypeEmbeds tests whether this node is of the given type, or it embeds 688 // that type at any level of anonymous embedding -- use Embed to get the 689 // embedded struct of that type from this node. 690 func TypeEmbeds(k Ki, t reflect.Type) bool { 691 return kit.TypeEmbeds(Type(k), t) 692 }