Commit c72f1b0d authored by Jakub Sztandera's avatar Jakub Sztandera Committed by GitHub

Merge pull request #22 from ipfs/feat/decoder-redux

rework block decoding framework
parents 4cb85ac9 7de71ad7
...@@ -2,31 +2,46 @@ package format ...@@ -2,31 +2,46 @@ package format
import ( import (
"fmt" "fmt"
"sync"
blocks "github.com/ipfs/go-block-format" blocks "github.com/ipfs/go-block-format"
) )
// DecodeBlock functions decode blocks into nodes. // DecodeBlockFunc functions decode blocks into nodes.
type DecodeBlockFunc func(block blocks.Block) (Node, error) type DecodeBlockFunc func(block blocks.Block) (Node, error)
// Map from codec types to decoder functions type BlockDecoder interface {
type BlockDecoder map[uint64]DecodeBlockFunc Register(codec uint64, decoder DecodeBlockFunc)
Decode(blocks.Block) (Node, error)
}
type safeBlockDecoder struct {
// Can be replaced with an RCU if necessary.
lock sync.RWMutex
decoders map[uint64]DecodeBlockFunc
}
// A default set of block decoders. // Register registers decoder for all blocks with the passed codec.
// //
// You SHOULD populate this map from `init` functions in packages that support // This will silently replace any existing registered block decoders.
// decoding various IPLD formats. You MUST NOT modify this map once `main` has func (d *safeBlockDecoder) Register(codec uint64, decoder DecodeBlockFunc) {
// been called. d.lock.Lock()
var DefaultBlockDecoder BlockDecoder = map[uint64]DecodeBlockFunc{} defer d.lock.Unlock()
d.decoders[codec] = decoder
}
func (b BlockDecoder) Decode(block blocks.Block) (Node, error) { func (d *safeBlockDecoder) Decode(block blocks.Block) (Node, error) {
// Short-circuit by cast if we already have a Node. // Short-circuit by cast if we already have a Node.
if node, ok := block.(Node); ok { if node, ok := block.(Node); ok {
return node, nil return node, nil
} }
ty := block.Cid().Type() ty := block.Cid().Type()
if decoder, ok := b[ty]; ok {
d.lock.RLock()
decoder, ok := d.decoders[ty]
d.lock.RUnlock()
if ok {
return decoder(block) return decoder(block)
} else { } else {
// TODO: get the *long* name for this format // TODO: get the *long* name for this format
...@@ -34,7 +49,14 @@ func (b BlockDecoder) Decode(block blocks.Block) (Node, error) { ...@@ -34,7 +49,14 @@ func (b BlockDecoder) Decode(block blocks.Block) (Node, error) {
} }
} }
// Decode the given block using the default block decoder. var DefaultBlockDecoder BlockDecoder = &safeBlockDecoder{decoders: make(map[uint64]DecodeBlockFunc)}
// Decode decodes the given block using the default BlockDecoder.
func Decode(block blocks.Block) (Node, error) { func Decode(block blocks.Block) (Node, error) {
return DefaultBlockDecoder.Decode(block) return DefaultBlockDecoder.Decode(block)
} }
// Register registers block decoders with the default BlockDecoder.
func Register(codec uint64, decoder DecodeBlockFunc) {
DefaultBlockDecoder.Register(codec, decoder)
}
...@@ -10,13 +10,13 @@ import ( ...@@ -10,13 +10,13 @@ import (
) )
func init() { func init() {
DefaultBlockDecoder[cid.Raw] = func(b blocks.Block) (Node, error) { Register(cid.Raw, func(b blocks.Block) (Node, error) {
node := &EmptyNode{} node := &EmptyNode{}
if b.RawData() != nil || !b.Cid().Equals(node.Cid()) { if b.RawData() != nil || !b.Cid().Equals(node.Cid()) {
return nil, errors.New("can only decode empty blocks") return nil, errors.New("can only decode empty blocks")
} }
return node, nil return node, nil
} })
} }
func TestDecode(t *testing.T) { func TestDecode(t *testing.T) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment