Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
parity
Mirrored projects
parity-scale-codec
Commits
72bb694b
Unverified
Commit
72bb694b
authored
Mar 12, 2019
by
thiolliere
Committed by
GitHub
Mar 12, 2019
Browse files
forward encoding for single field struct (#54)
* forward encoding for single field struct * code refactor
parent
efcdf2c3
Changes
3
Hide whitespace changes
Inline
Side-by-side
derive/src/encode.rs
View file @
72bb694b
...
...
@@ -26,6 +26,46 @@ use crate::utils;
type
FieldsList
=
Punctuated
<
Field
,
Comma
>
;
fn
encode_single_field
(
closure
:
&
TokenStream
,
field
:
&
Field
,
field_name
:
TokenStream
,
)
->
TokenStream
{
let
encoded_as
=
utils
::
get_encoded_as_type
(
field
);
let
compact
=
utils
::
get_enable_compact
(
field
);
if
encoded_as
.is_some
()
&&
compact
{
return
Error
::
new
(
Span
::
call_site
(),
"`encoded_as` and `compact` can not be used at the same time!"
)
.to_compile_error
();
}
if
compact
{
let
field_type
=
&
field
.ty
;
quote_spanned!
{
field
.span
()
=>
{
<<
#
field_type
as
_parity_codec
::
HasCompact
>
::
Type
as
_parity_codec
::
EncodeAsRef
<
'_
,
#
field_type
>>
::
RefType
::
from
(
#
field_name
)
.using_encoded
(
#
closure
)
}
}
}
else
if
let
Some
(
encoded_as
)
=
encoded_as
{
let
field_type
=
&
field
.ty
;
quote_spanned!
{
field
.span
()
=>
{
<
#
encoded_as
as
_parity_codec
::
EncodeAsRef
<
'_
,
#
field_type
>>
::
RefType
::
from
(
#
field_name
)
.using_encoded
(
#
closure
)
}
}
}
else
{
quote_spanned!
{
field
.span
()
=>
_parity_codec
::
Encode
::
using_encoded
(
&
#
field_name
,
#
closure
)
}
}
}
fn
encode_fields
<
F
>
(
dest
:
&
TokenStream
,
fields
:
&
FieldsList
,
...
...
@@ -79,27 +119,59 @@ fn encode_fields<F>(
}
}
pub
fn
quote
(
data
:
&
Data
,
type_name
:
&
Ident
,
self_
:
&
TokenStream
,
dest
:
&
TokenStream
)
->
TokenStream
{
let
call_site
=
Span
::
call_site
();
match
*
data
{
fn
try_impl_encode_single_field_optimisation
(
data
:
&
Data
)
->
Option
<
TokenStream
>
{
let
ref
closure
=
quote!
(
f
);
let
optimisation
=
match
*
data
{
Data
::
Struct
(
ref
data
)
=>
{
match
data
.fields
{
Fields
::
Named
(
ref
fields
)
if
fields
.named
.len
()
==
1
=>
{
let
field
=
fields
.named
.first
()
.unwrap
();
let
ref
name
=
field
.value
()
.ident
;
Some
(
encode_single_field
(
closure
,
field
.value
(),
quote!
(
&
self
.#
name
)
))
},
Fields
::
Unnamed
(
ref
fields
)
if
fields
.unnamed
.len
()
==
1
=>
{
Some
(
encode_single_field
(
closure
,
fields
.unnamed
.first
()
.unwrap
()
.value
(),
quote!
(
&
self
.0
)
))
},
_
=>
None
,
}
},
_
=>
None
,
};
optimisation
.map
(|
optimisation
|
{
quote!
{
fn
using_encoded
<
R
,
F
:
FnOnce
(
&
[
u8
])
->
R
>
(
&
self
,
#
closure
:
F
)
->
R
{
#
optimisation
}
}
})
}
fn
impl_encode
(
data
:
&
Data
,
type_name
:
&
Ident
)
->
TokenStream
{
let
self_
=
quote!
(
self
);
let
ref
dest
=
quote!
(
dest
);
let
encoding
=
match
*
data
{
Data
::
Struct
(
ref
data
)
=>
{
match
data
.fields
{
Fields
::
Named
(
ref
fields
)
=>
encode_fields
(
dest
,
&
fields
.named
,
|
_
,
name
|
quote
_spanned!
(
call_site
=>
&
#
self_
.#
name
),
|
_
,
name
|
quote
!
(
&
#
self_
.#
name
),
),
Fields
::
Unnamed
(
ref
fields
)
=>
encode_fields
(
dest
,
&
fields
.unnamed
,
|
i
,
_
|
{
let
index
=
Index
{
index
:
i
as
u32
,
span
:
call_site
};
quote_spanned!
(
call_site
=>
&
#
self_
.#
index
)
},
|
i
,
_
|
quote!
(
&
#
self_
.#
i
),
),
Fields
::
Unit
=>
quote_spanned!
{
call_site
=>
drop
(
#
dest
);
},
Fields
::
Unit
=>
quote!
(
drop
(
#
dest
);),
}
},
Data
::
Enum
(
ref
data
)
=>
{
...
...
@@ -116,7 +188,7 @@ pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest: &TokenSt
match
f
.fields
{
Fields
::
Named
(
ref
fields
)
=>
{
let
field_name
=
|
_
,
ident
:
&
Option
<
Ident
>
|
quote
_spanned!
(
call_site
=>
#
ident
);
let
field_name
=
|
_
,
ident
:
&
Option
<
Ident
>
|
quote
!
(
#
ident
);
let
names
=
fields
.named
.iter
()
.enumerate
()
...
...
@@ -139,8 +211,8 @@ pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest: &TokenSt
let
field_name
=
|
i
,
_
:
&
Option
<
Ident
>
|
{
let
data
=
stringify
(
i
as
u8
);
let
ident
=
from_utf8
(
&
data
)
.expect
(
"We never go beyond ASCII"
);
let
ident
=
Ident
::
new
(
ident
,
call_site
);
quote
_spanned!
(
call_site
=>
#
ident
)
let
ident
=
Ident
::
new
(
ident
,
Span
::
call_site
()
);
quote
!
(
#
ident
)
};
let
names
=
fields
.unnamed
.iter
()
...
...
@@ -177,8 +249,23 @@ pub fn quote(data: &Data, type_name: &Ident, self_: &TokenStream, dest: &TokenSt
}
},
Data
::
Union
(
_
)
=>
Error
::
new
(
Span
::
call_site
(),
"Union types are not supported."
)
.to_compile_error
(),
};
quote!
{
fn
encode_to
<
EncOut
:
_parity_codec
::
Output
>
(
&
#
self_
,
#
dest
:
&
mut
EncOut
)
{
#
encoding
}
}
}
pub
fn
quote
(
data
:
&
Data
,
type_name
:
&
Ident
)
->
TokenStream
{
if
let
Some
(
implementation
)
=
try_impl_encode_single_field_optimisation
(
data
)
{
implementation
}
else
{
impl_encode
(
data
,
type_name
)
}
}
pub
fn
stringify
(
id
:
u8
)
->
[
u8
;
2
]
{
const
CHARS
:
&
[
u8
]
=
b"abcdefghijklmnopqrstuvwxyz"
;
let
len
=
CHARS
.len
()
as
u8
;
...
...
derive/src/lib.rs
View file @
72bb694b
...
...
@@ -71,15 +71,11 @@ pub fn encode_derive(input: TokenStream) -> TokenStream {
let
name
=
&
input
.ident
;
let
(
impl_generics
,
ty_generics
,
where_clause
)
=
input
.generics
.split_for_impl
();
let
self_
=
quote!
(
self
);
let
dest_
=
quote!
(
dest
);
let
encoding
=
encode
::
quote
(
&
input
.data
,
name
,
&
self_
,
&
dest_
);
let
encode_impl
=
encode
::
quote
(
&
input
.data
,
name
);
let
impl_block
=
quote!
{
impl
#
impl_generics
_parity_codec
::
Encode
for
#
name
#
ty_generics
#
where_clause
{
fn
encode_to
<
EncOut
:
_parity_codec
::
Output
>
(
&
#
self_
,
#
dest_
:
&
mut
EncOut
)
{
#
encoding
}
#
encode_impl
}
};
...
...
tests/single_field_struct_encoding.rs
0 → 100644
View file @
72bb694b
#[macro_use]
extern
crate
parity_codec_derive
;
use
parity_codec
::{
Encode
,
Decode
,
HasCompact
,
Compact
,
EncodeAsRef
,
CompactAs
};
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
S
{
x
:
u32
,
}
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
Sc
{
#[codec(compact)]
x
:
u32
,
}
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
Sh
<
T
:
HasCompact
>
{
#[codec(encoded_as
=
"<T as HasCompact>::Type"
)]
x
:
T
,
}
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
U
(
u32
);
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
Uc
(
#[codec(compact)]
u32
);
#[derive(Debug,
PartialEq,
Encode,
Decode)]
struct
Uh
<
T
:
HasCompact
>
(
#[codec(encoded_as
=
"<T as HasCompact>::Type"
)]
T
);
#[test]
fn
test_encoding
()
{
let
x
=
3u32
;
let
s
=
S
{
x
}
.encode
();
let
sc
=
Sc
{
x
}
.encode
();
let
sh
=
Sh
{
x
}
.encode
();
let
u
=
U
(
x
)
.encode
();
let
uc
=
Uc
(
x
)
.encode
();
let
uh
=
Uh
(
x
)
.encode
();
assert_eq!
(
&
s
,
&
[
3
,
0
,
0
,
0
]);
assert_eq!
(
&
sc
,
&
[
12
]);
assert_eq!
(
&
sh
,
&
[
12
]);
assert_eq!
(
&
u
,
&
[
3
,
0
,
0
,
0
]);
assert_eq!
(
&
uc
,
&
[
12
]);
assert_eq!
(
&
uh
,
&
[
12
]);
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new 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