Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
neoppod
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Levin Zimmermann
neoppod
Commits
a2e379ac
Commit
a2e379ac
authored
Jan 26, 2017
by
Kirill Smelkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
.
parent
44b5b834
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
37 additions
and
31 deletions
+37
-31
t/neo/proto.go
t/neo/proto.go
+3
-3
t/neo/proto_test.go
t/neo/proto_test.go
+3
-0
t/neo/protogen.go
t/neo/protogen.go
+31
-28
No files found.
t/neo/proto.go
View file @
a2e379ac
...
@@ -92,17 +92,17 @@ type UUID int32
...
@@ -92,17 +92,17 @@ type UUID int32
var
ErrDecodeOverflow
=
errors
.
New
(
"decode: bufer overflow"
)
var
ErrDecodeOverflow
=
errors
.
New
(
"decode: bufer overflow"
)
// NEOEncoder is interface for marshaling objects to wire format
in NEO
// NEOEncoder is interface for marshaling objects to wire format
type
NEOEncoder
interface
{
type
NEOEncoder
interface
{
// compute how much space is needed to encode
// compute how much space is needed to encode
NEOEncodedLen
()
int
NEOEncodedLen
()
int
// perform the encoding.
// perform the encoding.
// len(buf) must be >= NEOEncodedLen()
// XXX check in tests it will panic
// len(buf) must be >= NEOEncodedLen()
NEOEncode
(
buf
[]
byte
)
NEOEncode
(
buf
[]
byte
)
}
}
// NEODecoder is interface for unmarshalling objects from wire format
in NEO
// NEODecoder is interface for unmarshalling objects from wire format
type
NEODecoder
interface
{
type
NEODecoder
interface
{
NEODecode
(
data
[]
byte
)
(
nread
int
,
err
error
)
NEODecode
(
data
[]
byte
)
(
nread
int
,
err
error
)
}
}
...
...
t/neo/proto_test.go
View file @
a2e379ac
...
@@ -68,6 +68,9 @@ type NEOCodec interface {
...
@@ -68,6 +68,9 @@ type NEOCodec interface {
NEODecoder
NEODecoder
}
}
// TODO for _all_ packet types:
// zero-value -> encodedlen -> [encodedlen]byte -> decode (= ok) + check for overflow
// zero-value.encode([<encodedlen]byte) -> panic
// test marshalling for one packet type
// test marshalling for one packet type
func
testPktMarshal
(
t
*
testing
.
T
,
pkt
NEOCodec
,
encoded
string
)
{
func
testPktMarshal
(
t
*
testing
.
T
,
pkt
NEOCodec
,
encoded
string
)
{
...
...
t/neo/protogen.go
View file @
a2e379ac
...
@@ -33,7 +33,7 @@ maps, ...).
...
@@ -33,7 +33,7 @@ maps, ...).
Top-level generation driver is in generateCodecCode(). It accepts type
Top-level generation driver is in generateCodecCode(). It accepts type
specification and something that performs actual leaf-nodes code generation
specification and something that performs actual leaf-nodes code generation
(CodeGenerator interface). There are 3 particular codegenerators implemented -
(CodeGenerator interface). There are 3 particular codegenerators implemented -
- size
CodeGen, encoder & decoder - to generate each of the needed method functions. XXX naming
- size
r, encoder & decoder - to generate each of the needed method functions.
The structure of whole process is very similar to what would be happening at
The structure of whole process is very similar to what would be happening at
runtime if marshalling was reflect based, but statically with go/types we don't
runtime if marshalling was reflect based, but statically with go/types we don't
...
@@ -45,6 +45,11 @@ other.
...
@@ -45,6 +45,11 @@ other.
NOTE we do no try to emit very clever code - for cases where compiler
NOTE we do no try to emit very clever code - for cases where compiler
can do a good job the work is delegated to it.
can do a good job the work is delegated to it.
--------
TODO also types registry tables
*/
*/
package
main
package
main
...
@@ -144,7 +149,7 @@ import (
...
@@ -144,7 +149,7 @@ import (
case
*
ast
.
StructType
:
case
*
ast
.
StructType
:
fmt
.
Fprintf
(
&
buf
,
"// %d. %s
\n\n
"
,
pktCode
,
typename
)
fmt
.
Fprintf
(
&
buf
,
"// %d. %s
\n\n
"
,
pktCode
,
typename
)
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
size
CodeGen
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
size
r
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
encoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
encoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
decoder
{}))
buf
.
WriteString
(
generateCodecCode
(
typespec
,
&
decoder
{}))
...
@@ -238,14 +243,14 @@ func (b *Buffer) emit(format string, a ...interface{}) {
...
@@ -238,14 +243,14 @@ func (b *Buffer) emit(format string, a ...interface{}) {
fmt
.
Fprintf
(
b
,
format
+
"
\n
"
,
a
...
)
fmt
.
Fprintf
(
b
,
format
+
"
\n
"
,
a
...
)
}
}
// interface of a codegenerator (for size
CodeGen/coder/decoder XXX naming
)
// interface of a codegenerator (for size
r/coder/decoder
)
type
CodeGenerator
interface
{
type
CodeGenerator
interface
{
// tell codegen it should generate code for which type & receiver name
// tell codegen it should generate code for which type & receiver name
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
setFunc
(
recvName
,
typeName
string
,
typ
types
.
Type
)
// generate code to process a basic fixed type (not string)
// generate code to process a basic fixed type (not string)
// userType is type actually used in source (for which typ is underlying), or nil
// userType is type actually used in source (for which typ is underlying), or nil
// path is associated data member (to read from or write to)
// path is associated data member
- e.g. p.Address.Port
(to read from or write to)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
// generate code to process slice or map
// generate code to process slice or map
...
@@ -387,14 +392,12 @@ func (o *OverflowCheck) AddExpr(format string, a ...interface{}) {
...
@@ -387,14 +392,12 @@ func (o *OverflowCheck) AddExpr(format string, a ...interface{}) {
}
}
// XXX naming ok?
// sizer generates code to compute encoded size of a packet
// XXX -> Gen_NEOEncodedLen ?
// sizeCodeGen generates code to compute encoded size of a packet
//
//
// when type is recursively walked for every case symbolic size is added appropriately
// when type is recursively walked for every case symbolic size is added appropriately
// in case when it was needed to generate loops runtime accumulator variable is additionally used
// in case when it was needed to generate loops runtime accumulator variable is additionally used
// result is: symbolic size + (optionally) runtime accumulator
// result is: symbolic size + (optionally) runtime accumulator
type
size
CodeGen
struct
{
type
size
r
struct
{
commonCodeGen
commonCodeGen
size
SymSize
// currently accumulated packet size
size
SymSize
// currently accumulated packet size
}
}
...
@@ -403,8 +406,7 @@ type sizeCodeGen struct {
...
@@ -403,8 +406,7 @@ type sizeCodeGen struct {
//
//
// when type is recursively walked for every case code to update `data[n:]` is generated.
// when type is recursively walked for every case code to update `data[n:]` is generated.
// no overflow checks are generated as by NEOEncoder interface provided data
// no overflow checks are generated as by NEOEncoder interface provided data
// buffer should have at least NEOEncodedLen() length (the size computed by
// buffer should have at least NEOEncodedLen() length (the size computed by sizer)
// sizeCodeGen)
type
encoder
struct
{
type
encoder
struct
{
commonCodeGen
commonCodeGen
n
int
// current write position in data
n
int
// current write position in data
...
@@ -417,9 +419,7 @@ type encoder struct {
...
@@ -417,9 +419,7 @@ type encoder struct {
//
//
// overflow checks and, when convenient, nread updates are grouped and emitted
// overflow checks and, when convenient, nread updates are grouped and emitted
// so that they are performed in the beginning of greedy fixed-wire-size
// so that they are performed in the beginning of greedy fixed-wire-size
// blocks - checking as much as possible in one go.
// blocks - checking as much as possible to do ahead in one go.
//
// TODO more text?
type
decoder
struct
{
type
decoder
struct
{
commonCodeGen
commonCodeGen
...
@@ -429,16 +429,17 @@ type decoder struct {
...
@@ -429,16 +429,17 @@ type decoder struct {
n
int
// current read position in data.
n
int
// current read position in data.
// size that will be checked for overflow at current overflow check point
// overflow check state and size that will be checked for overflow at
// current overflow check point
overflowCheck
OverflowCheck
overflowCheck
OverflowCheck
}
}
var
_
CodeGenerator
=
(
*
size
CodeGen
)(
nil
)
var
_
CodeGenerator
=
(
*
size
r
)(
nil
)
var
_
CodeGenerator
=
(
*
encoder
)(
nil
)
var
_
CodeGenerator
=
(
*
encoder
)(
nil
)
var
_
CodeGenerator
=
(
*
decoder
)(
nil
)
var
_
CodeGenerator
=
(
*
decoder
)(
nil
)
func
(
s
*
size
CodeGen
)
generatedCode
()
string
{
func
(
s
*
size
r
)
generatedCode
()
string
{
code
:=
Buffer
{}
code
:=
Buffer
{}
// prologue
// prologue
code
.
emit
(
"func (%s *%s) NEOEncodedLen() int {"
,
s
.
recvName
,
s
.
typeName
)
code
.
emit
(
"func (%s *%s) NEOEncodedLen() int {"
,
s
.
recvName
,
s
.
typeName
)
...
@@ -500,6 +501,11 @@ func (d *decoder) resetPos() {
...
@@ -500,6 +501,11 @@ func (d *decoder) resetPos() {
// - before reading a variable sized item
// - before reading a variable sized item
// - in the beginning of a loop inside
// - in the beginning of a loop inside
func
(
d
*
decoder
)
overflowCheckpoint
()
{
func
(
d
*
decoder
)
overflowCheckpoint
()
{
// nop if we know overflow was already checked
if
d
.
overflowCheck
.
checked
{
return
}
//d.bufDone.emit("// overflow check point")
//d.bufDone.emit("// overflow check point")
if
!
d
.
overflowCheck
.
size
.
IsZero
()
{
if
!
d
.
overflowCheck
.
size
.
IsZero
()
{
d
.
bufDone
.
emit
(
"if uint32(len(data)) < %v { goto overflow }"
,
&
d
.
overflowCheck
.
size
)
d
.
bufDone
.
emit
(
"if uint32(len(data)) < %v { goto overflow }"
,
&
d
.
overflowCheck
.
size
)
...
@@ -541,7 +547,7 @@ func (d *decoder) generatedCode() string {
...
@@ -541,7 +547,7 @@ func (d *decoder) generatedCode() string {
}
}
// emit code to size/encode/decode basic fixed type
// emit code to size/encode/decode basic fixed type
func
(
s
*
size
CodeGen
)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
func
(
s
*
size
r
)
genBasic
(
path
string
,
typ
*
types
.
Basic
,
userType
types
.
Type
)
{
basic
:=
basicTypes
[
typ
.
Kind
()]
basic
:=
basicTypes
[
typ
.
Kind
()]
s
.
size
.
Add
(
basic
.
wireSize
)
s
.
size
.
Add
(
basic
.
wireSize
)
}
}
...
@@ -577,7 +583,7 @@ func (d *decoder) genBasic(assignto string, typ *types.Basic, userType types.Typ
...
@@ -577,7 +583,7 @@ func (d *decoder) genBasic(assignto string, typ *types.Basic, userType types.Typ
// emit code to size/encode/decode string or []byte
// emit code to size/encode/decode string or []byte
// len u32
// len u32
// [len]byte
// [len]byte
func
(
s
*
size
CodeGen
)
genSlice1
(
path
string
,
typ
types
.
Type
)
{
func
(
s
*
size
r
)
genSlice1
(
path
string
,
typ
types
.
Type
)
{
s
.
size
.
Add
(
4
)
s
.
size
.
Add
(
4
)
s
.
size
.
AddExpr
(
"len(%s)"
,
path
)
s
.
size
.
AddExpr
(
"len(%s)"
,
path
)
}
}
...
@@ -626,7 +632,7 @@ func (d *decoder) genSlice1(assignto string, typ types.Type) {
...
@@ -626,7 +632,7 @@ func (d *decoder) genSlice1(assignto string, typ types.Type) {
// emit code to size/encode/decode array with sizeof(elem)==1
// emit code to size/encode/decode array with sizeof(elem)==1
// [len(A)]byte
// [len(A)]byte
func
(
s
*
size
CodeGen
)
genArray1
(
path
string
,
typ
*
types
.
Array
)
{
func
(
s
*
size
r
)
genArray1
(
path
string
,
typ
*
types
.
Array
)
{
s
.
size
.
Add
(
int
(
typ
.
Len
()))
s
.
size
.
Add
(
int
(
typ
.
Len
()))
}
}
...
@@ -646,7 +652,7 @@ func (d *decoder) genArray1(assignto string, typ *types.Array) {
...
@@ -646,7 +652,7 @@ func (d *decoder) genArray1(assignto string, typ *types.Array) {
// emit code to size/encode/decode slice
// emit code to size/encode/decode slice
// len u32
// len u32
// [len]item
// [len]item
func
(
s
*
size
CodeGen
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
func
(
s
*
size
r
)
genSlice
(
path
string
,
typ
*
types
.
Slice
,
obj
types
.
Object
)
{
s
.
size
.
Add
(
4
)
s
.
size
.
Add
(
4
)
// if size(item)==const - size update in one go
// if size(item)==const - size update in one go
...
@@ -682,7 +688,7 @@ func (e *encoder) genSlice(path string, typ *types.Slice, obj types.Object) {
...
@@ -682,7 +688,7 @@ func (e *encoder) genSlice(path string, typ *types.Slice, obj types.Object) {
e
.
emit
(
"for i := 0; uint32(i) <l; i++ {"
)
e
.
emit
(
"for i := 0; uint32(i) <l; i++ {"
)
e
.
emit
(
"a := &%s[i]"
,
path
)
e
.
emit
(
"a := &%s[i]"
,
path
)
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
e
)
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
e
)
e
.
emit
(
"data = data[%v:]"
,
e
.
n
)
//
FIXME
wrt slice of slice ?
e
.
emit
(
"data = data[%v:]"
,
e
.
n
)
//
XXX
wrt slice of slice ?
e
.
emit
(
"}"
)
e
.
emit
(
"}"
)
e
.
emit
(
"}"
)
e
.
emit
(
"}"
)
e
.
n
=
0
e
.
n
=
0
...
@@ -710,9 +716,8 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
...
@@ -710,9 +716,8 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
d
.
emit
(
"for i := 0; uint32(i) < l; i++ {"
)
d
.
emit
(
"for i := 0; uint32(i) < l; i++ {"
)
d
.
emit
(
"a := &%s[i]"
,
assignto
)
d
.
emit
(
"a := &%s[i]"
,
assignto
)
if
!
elemFixed
{
d
.
overflowCheckpoint
()
d
.
overflowCheckpoint
()
}
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
d
)
codegenType
(
"(*a)"
,
typ
.
Elem
(),
obj
,
d
)
// d.resetPos() with nread update optionally skipped
// d.resetPos() with nread update optionally skipped
...
@@ -731,7 +736,7 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
...
@@ -731,7 +736,7 @@ func (d *decoder) genSlice(assignto string, typ *types.Slice, obj types.Object)
// generate code to encode/decode map
// generate code to encode/decode map
// len u32
// len u32
// [len](key, value)
// [len](key, value)
func
(
s
*
size
CodeGen
)
genMap
(
path
string
,
typ
*
types
.
Map
,
obj
types
.
Object
)
{
func
(
s
*
size
r
)
genMap
(
path
string
,
typ
*
types
.
Map
,
obj
types
.
Object
)
{
keySize
,
keyFixed
:=
typeSizeFixed
(
typ
.
Key
())
keySize
,
keyFixed
:=
typeSizeFixed
(
typ
.
Key
())
elemSize
,
elemFixed
:=
typeSizeFixed
(
typ
.
Elem
())
elemSize
,
elemFixed
:=
typeSizeFixed
(
typ
.
Elem
())
...
@@ -804,9 +809,7 @@ func (d *decoder) genMap(assignto string, typ *types.Map, obj types.Object) {
...
@@ -804,9 +809,7 @@ func (d *decoder) genMap(assignto string, typ *types.Map, obj types.Object) {
d
.
emit
(
"m := %v"
,
assignto
)
d
.
emit
(
"m := %v"
,
assignto
)
d
.
emit
(
"for i := 0; uint32(i) < l; i++ {"
)
d
.
emit
(
"for i := 0; uint32(i) < l; i++ {"
)
if
!
itemFixed
{
d
.
overflowCheckpoint
()
d
.
overflowCheckpoint
()
}
codegenType
(
"key:"
,
typ
.
Key
(),
obj
,
d
)
codegenType
(
"key:"
,
typ
.
Key
(),
obj
,
d
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment