Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37e9b6d587
commit
03bfe4079e
356 changed files with 28857 additions and 0 deletions
414
tree/generic/node.go
Normal file
414
tree/generic/node.go
Normal file
|
@ -0,0 +1,414 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"code.forgejo.org/f3/gof3/v3/f3"
|
||||
"code.forgejo.org/f3/gof3/v3/id"
|
||||
"code.forgejo.org/f3/gof3/v3/kind"
|
||||
"code.forgejo.org/f3/gof3/v3/logger"
|
||||
"code.forgejo.org/f3/gof3/v3/path"
|
||||
"code.forgejo.org/f3/gof3/v3/util"
|
||||
)
|
||||
|
||||
type ChildrenSlice []NodeInterface
|
||||
|
||||
func NewChildrenSlice(len int) ChildrenSlice {
|
||||
return make([]NodeInterface, 0, len)
|
||||
}
|
||||
|
||||
func (o ChildrenSlice) Len() int {
|
||||
return len(o)
|
||||
}
|
||||
|
||||
func (o ChildrenSlice) Swap(i, j int) {
|
||||
o[i], o[j] = o[j], o[i]
|
||||
}
|
||||
|
||||
func (o ChildrenSlice) Less(i, j int) bool {
|
||||
return o[i].GetID().String() < o[j].GetID().String()
|
||||
}
|
||||
|
||||
type NodeChildren map[id.NodeID]NodeInterface
|
||||
|
||||
func NewNodeChildren() NodeChildren {
|
||||
return make(NodeChildren)
|
||||
}
|
||||
|
||||
var (
|
||||
NilNode = &Node{isNil: true}
|
||||
NilParent = NilNode
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
logger.Logger
|
||||
|
||||
tree TreeInterface
|
||||
isNil bool
|
||||
sync bool
|
||||
kind kind.Kind
|
||||
id id.NodeID
|
||||
|
||||
driver NodeDriverInterface
|
||||
self NodeInterface
|
||||
parent NodeInterface
|
||||
|
||||
children NodeChildren
|
||||
}
|
||||
|
||||
func NewElementNode() path.PathElement {
|
||||
return NewNode().(path.PathElement)
|
||||
}
|
||||
|
||||
func NewNode() NodeInterface {
|
||||
node := &Node{}
|
||||
return node.Init(node)
|
||||
}
|
||||
|
||||
func NewNodeFromID[T any](i T) NodeInterface {
|
||||
node := NewNode()
|
||||
node.SetID(id.NewNodeID(i))
|
||||
return node
|
||||
}
|
||||
|
||||
func (o *Node) Init(self NodeInterface) NodeInterface {
|
||||
o.SetTree(nil)
|
||||
o.SetIsNil(true)
|
||||
o.SetKind(kind.KindNil)
|
||||
o.SetID(id.NilID)
|
||||
o.SetSelf(self)
|
||||
o.SetParent(NilNode)
|
||||
o.children = NewNodeChildren()
|
||||
|
||||
return self
|
||||
}
|
||||
|
||||
func (o *Node) GetIsNil() bool { return o == nil || o.isNil }
|
||||
func (o *Node) SetIsNil(isNil bool) { o.isNil = isNil }
|
||||
|
||||
func (o *Node) GetIsSync() bool { return o.sync }
|
||||
func (o *Node) SetIsSync(sync bool) { o.sync = sync }
|
||||
|
||||
func (o *Node) GetSelf() NodeInterface { return o.self }
|
||||
func (o *Node) SetSelf(self NodeInterface) { o.self = self }
|
||||
|
||||
func (o *Node) GetParent() NodeInterface { return o.parent }
|
||||
func (o *Node) SetParent(parent NodeInterface) { o.parent = parent }
|
||||
|
||||
func (o *Node) GetKind() kind.Kind { return o.kind }
|
||||
func (o *Node) SetKind(kind kind.Kind) { o.kind = kind }
|
||||
|
||||
func (o *Node) GetID() id.NodeID {
|
||||
if o.id == nil {
|
||||
return id.NilID
|
||||
}
|
||||
return o.id
|
||||
}
|
||||
func (o *Node) SetID(id id.NodeID) { o.id = id }
|
||||
|
||||
func (o *Node) GetMappedID() id.NodeID {
|
||||
mappedID := o.GetDriver().GetMappedID()
|
||||
if mappedID == nil {
|
||||
mappedID = id.NilID
|
||||
}
|
||||
return mappedID
|
||||
}
|
||||
|
||||
func (o *Node) SetMappedID(mapped id.NodeID) {
|
||||
o.GetDriver().SetMappedID(mapped)
|
||||
}
|
||||
|
||||
func (o *Node) GetTree() TreeInterface { return o.tree }
|
||||
func (o *Node) SetTree(tree TreeInterface) {
|
||||
o.tree = tree
|
||||
if tree != nil {
|
||||
o.SetLogger(tree.GetLogger())
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Node) GetDriver() NodeDriverInterface { return o.driver }
|
||||
func (o *Node) SetDriver(driver NodeDriverInterface) {
|
||||
driver.SetNode(o)
|
||||
o.driver = driver
|
||||
}
|
||||
|
||||
func (o *Node) GetNodeChildren() NodeChildren {
|
||||
return o.children
|
||||
}
|
||||
|
||||
func (o *Node) GetChildren() ChildrenSlice {
|
||||
children := NewChildrenSlice(len(o.children))
|
||||
for _, child := range o.children {
|
||||
children = append(children, child)
|
||||
}
|
||||
sort.Sort(children)
|
||||
return children
|
||||
}
|
||||
|
||||
func (o *Node) SetChildren(children NodeChildren) { o.children = children }
|
||||
|
||||
func (o *Node) String() string {
|
||||
driver := o.GetDriver().String()
|
||||
if driver != "" {
|
||||
driver = "=" + driver
|
||||
}
|
||||
return o.GetID().String() + driver
|
||||
}
|
||||
|
||||
func (o *Node) Equals(ctx context.Context, other NodeInterface) bool {
|
||||
return o.GetKind() == other.GetKind() && o.GetID() == other.GetID()
|
||||
}
|
||||
|
||||
func (o *Node) GetCurrentPath() path.Path {
|
||||
var p path.Path
|
||||
if o.GetIsNil() {
|
||||
p = path.NewPath()
|
||||
} else {
|
||||
p = o.GetParent().GetCurrentPath().Append(o)
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
func (o *Node) ListPage(ctx context.Context, page int) ChildrenSlice {
|
||||
return o.GetDriver().ListPage(ctx, page)
|
||||
}
|
||||
|
||||
func (o *Node) List(ctx context.Context) ChildrenSlice {
|
||||
o.Trace("%s", o.GetKind())
|
||||
children := NewNodeChildren()
|
||||
|
||||
self := o.GetSelf()
|
||||
for page := 1; ; page++ {
|
||||
util.MaybeTerminate(ctx)
|
||||
childrenPage := self.ListPage(ctx, page)
|
||||
for _, child := range childrenPage {
|
||||
children[child.GetID()] = child
|
||||
}
|
||||
|
||||
if len(childrenPage) < o.GetTree().GetPageSize() {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
o.children = children
|
||||
return o.GetChildren()
|
||||
}
|
||||
|
||||
func (o *Node) GetChild(id id.NodeID) NodeInterface {
|
||||
child, ok := o.children[id]
|
||||
if !ok {
|
||||
return NilNode
|
||||
}
|
||||
return child
|
||||
}
|
||||
|
||||
func (o *Node) SetChild(child NodeInterface) NodeInterface {
|
||||
o.children[child.GetID()] = child
|
||||
return child
|
||||
}
|
||||
|
||||
func (o *Node) DeleteChild(id id.NodeID) NodeInterface {
|
||||
if child, ok := o.children[id]; ok {
|
||||
delete(o.children, id)
|
||||
return child
|
||||
}
|
||||
return NilNode
|
||||
}
|
||||
|
||||
func (o *Node) CreateChild(ctx context.Context) NodeInterface {
|
||||
tree := o.GetTree()
|
||||
child := tree.Factory(ctx, tree.GetChildrenKind(o.GetKind()))
|
||||
child.SetParent(o)
|
||||
return child
|
||||
}
|
||||
|
||||
func (o *Node) GetIDFromName(ctx context.Context, name string) id.NodeID {
|
||||
return o.GetDriver().GetIDFromName(ctx, name)
|
||||
}
|
||||
|
||||
func (o *Node) Get(ctx context.Context) NodeInterface {
|
||||
if o.GetDriver().Get(ctx) {
|
||||
o.SetIsSync(true)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Node) Upsert(ctx context.Context) NodeInterface {
|
||||
if o.GetID() != id.NilID {
|
||||
o.GetDriver().Patch(ctx)
|
||||
} else {
|
||||
o.SetID(o.GetDriver().Put(ctx))
|
||||
}
|
||||
if o.GetParent() != NilNode {
|
||||
o.GetParent().SetChild(o)
|
||||
}
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Node) Delete(ctx context.Context) NodeInterface {
|
||||
o.GetDriver().Delete(ctx)
|
||||
return o.GetParent().DeleteChild(o.GetID())
|
||||
}
|
||||
|
||||
func (o *Node) NewFormat() f3.Interface {
|
||||
return o.GetDriver().NewFormat()
|
||||
}
|
||||
|
||||
func (o *Node) FromFormat(f f3.Interface) NodeInterface {
|
||||
o.SetID(id.NewNodeID(f.GetID()))
|
||||
o.GetDriver().FromFormat(f)
|
||||
return o
|
||||
}
|
||||
|
||||
func (o *Node) ToFormat() f3.Interface {
|
||||
if o == nil || o.GetDriver() == nil {
|
||||
return nil
|
||||
}
|
||||
return o.GetDriver().ToFormat()
|
||||
}
|
||||
|
||||
func (o *Node) LookupMappedID(id id.NodeID) id.NodeID { return o.GetDriver().LookupMappedID(id) }
|
||||
|
||||
func (o *Node) ApplyAndGet(ctx context.Context, p path.Path, options *ApplyOptions) bool {
|
||||
applyWrapInGet := func(options *ApplyOptions) ApplyFunc {
|
||||
return func(ctx context.Context, parent, p path.Path, node NodeInterface) {
|
||||
if options.fun != nil && (p.Empty() || options.where == ApplyEachNode) {
|
||||
options.fun(ctx, parent, p, node)
|
||||
}
|
||||
if p.Empty() {
|
||||
return
|
||||
}
|
||||
|
||||
childID := p.First().(NodeInterface).GetID()
|
||||
// is it a known child?
|
||||
child := node.GetChild(childID)
|
||||
// if not, maybe it is a known child referenced by name
|
||||
if child.GetIsNil() {
|
||||
childIDFromName := node.GetIDFromName(ctx, childID.String())
|
||||
if childIDFromName != id.NilID {
|
||||
childID = childIDFromName
|
||||
child = node.GetChild(childID)
|
||||
p.First().(NodeInterface).SetID(childID)
|
||||
}
|
||||
}
|
||||
// not a known child by ID or by Name: make one
|
||||
if child.GetIsNil() {
|
||||
child = node.CreateChild(ctx)
|
||||
child.SetID(childID)
|
||||
if child.Get(ctx).GetIsSync() {
|
||||
// only set the child if the driver is able to get it, otherwise
|
||||
// it means that although the ID is known the child itself cannot be
|
||||
// obtained and is assumed to be not found
|
||||
node.SetChild(child)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return o.Apply(ctx, path.NewPath(), p, NewApplyOptions(applyWrapInGet(options)).SetWhere(ApplyEachNode))
|
||||
}
|
||||
|
||||
func (o *Node) WalkAndGet(ctx context.Context, parent path.Path, options *WalkOptions) {
|
||||
walkWrapInGet := func(fun WalkFunc) WalkFunc {
|
||||
return func(ctx context.Context, p path.Path, node NodeInterface) {
|
||||
node.Get(ctx)
|
||||
node.List(ctx)
|
||||
if fun != nil {
|
||||
fun(ctx, p, node)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
o.Walk(ctx, parent, NewWalkOptions(walkWrapInGet(options.fun)))
|
||||
}
|
||||
|
||||
func (o *Node) Walk(ctx context.Context, parent path.Path, options *WalkOptions) {
|
||||
util.MaybeTerminate(ctx)
|
||||
options.fun(ctx, parent, o.GetSelf())
|
||||
parent = parent.Append(o.GetSelf().(path.PathElement))
|
||||
for _, child := range o.GetSelf().GetChildren() {
|
||||
child.Walk(ctx, parent, options)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *Node) FindAndGet(ctx context.Context, p path.Path) NodeInterface {
|
||||
var r NodeInterface
|
||||
r = NilNode
|
||||
set := func(ctx context.Context, parent, p path.Path, node NodeInterface) {
|
||||
r = node
|
||||
}
|
||||
o.ApplyAndGet(ctx, p, NewApplyOptions(set))
|
||||
return r
|
||||
}
|
||||
|
||||
func (o *Node) MustFind(p path.Path) NodeInterface {
|
||||
found := o.Find(p)
|
||||
if found.GetIsNil() {
|
||||
panic(fmt.Errorf("%s not found", p))
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
func (o *Node) Find(p path.Path) NodeInterface {
|
||||
if p.Empty() {
|
||||
return o
|
||||
}
|
||||
|
||||
child := o.GetChild(p.First().(NodeInterface).GetID())
|
||||
if child.GetIsNil() {
|
||||
o.Info("'%s' not found", p.String())
|
||||
return NilNode
|
||||
}
|
||||
|
||||
return child.Find(p.RemoveFirst())
|
||||
}
|
||||
|
||||
func (o *Node) Apply(ctx context.Context, parentPath, p path.Path, options *ApplyOptions) bool {
|
||||
o.Trace("parent '%s', node '%s', path '%s'", parentPath.ReadableString(), o.String(), p.ReadableString())
|
||||
|
||||
util.MaybeTerminate(ctx)
|
||||
|
||||
if p.Empty() {
|
||||
options.fun(ctx, parentPath, p, o.GetSelf())
|
||||
return true
|
||||
}
|
||||
|
||||
i := p.First().(NodeInterface).GetID().String()
|
||||
|
||||
if i == "." {
|
||||
return o.Apply(ctx, parentPath, p.RemoveFirst(), options)
|
||||
}
|
||||
|
||||
if i == ".." {
|
||||
parent, parentPath := parentPath.Pop()
|
||||
return parent.(NodeInterface).Apply(ctx, parentPath, p.RemoveFirst(), options)
|
||||
}
|
||||
|
||||
if options.where == ApplyEachNode {
|
||||
options.fun(ctx, parentPath, p, o.GetSelf())
|
||||
}
|
||||
|
||||
child := o.GetChild(p.First().(NodeInterface).GetID())
|
||||
if child.GetIsNil() && options.search == ApplySearchByName {
|
||||
if childID := o.GetIDFromName(ctx, p.First().(NodeInterface).GetID().String()); childID != id.NilID {
|
||||
child = o.GetChild(childID)
|
||||
}
|
||||
}
|
||||
if child.GetIsNil() {
|
||||
return false
|
||||
}
|
||||
parentPath = parentPath.Append(o.GetSelf().(path.PathElement))
|
||||
return child.Apply(ctx, parentPath, p.RemoveFirst(), options)
|
||||
}
|
||||
|
||||
type ErrorNodeNotFound error
|
||||
|
||||
func NewError[T error](message string, args ...any) T {
|
||||
e := fmt.Errorf(message, args...)
|
||||
return e.(T)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue