Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EXPERIMENTAL: map/list interfaces #4

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions datamodel/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package datamodel

type Container interface {
Empty() bool
Length() int64
Clear()
Values() []Node
}
11 changes: 11 additions & 0 deletions datamodel/list.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package datamodel

type List interface {
Get(idx int64) (Node, bool)
Remove(idx int64)
Append(values ...interface{})
Insert(idx int64, values ...interface{})
Set(idx int64, value interface{})

Container
}
10 changes: 10 additions & 0 deletions datamodel/map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package datamodel

type Map interface {
Put(key string, value interface{}) bool
Get(key string) (value Node, found bool)
Remove(key string) bool
Keys() []string

Container
}
4 changes: 2 additions & 2 deletions traversal/amendAny.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ func (a *anyAmender) Prototype() datamodel.NodePrototype {

// -- Amender -->

func (a *anyAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *anyAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the base node is an amender, use it, otherwise return the base node.
if amd, castOk := a.base.(Amender); castOk {
return amd.Get(prog, path, trackProgress)
return amd.Fetch(prog, path, trackProgress)
}
return a.base, nil
}
Expand Down
4 changes: 2 additions & 2 deletions traversal/amendLink.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func (a *linkAmender) Prototype() datamodel.NodePrototype {

// -- Amender -->

func (a *linkAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *linkAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// Check the budget
if prog.Budget != nil {
if prog.Budget.LinkBudget <= 0 {
Expand All @@ -133,7 +133,7 @@ func (a *linkAmender) Get(prog *Progress, path datamodel.Path, trackProgress boo
if path.Len() == 0 {
return a.Build(), nil
}
return a.child.Get(prog, path, trackProgress)
return a.child.Fetch(prog, path, trackProgress)
}

func (a *linkAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down
52 changes: 50 additions & 2 deletions traversal/amendList.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

var (
_ datamodel.Node = &listAmender{}
_ datamodel.List = &listAmender{}
_ Amender = &listAmender{}
)

Expand Down Expand Up @@ -160,7 +161,7 @@ func (itr *listAmender_Iterator) Done() bool {

// -- Amender -->

func (a *listAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *listAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the root is requested, return the `Node` view of the amender.
if path.Len() == 0 {
return a.Build(), nil
Expand Down Expand Up @@ -188,7 +189,7 @@ func (a *listAmender) Get(prog *Progress, path datamodel.Path, trackProgress boo
if err != nil {
return nil, err
}
return childAmender.Get(prog, remainingPath, trackProgress)
return childAmender.Fetch(prog, remainingPath, trackProgress)
}

func (a *listAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down Expand Up @@ -343,3 +344,50 @@ func (a *listAmender) storeChildAmender(childIdx int64, n datamodel.Node, k data
}
return a.opts.newAmender(n, a, k, create), nil
}

// -- List -->

func NewList(base interface{}) datamodel.List {
// TODO: `base` must be of "list" type
return AmendOptions{}.newListAmender(nodeForType(base), nil, false).(*listAmender)
}

func (a *listAmender) Get(idx int64) (datamodel.Node, bool) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Remove(idx int64) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Append(values ...interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Insert(idx int64, values ...interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Set(idx int64, value interface{}) {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Empty() bool {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Clear() {
//TODO implement me
panic("implement me")
}

func (a *listAmender) Values() []datamodel.Node {
//TODO implement me
panic("implement me")
}
80 changes: 78 additions & 2 deletions traversal/amendMap.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (

var (
_ datamodel.Node = &mapAmender{}
_ datamodel.Map = &mapAmender{}
_ Amender = &mapAmender{}
)

Expand Down Expand Up @@ -208,7 +209,7 @@ func (itr *mapAmender_Iterator) Done() bool {

// -- Amender -->

func (a *mapAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
func (a *mapAmender) Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error) {
// If the root is requested, return the `Node` view of the amender.
if path.Len() == 0 {
return a.Build(), nil
Expand All @@ -228,7 +229,7 @@ func (a *mapAmender) Get(prog *Progress, path datamodel.Path, trackProgress bool
if err != nil {
return nil, err
}
return a.storeChildAmender(childSeg, childVal, childVal.Kind(), false, trackProgress).Get(prog, remainingPath, trackProgress)
return a.storeChildAmender(childSeg, childVal, childVal.Kind(), false, trackProgress).Fetch(prog, remainingPath, trackProgress)
}

func (a *mapAmender) Transform(prog *Progress, path datamodel.Path, fn TransformFn, createParents bool) (datamodel.Node, error) {
Expand Down Expand Up @@ -337,3 +338,78 @@ func (a *mapAmender) storeChildAmender(seg datamodel.PathSegment, n datamodel.No
}
return childAmender
}

// -- Map -->

func NewMap(base interface{}) datamodel.Map {
// TODO: `base` must be of "map" type
return AmendOptions{}.newMapAmender(nodeForType(base), nil, false).(*mapAmender)
}

func (a *mapAmender) Put(key string, value interface{}) bool {
if _, err := a.Transform(&Progress{}, datamodel.ParsePath("/"+key), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nodeForType(value), nil
}, false); err != nil {
return false
} else {
return true
}
}

func (a *mapAmender) Get(key string) (value datamodel.Node, found bool) {
if v, err := a.Fetch(&Progress{}, datamodel.ParsePath("/"+key), true); err != nil {
return nil, false
} else {
return nodeForType(v), true
}
}

func (a *mapAmender) Remove(key string) bool {
if _, err := a.Transform(&Progress{}, datamodel.ParsePath("/"+key), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}, false); err != nil {
return false
} else {
return true
}
}

func (a *mapAmender) Keys() []string {
keys := make([]string, a.Length())
count := 0
for itr := a.MapIterator(); !itr.Done(); {
if k, _, err := itr.Next(); err != nil {
return []string{}
} else if key, err := k.AsString(); err != nil {
return []string{}
} else {
keys[count] = key
count++
}
}
return keys
}

func (a *mapAmender) Empty() bool {
return a.Length() == 0
}

func (a *mapAmender) Clear() {
a.Transform(&Progress{}, datamodel.ParsePath("/"), func(progress Progress, node datamodel.Node) (datamodel.Node, error) {
return nil, nil
}, false)
}

func (a *mapAmender) Values() []datamodel.Node {
values := make([]datamodel.Node, a.Length())
count := 0
for itr := a.MapIterator(); !itr.Done(); {
_, v, err := itr.Next()
if err != nil {
return []datamodel.Node{}
}
values[count] = v
count++
}
return values
}
71 changes: 71 additions & 0 deletions traversal/amendUtils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package traversal

import (
"log"

"github.com/ipld/go-ipld-prime/datamodel"
"github.com/ipld/go-ipld-prime/node/basicnode"
)

func nodeForType(base interface{}) datamodel.Node {
if base == nil {
return nil
}
switch typ := base.(type) {
case Amender:
return base.(Amender).Build()
case datamodel.Node:
return base.(datamodel.Node)
case datamodel.Link:
return basicnode.NewLink(base.(datamodel.Link))
case bool:
return basicnode.NewBool(base.(bool))
case int8:
return basicnode.NewInt(int64(base.(int8)))
case int16:
return basicnode.NewInt(int64(base.(int16)))
case int32:
return basicnode.NewInt(int64(base.(int32)))
case int64:
return basicnode.NewInt(base.(int64))
case int:
return basicnode.NewInt(int64(base.(int)))
case uint8:
return basicnode.NewUint(uint64(base.(uint8)))
case uint16:
return basicnode.NewUint(uint64(base.(uint16)))
case uint32:
return basicnode.NewUint(uint64(base.(uint32)))
case uint64:
return basicnode.NewUint(base.(uint64))
case uint:
return basicnode.NewUint(uint64(base.(uint)))
case float32:
return basicnode.NewFloat(float64(base.(float32)))
case float64:
return basicnode.NewFloat(base.(float64))
case string:
return basicnode.NewString(base.(string))
case []byte: // Special handling for array of bytes
{
return basicnode.NewBytes(base.([]byte))
}
case map[string]interface{}:
{
a := AmendOptions{}.newMapAmender(nil, nil, false)
for k, v := range base.(map[string]interface{}) {
a.(datamodel.Map).Put(k, v)
}
return a.Build()
}
case []interface{}:
{
a := AmendOptions{}.newListAmender(nil, nil, false)
a.(datamodel.List).Append(base.([]interface{}))
return a.Build()
}
default:
log.Printf("invalid type: %s", typ)
panic("unreachable")
}
}
4 changes: 2 additions & 2 deletions traversal/amender.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package traversal
import "github.com/ipld/go-ipld-prime/datamodel"

type Amender interface {
// Get returns the node at the specified path. It will not create any intermediate nodes because this is just a
// Fetch returns the node at the specified path. It will not create any intermediate nodes because this is just a
// retrieval and not a modification operation.
Get(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error)
Fetch(prog *Progress, path datamodel.Path, trackProgress bool) (datamodel.Node, error)

// Transform will do an in-place transformation of the node at the specified path and return its previous value.
// If `createParents = true`, any missing parents will be created, otherwise this function will return an error.
Expand Down
2 changes: 1 addition & 1 deletion traversal/focus.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (prog Progress) Get(n datamodel.Node, p datamodel.Path) (datamodel.Node, er
// For Get calls, trackProgress=false, which avoids some allocations for state tracking that's not needed by that call.
func (prog *Progress) get(n datamodel.Node, p datamodel.Path, trackProgress bool) (datamodel.Node, error) {
prog.init()
return NewAmender(n).Get(prog, p, trackProgress)
return NewAmender(n).Fetch(prog, p, trackProgress)
}

// FocusedTransform traverses a datamodel.Node graph, reaches a single Node,
Expand Down
Loading