Add router
This commit is contained in:
parent
aefebf278a
commit
f6e1d2bacc
@ -105,11 +105,14 @@ PREV <selector> <display>
|
|||||||
GOTO <selector> <display> <symbol>
|
GOTO <selector> <display> <symbol>
|
||||||
EXIT <selector> <display>
|
EXIT <selector> <display>
|
||||||
COND <selector> <display> <symbol> <[!]state>
|
COND <selector> <display> <symbol> <[!]state>
|
||||||
|
VAL <symbol>
|
||||||
|
|
||||||
kept in session as a router object:
|
kept in session as a router object:
|
||||||
|
|
||||||
SELECTORHASH|SYMBOLHASH
|
SELECTORHASH|SYMBOLHASH
|
||||||
|
|
||||||
|
Selectorhash 0x0 is VAL
|
||||||
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
80
go/router/router.go
Normal file
80
go/router/router.go
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Router struct {
|
||||||
|
selectors []string
|
||||||
|
symbols map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRouter() Router {
|
||||||
|
return Router{
|
||||||
|
symbols: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func(r *Router) Add(selector string, symbol string) error {
|
||||||
|
if r.symbols[selector] != "" {
|
||||||
|
return fmt.Errorf("selector %v already set to symbol %v", selector, symbol)
|
||||||
|
}
|
||||||
|
l := len(selector)
|
||||||
|
if (l > 255) {
|
||||||
|
return fmt.Errorf("selector too long (is %v, max 255)", l)
|
||||||
|
}
|
||||||
|
l = len(symbol)
|
||||||
|
if (l > 255) {
|
||||||
|
return fmt.Errorf("symbol too long (is %v, max 255)", l)
|
||||||
|
}
|
||||||
|
r.selectors = append(r.selectors, selector)
|
||||||
|
r.symbols[selector] = symbol
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func(r *Router) Next() []byte {
|
||||||
|
if len(r.selectors) == 0 {
|
||||||
|
return []byte{}
|
||||||
|
}
|
||||||
|
k := r.selectors[0]
|
||||||
|
r.selectors = r.selectors[1:]
|
||||||
|
v := r.symbols[k]
|
||||||
|
if len(r.selectors) == 0 {
|
||||||
|
r.symbols = nil
|
||||||
|
} else {
|
||||||
|
delete(r.symbols, k)
|
||||||
|
}
|
||||||
|
lk := len(k)
|
||||||
|
lv := len(v)
|
||||||
|
b := []byte{uint8(lk)}
|
||||||
|
b = append(b, k...)
|
||||||
|
b = append(b, uint8(lv))
|
||||||
|
b = append(b, v...)
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func(r *Router) ToBytes() []byte {
|
||||||
|
b := []byte{}
|
||||||
|
for true {
|
||||||
|
v := r.Next()
|
||||||
|
if len(v) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
b = append(b, v...)
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
func FromBytes(b []byte) Router {
|
||||||
|
rb := NewRouter()
|
||||||
|
for len(b) > 0 {
|
||||||
|
l := b[0]
|
||||||
|
k := b[1:1+l]
|
||||||
|
b = b[1+l:]
|
||||||
|
l = b[0]
|
||||||
|
v := b[1:1+l]
|
||||||
|
b = b[1+l:]
|
||||||
|
rb.Add(string(k), string(v))
|
||||||
|
}
|
||||||
|
return rb
|
||||||
|
}
|
89
go/router/router_test.go
Normal file
89
go/router/router_test.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
package router
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRouter(t *testing.T) {
|
||||||
|
r := NewRouter()
|
||||||
|
err := r.Add("foo", "bar")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = r.Add("baz", "barbarbar")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = r.Add("foo", "xyzzy")
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("expected error for duplicate key foo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRouterOut(t *testing.T) {
|
||||||
|
rt := NewRouter()
|
||||||
|
err := rt.Add("foo", "inky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = rt.Add("barbar", "pinky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = rt.Add("bazbazbaz", "blinky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
rb := []byte{}
|
||||||
|
r := rt.Next()
|
||||||
|
expect := append([]byte{0x3}, []byte("foo")...)
|
||||||
|
expect = append(expect, 4)
|
||||||
|
expect = append(expect, []byte("inky")...)
|
||||||
|
if !bytes.Equal(r, expect) {
|
||||||
|
t.Errorf("expected %v, got %v", expect, r)
|
||||||
|
}
|
||||||
|
rb = append(rb, r...)
|
||||||
|
|
||||||
|
r = rt.Next()
|
||||||
|
expect = append([]byte{0x6}, []byte("barbar")...)
|
||||||
|
expect = append(expect, 5)
|
||||||
|
expect = append(expect, []byte("pinky")...)
|
||||||
|
if !bytes.Equal(r, expect) {
|
||||||
|
t.Errorf("expected %v, got %v", expect, r)
|
||||||
|
}
|
||||||
|
rb = append(rb, r...)
|
||||||
|
|
||||||
|
r = rt.Next()
|
||||||
|
expect = append([]byte{0x9}, []byte("bazbazbaz")...)
|
||||||
|
expect = append(expect, 6)
|
||||||
|
expect = append(expect, []byte("blinky")...)
|
||||||
|
if !bytes.Equal(r, expect) {
|
||||||
|
t.Errorf("expected %v, got %v", expect, r)
|
||||||
|
}
|
||||||
|
rb = append(rb, r...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSerialize(t *testing.T) {
|
||||||
|
rt := NewRouter()
|
||||||
|
err := rt.Add("foo", "inky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = rt.Add("barbar", "pinky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
err = rt.Add("bazbazbaz", "blinky")
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serialize and deserialize.
|
||||||
|
ra := rt.ToBytes()
|
||||||
|
rt = FromBytes(ra)
|
||||||
|
rb := rt.ToBytes()
|
||||||
|
if !bytes.Equal(ra, rb) {
|
||||||
|
t.Errorf("expected %v, got %v", ra, rb)
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,15 @@ import (
|
|||||||
|
|
||||||
type Runner func(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error)
|
type Runner func(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error)
|
||||||
|
|
||||||
|
func Apply(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
||||||
|
var err error
|
||||||
|
st, instruction, err = Run(instruction, st, rs, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return st, instruction, err
|
||||||
|
}
|
||||||
|
return st, instruction, nil
|
||||||
|
}
|
||||||
|
|
||||||
func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
func Run(instruction []byte, st state.State, rs resource.Fetcher, ctx context.Context) (state.State, []byte, error) {
|
||||||
var err error
|
var err error
|
||||||
for len(instruction) > 0 {
|
for len(instruction) > 0 {
|
||||||
|
Loading…
Reference in New Issue
Block a user