Skip to content
This repository has been archived by the owner on Aug 9, 2018. It is now read-only.

Commit

Permalink
Add Reader Iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
mildred committed Feb 5, 2016
1 parent 20f5533 commit 47bf9d6
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 18 deletions.
177 changes: 177 additions & 0 deletions iterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package ipld

import (
"math/big"
)

type NodeIterator struct {
ReadItem
LastError error
nextError bool
items chan *ReadItem
feedback chan error
feedbackClosed bool
}

type ReadItem struct {
Path []interface{}
TokenType ReaderToken
Value interface{}
}

func (s *ReadItem) StringPath() []string {
return ToStringPath(s.Path)
}

func (s *ReadItem) ToInt() (res int64, ok bool) {
ok = true
defer func() {
if r := recover(); r != nil {
ok = false
}
}()
switch s.Value.(type) {
case int:
res = int64(s.Value.(int))
case int64:
res = s.Value.(int64)
case uint64:
res = int64(s.Value.(uint64))
case *big.Int:
i := s.Value.(*big.Int)
if i.BitLen() > 63 {
ok = false
} else {
res = i.Int64()
}
default:
ok = false
}
return res, ok
}

func (s *ReadItem) ToUint() (res uint64, ok bool) {
ok = true
defer func() {
if r := recover(); r != nil {
ok = false
}
}()
switch s.Value.(type) {
case int:
res = uint64(s.Value.(int))
case int64:
res = uint64(s.Value.(int64))
case uint64:
res = s.Value.(uint64)
case *big.Int:
i := s.Value.(*big.Int)
if i.BitLen() > 64 || i.Sign() < 0 {
ok = false
} else {
res = i.Uint64()
}
default:
ok = false
}
return res, ok
}

func (s *ReadItem) ToFloat() (res float64, ok bool) {
ok = true
defer func() {
if r := recover(); r != nil {
ok = false
}
}()
switch s.Value.(type) {
case int:
res = float64(s.Value.(int))
case int64:
res = float64(s.Value.(int64))
case uint64:
res = float64(s.Value.(uint64))
case float32:
res = float64(s.Value.(float32))
case float64:
res = s.Value.(float64)
case *big.Int:
i := s.Value.(*big.Int)
if i.BitLen() > 64 {
ok = false
} else if i.Sign() < 0 {
res = -float64(big.NewInt(0).Abs(i).Uint64())
} else {
res = float64(i.Uint64())
}
default:
ok = false
}
return res, ok
}

// Read from a NodeReader using a channel of ReadItem.
func Iterate(r NodeReader, res_error *error) *NodeIterator {
it := make(chan *ReadItem)
ce := make(chan error)
res := &NodeIterator{ReadItem{}, nil, true, it, ce, false}

go func() {
err := r.Read(func(path []interface{}, tokenType ReaderToken, value interface{}) error {
item := &ReadItem{path, tokenType, value}
it <- item
return <-ce
})
close(it)
if err != nil && res_error != nil {
res.LastError = err
}
}()

return res
}

func (s *NodeIterator) Iter() bool {
if !s.nextError {
s.feedback <- nil
}

item := <-s.items
if item == nil {
if !s.feedbackClosed {
close(s.feedback)
s.feedbackClosed = true
}
return false
}

s.ReadItem = *item
return true
}

func (s *NodeIterator) Abort() {
s.StopError(NodeReadAbort)
}

func (s *NodeIterator) Skip() {
s.StopError(NodeReadSkip)
}

func (s *NodeIterator) StopError(e error) {
if s.nextError {
panic("Already stopped")
}

s.feedback <- e
s.nextError = true
}

func (s *NodeIterator) Close() error {
if !s.nextError {
s.Abort()
}
for s.Iter() {
s.Abort()
}
return s.LastError
}
20 changes: 20 additions & 0 deletions links.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ipld

import (
"fmt"
mh "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-multihash"
)

const (
LinkKey = "@link"
)

// Read the hash of an IPLD link.
func ReadLinkPath(value interface{}) (mh.Multihash, error) {
svalue, has_value := value.(string)
var h mh.Multihash
if has_value {
return mh.FromB58String(svalue)
}
return h, fmt.Errorf("Could not get multihash for %#v", value)
}
20 changes: 20 additions & 0 deletions path.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
package ipld

import (
"fmt"
"strings"
)

// Convert a []interface{} path to a []string path
// This should only convert array indices to strings, and such are not ambiguous
// because array indices and object keys cannot be mixed for the same prefix.
func ToStringPath(path []interface{}) []string {
res := make([]string, len(path))
for _, e := range path {
if str, ok := e.(string); ok {
res = append(res, str)
} else if i, ok := e.(int); ok {
res = append(res, fmt.Sprintf("%d", i))
} else if i, ok := e.(uint64); ok {
res = append(res, fmt.Sprintf("%d", i))
} else {
res = append(res, fmt.Sprintf("%v", e))
}
}
return res
}

// Escape path component. The special characters ("@" and "\") are escaped to
// allow mixing the path component with directives (starting with "@") in IPLD
// data structure.
Expand Down
18 changes: 0 additions & 18 deletions reader_at.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,10 @@
package ipld

import (
"fmt"
"reflect"
"strings"
)

// Convert a []interface{} path to a []string path
// This should only convert array indices to strings, and such are not ambiguous
// because array indices and object keys cannot be mixed for the same prefix.
func ToStringPath(anyPath []interface{}) []string {
var res []string
for _, e := range anyPath {
if str, ok := e.(string); ok {
res = append(res, str)
} else if i, ok := e.(int); ok {
res = append(res, fmt.Sprintf("%d", i))
} else {
res = append(res, fmt.Sprintf("%v", e))
}
}
return res
}

// A NodeReader that only read elements from a path prefix
type NodeReaderAt struct {
parent NodeReader
Expand Down

0 comments on commit 47bf9d6

Please sign in to comment.