Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
redox-os
cbindgen
Commits
4064a092
Commit
4064a092
authored
Jun 20, 2017
by
Ryan Hunt
Browse files
Do a bunch of clean up and add some comments
parent
9d10cd96
Changes
12
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
4064a092
...
...
@@ -38,7 +38,9 @@ fn main() {
let
root
=
env
::
var
(
"CARGO_MANIFEST_DIR"
)
.unwrap
();
let
config
=
Config
::
from_root_or_default
(
&
root
);
Library
::
load
(
&
root
,
&
config
)
Library
::
load_crate
(
Path
::
new
(
root
),
"CRATE_NAME"
,
&
config
)
.generate
()
.unwrap
()
.write_to_file
(
"bindings.h"
);
}
...
...
@@ -59,8 +61,6 @@ See `compile-tests/` for some examples of rust source that can be handled.
## Future work
1.
Add a validation step to catch common issues
2.
Better support for types with fully specified names
3.
Better support for finding dependencies managed by Cargo
4.
Support for generating a FFI interface for a Struct+Impl
5.
...
1.
Better support for types with fully specified names
2.
Support for generating a FFI interface for a Struct+Impl
3.
...
src/bindgen/annotation.rs
View file @
4064a092
...
...
@@ -38,11 +38,17 @@ impl AnnotationSet {
pub
fn
parse
(
text
:
String
)
->
Result
<
AnnotationSet
,
String
>
{
let
mut
annotations
=
HashMap
::
new
();
// Look at each line for an annotation
for
line
in
text
.lines
()
.map
(|
x
|
x
.trim_left_matches
(
"///"
)
.trim
())
{
// Skip lines that don't start with cbindgen
if
!
line
.starts_with
(
"cbindgen:"
)
{
continue
;
}
// Remove the "cbingen:" prefix
let
annotation
=
&
line
[
9
..
];
// Split the annotation in two
let
parts
:
Vec
<&
str
>
=
annotation
.split
(
"="
)
.map
(|
x
|
x
.trim
())
.collect
();
...
...
@@ -51,13 +57,16 @@ impl AnnotationSet {
return
Err
(
format!
(
"couldn't parse {}"
,
line
));
}
// Grab the name that this annotation is modifying
let
name
=
parts
[
0
];
// If the annotation only has a name, assume it's setting a bool flag
if
parts
.len
()
==
1
{
annotations
.insert
(
name
.to_string
(),
AnnotationValue
::
Bool
(
true
));
continue
;
}
// Parse the value we're setting the name to
let
value
=
parts
[
1
];
if
let
Some
(
x
)
=
parse_list
(
value
)
{
...
...
@@ -111,6 +120,7 @@ impl AnnotationSet {
}
}
/// Parse lists like "[x, y, z]". This is not implemented efficiently or well.
fn
parse_list
(
list
:
&
str
)
->
Option
<
Vec
<
String
>>
{
if
list
.len
()
<
2
{
return
None
;
...
...
src/bindgen/cargo_expand.rs
View file @
4064a092
...
...
@@ -3,10 +3,11 @@ use std::path::Path;
use
std
::
process
::
Command
;
use
std
::
str
::
from_utf8
;
type
ExpandResult
=
Result
<
String
,
String
>
;
pub
fn
expand
(
manifest_path
:
&
Path
,
crate_name
:
&
str
)
->
Expand
Result
{
/// Use rustc to expand and pretty print the crate into a single file,
/// removing any macros in the process.
pub
fn
expand
(
manifest_path
:
&
Path
,
crate_name
:
&
str
)
->
Result
<
String
,
String
>
{
let
cargo
=
env
::
var
(
"CARGO"
)
.unwrap_or_else
(|
_
|
String
::
from
(
"cargo"
));
let
mut
cmd
=
Command
::
new
(
cargo
);
cmd
.arg
(
"rustc"
);
cmd
.arg
(
"--manifest-path"
);
...
...
src/bindgen/cargo_toml.rs
View file @
4064a092
...
...
@@ -35,6 +35,7 @@ pub struct Package {
pub
name
:
String
,
}
/// Parse the Cargo.toml for a given path
pub
fn
manifest
(
manifest_path
:
&
Path
)
->
Result
<
Manifest
,
Error
>
{
let
mut
s
=
String
::
new
();
let
mut
f
=
File
::
open
(
manifest_path
)
?
;
...
...
src/bindgen/cdecl.rs
View file @
4064a092
...
...
@@ -89,8 +89,7 @@ impl CDecl {
}
}
fn
to_string
(
&
self
,
ident
:
Option
<&
str
>
)
->
String
{
fn
to_string
(
&
self
,
ident
:
Option
<&
str
>
)
->
String
{
// Build the left side (the type-specifier and type-qualifier),
// and then build the right side (the declarators), and then
// merge the result.
...
...
@@ -169,11 +168,9 @@ impl CDecl {
}
}
pub
fn
write_func
<
F
:
Write
>
(
out
:
&
mut
SourceWriter
<
F
>
,
f
:
&
Function
)
{
pub
fn
write_func
<
F
:
Write
>
(
out
:
&
mut
SourceWriter
<
F
>
,
f
:
&
Function
)
{
out
.write
(
&
CDecl
::
from_func
(
f
)
.to_string
(
Some
(
&
f
.name
)));
}
pub
fn
write_type
<
F
:
Write
>
(
out
:
&
mut
SourceWriter
<
F
>
,
t
:
&
Type
,
ident
:
&
str
)
{
pub
fn
write_type
<
F
:
Write
>
(
out
:
&
mut
SourceWriter
<
F
>
,
t
:
&
Type
,
ident
:
&
str
)
{
out
.write
(
&
CDecl
::
from_type
(
t
)
.to_string
(
Some
(
ident
)));
}
src/bindgen/config.rs
View file @
4064a092
...
...
@@ -19,21 +19,6 @@ pub enum Language {
C
,
}
/// A style of braces to use for generating code.
#[derive(Debug,
Clone,
PartialEq)]
pub
enum
Braces
{
SameLine
,
NextLine
,
}
/// A type of layout to use when generating long lines of code.
#[derive(Debug,
Clone,
PartialEq)]
pub
enum
Layout
{
Horizontal
,
Vertical
,
Auto
,
}
impl
FromStr
for
Language
{
type
Err
=
String
;
...
...
@@ -53,6 +38,16 @@ impl FromStr for Language {
}
}
}
deserialize_enum_str!
(
Language
);
/// A style of braces to use for generating code.
#[derive(Debug,
Clone,
PartialEq)]
pub
enum
Braces
{
SameLine
,
NextLine
,
}
impl
FromStr
for
Braces
{
type
Err
=
String
;
...
...
@@ -66,6 +61,17 @@ impl FromStr for Braces {
}
}
}
deserialize_enum_str!
(
Braces
);
/// A type of layout to use when generating long lines of code.
#[derive(Debug,
Clone,
PartialEq)]
pub
enum
Layout
{
Horizontal
,
Vertical
,
Auto
,
}
impl
FromStr
for
Layout
{
type
Err
=
String
;
...
...
@@ -82,67 +88,8 @@ impl FromStr for Layout {
}
}
deserialize_enum_str!
(
Language
);
deserialize_enum_str!
(
Braces
);
deserialize_enum_str!
(
Layout
);
/// A collection of settings to customize the generated bindings.
#[derive(Debug,
Clone,
Deserialize)]
#[serde(rename_all
=
"snake_case"
)]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub
struct
Config
{
/// Optional text to output at the beginning of the file
pub
header
:
Option
<
String
>
,
/// Optional text to output at the end of the file
pub
trailer
:
Option
<
String
>
,
/// Option name to use for an include guard
pub
include_guard
:
Option
<
String
>
,
/// Optional text to output at major sections to deter manual editing
pub
autogen_warning
:
Option
<
String
>
,
/// Include a comment with the version of cbindgen used to generate the file
pub
include_version
:
bool
,
/// The style to use for braces
pub
braces
:
Braces
,
/// The preferred length of a line, used for auto breaking function arguments
pub
line_length
:
usize
,
/// The amount of spaces in a tab
pub
tab_width
:
usize
,
/// The language to output bindings for
pub
language
:
Language
,
/// The names of crates to parse with `rustc --pretty=expanded`
pub
expand
:
Vec
<
String
>
,
/// The configuration options for functions
#[serde(rename
=
"fn"
)]
pub
function
:
FunctionConfig
,
/// The configuration options for structs
#[serde(rename
=
"struct"
)]
pub
structure
:
StructConfig
,
/// The configuration options for enums
#[serde(rename
=
"enum"
)]
pub
enumeration
:
EnumConfig
,
}
impl
Default
for
Config
{
fn
default
()
->
Config
{
Config
{
header
:
None
,
trailer
:
None
,
include_guard
:
None
,
autogen_warning
:
None
,
include_version
:
true
,
braces
:
Braces
::
SameLine
,
line_length
:
100
,
tab_width
:
2
,
language
:
Language
::
Cxx
,
expand
:
Vec
::
new
(),
function
:
FunctionConfig
::
default
(),
structure
:
StructConfig
::
default
(),
enumeration
:
EnumConfig
::
default
(),
}
}
}
/// Settings to apply to generated functions.
#[derive(Debug,
Clone,
Deserialize)]
#[serde(rename_all
=
"snake_case"
)]
...
...
@@ -170,6 +117,22 @@ impl Default for FunctionConfig {
}
}
impl
FunctionConfig
{
pub
fn
prefix
(
&
self
,
annotations
:
&
AnnotationSet
)
->
Option
<
String
>
{
if
let
Some
(
x
)
=
annotations
.atom
(
"prefix"
)
{
return
x
;
}
self
.prefix
.clone
()
}
pub
fn
postfix
(
&
self
,
annotations
:
&
AnnotationSet
)
->
Option
<
String
>
{
if
let
Some
(
x
)
=
annotations
.atom
(
"postfix"
)
{
return
x
;
}
self
.postfix
.clone
()
}
}
/// Settings to apply to generated structs.
#[derive(Debug,
Clone,
Deserialize)]
#[serde(rename_all
=
"snake_case"
)]
...
...
@@ -206,6 +169,45 @@ impl Default for StructConfig {
}
}
impl
StructConfig
{
pub
fn
derive_eq
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-eq"
)
{
return
x
;
}
self
.derive_eq
}
pub
fn
derive_neq
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-neq"
)
{
return
x
;
}
self
.derive_neq
}
pub
fn
derive_lt
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-lt"
)
{
return
x
;
}
self
.derive_lt
}
pub
fn
derive_lte
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-lte"
)
{
return
x
;
}
self
.derive_lte
}
pub
fn
derive_gt
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-gt"
)
{
return
x
;
}
self
.derive_gt
}
pub
fn
derive_gte
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-gte"
)
{
return
x
;
}
self
.derive_gte
}
}
/// Settings to apply to generated enums.
#[derive(
Debug,
Clone,
Deserialize)]
#[serde(rename_all
=
"snake_case"
)]
...
...
@@ -228,6 +230,72 @@ impl Default for EnumConfig {
}
}
impl
EnumConfig
{
pub
fn
add_sentinel
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"add-sentinel"
)
{
return
x
;
}
self
.add_sentinel
}
}
/// A collection of settings to customize the generated bindings.
#[derive(Debug,
Clone,
Deserialize)]
#[serde(rename_all
=
"snake_case"
)]
#[serde(deny_unknown_fields)]
#[serde(default)]
pub
struct
Config
{
/// Optional text to output at the beginning of the file
pub
header
:
Option
<
String
>
,
/// Optional text to output at the end of the file
pub
trailer
:
Option
<
String
>
,
/// Option name to use for an include guard
pub
include_guard
:
Option
<
String
>
,
/// Optional text to output at major sections to deter manual editing
pub
autogen_warning
:
Option
<
String
>
,
/// Include a comment with the version of cbindgen used to generate the file
pub
include_version
:
bool
,
/// The style to use for braces
pub
braces
:
Braces
,
/// The preferred length of a line, used for auto breaking function arguments
pub
line_length
:
usize
,
/// The amount of spaces in a tab
pub
tab_width
:
usize
,
/// The language to output bindings for
pub
language
:
Language
,
/// The names of crates to parse with `rustc --pretty=expanded`
pub
expand
:
Vec
<
String
>
,
/// The configuration options for functions
#[serde(rename
=
"fn"
)]
pub
function
:
FunctionConfig
,
/// The configuration options for structs
#[serde(rename
=
"struct"
)]
pub
structure
:
StructConfig
,
/// The configuration options for enums
#[serde(rename
=
"enum"
)]
pub
enumeration
:
EnumConfig
,
}
impl
Default
for
Config
{
fn
default
()
->
Config
{
Config
{
header
:
None
,
trailer
:
None
,
include_guard
:
None
,
autogen_warning
:
None
,
include_version
:
true
,
braces
:
Braces
::
SameLine
,
line_length
:
100
,
tab_width
:
2
,
language
:
Language
::
Cxx
,
expand
:
Vec
::
new
(),
function
:
FunctionConfig
::
default
(),
structure
:
StructConfig
::
default
(),
enumeration
:
EnumConfig
::
default
(),
}
}
}
impl
Config
{
pub
fn
from_file
(
file_name
:
&
str
)
->
Result
<
Config
,
String
>
{
fn
read
(
file_name
:
&
str
)
->
io
::
Result
<
String
>
{
...
...
@@ -256,67 +324,3 @@ impl Config {
}
}
}
impl
FunctionConfig
{
pub
fn
prefix
(
&
self
,
annotations
:
&
AnnotationSet
)
->
Option
<
String
>
{
if
let
Some
(
x
)
=
annotations
.atom
(
"prefix"
)
{
return
x
;
}
self
.prefix
.clone
()
}
pub
fn
postfix
(
&
self
,
annotations
:
&
AnnotationSet
)
->
Option
<
String
>
{
if
let
Some
(
x
)
=
annotations
.atom
(
"postfix"
)
{
return
x
;
}
self
.postfix
.clone
()
}
}
impl
StructConfig
{
pub
fn
derive_eq
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-eq"
)
{
return
x
;
}
self
.derive_eq
}
pub
fn
derive_neq
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-neq"
)
{
return
x
;
}
self
.derive_neq
}
pub
fn
derive_lt
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-lt"
)
{
return
x
;
}
self
.derive_lt
}
pub
fn
derive_lte
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-lte"
)
{
return
x
;
}
self
.derive_lte
}
pub
fn
derive_gt
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-gt"
)
{
return
x
;
}
self
.derive_gt
}
pub
fn
derive_gte
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"derive-gte"
)
{
return
x
;
}
self
.derive_gte
}
}
impl
EnumConfig
{
pub
fn
add_sentinel
(
&
self
,
annotations
:
&
AnnotationSet
)
->
bool
{
if
let
Some
(
x
)
=
annotations
.bool
(
"add-sentinel"
)
{
return
x
;
}
self
.add_sentinel
}
}
src/bindgen/items.rs
View file @
4064a092
...
...
@@ -39,6 +39,7 @@ pub enum PrimitiveType {
Float
,
Double
,
}
impl
PrimitiveType
{
fn
maybe
(
path
:
&
str
)
->
Option
<
PrimitiveType
>
{
match
path
{
...
...
@@ -83,6 +84,7 @@ impl PrimitiveType {
true
}
}
impl
fmt
::
Display
for
PrimitiveType
{
fn
fmt
(
&
self
,
f
:
&
mut
fmt
::
Formatter
)
->
fmt
::
Result
{
match
self
{
...
...
@@ -124,11 +126,12 @@ pub enum Type {
Array
(
Box
<
Type
>
,
u64
),
FuncPtr
(
Box
<
Type
>
,
Vec
<
Type
>
),
}
impl
Type
{
pub
fn
convert
(
ty
:
&
syn
::
Ty
)
->
Convert
Result
<
Option
<
Type
>>
{
pub
fn
load
(
ty
:
&
syn
::
Ty
)
->
Result
<
Option
<
Type
>
,
String
>
{
let
converted
=
match
ty
{
&
syn
::
Ty
::
Rptr
(
_
,
ref
mut_ty
)
=>
{
let
converted
=
try
!
(
Type
::
convert
(
&
mut_ty
.ty
)
)
;
let
converted
=
Type
::
load
(
&
mut_ty
.ty
)
?
;
let
converted
=
match
converted
{
Some
(
converted
)
=>
converted
,
...
...
@@ -141,7 +144,7 @@ impl Type {
}
}
&
syn
::
Ty
::
Ptr
(
ref
mut_ty
)
=>
{
let
converted
=
try
!
(
Type
::
convert
(
&
mut_ty
.ty
)
)
;
let
converted
=
Type
::
load
(
&
mut_ty
.ty
)
?
;
let
converted
=
match
converted
{
Some
(
converted
)
=>
converted
,
...
...
@@ -154,7 +157,7 @@ impl Type {
}
}
&
syn
::
Ty
::
Path
(
_
,
ref
p
)
=>
{
let
(
name
,
generics
)
=
try
!
(
p
.convert_to_generic_single_segment
()
)
;
let
(
name
,
generics
)
=
p
.convert_to_generic_single_segment
()
?
;
if
name
==
"PhantomData"
{
return
Ok
(
None
);
...
...
@@ -169,7 +172,7 @@ impl Type {
}
}
&
syn
::
Ty
::
Array
(
ref
ty
,
syn
::
ConstExpr
::
Lit
(
syn
::
Lit
::
Int
(
sz
,
_
)))
=>
{
let
converted
=
try
!
(
Type
::
convert
(
ty
)
)
;
let
converted
=
Type
::
load
(
ty
)
?
;
let
converted
=
match
converted
{
Some
(
converted
)
=>
converted
,
...
...
@@ -179,9 +182,9 @@ impl Type {
Type
::
Array
(
Box
::
new
(
converted
),
sz
)
},
&
syn
::
Ty
::
BareFn
(
ref
f
)
=>
{
let
args
=
try
!
(
f
.inputs
.iter
()
.try_skip_map
(|
x
|
Type
::
convert
(
&
x
.ty
))
)
;
let
ret
=
try
!
(
f
.output
.as_type
()
)
;
let
args
=
f
.inputs
.iter
()
.try_skip_map
(|
x
|
Type
::
load
(
&
x
.ty
))
?
;
let
ret
=
f
.output
.as_type
()
?
;
Type
::
FuncPtr
(
Box
::
new
(
ret
),
args
)
},
...
...
@@ -281,6 +284,7 @@ impl Type {
}
}
}
impl
Source
for
(
String
,
Type
)
{
fn
write
<
F
:
Write
>
(
&
self
,
_config
:
&
Config
,
out
:
&
mut
SourceWriter
<
F
>
)
{
cdecl
::
write_type
(
out
,
&
self
.1
,
&
self
.0
);
...
...
@@ -297,14 +301,14 @@ pub struct Function {
}
impl
Function
{
pub
fn
convert
(
name
:
String
,
annotations
:
AnnotationSet
,
decl
:
&
syn
::
FnDecl
,
extern_decl
:
bool
)
->
Convert
Result
<
Function
>
pub
fn
load
(
name
:
String
,
annotations
:
AnnotationSet
,
decl
:
&
syn
::
FnDecl
,
extern_decl
:
bool
)
->
Result
<
Function
,
String
>
{
let
args
=
try
!
(
decl
.inputs
.iter
()
.try_skip_map
(|
x
|
x
.as_ident_and_type
())
)
;
let
ret
=
try
!
(
decl
.output
.as_type
()
)
;
let
args
=
decl
.inputs
.iter
()
.try_skip_map
(|
x
|
x
.as_ident_and_type
())
?
;
let
ret
=
decl
.output
.as_type
()
?
;
Ok
(
Function
{
name
:
name
,
...
...
@@ -335,6 +339,7 @@ impl Function {
}
}
}
impl
Source
for
Function
{
fn
write
<
F
:
Write
>
(
&
self
,
config
:
&
Config
,
out
:
&
mut
SourceWriter
<
F
>
)
{
fn
write_1
<
W
:
Write
>
(
func
:
&
Function
,
config
:
&
Config
,
out
:
&
mut
SourceWriter
<
W
>
)
{
...
...
@@ -352,6 +357,7 @@ impl Source for Function {
}
out
.write
(
";"
);
}
fn
write_2
<
W
:
Write
>
(
func
:
&
Function
,
config
:
&
Config
,
out
:
&
mut
SourceWriter
<
W
>
)
{
let
prefix
=
config
.function
.prefix
(
&
func
.annotations
);
let
postfix
=
config
.function
.postfix
(
&
func
.annotations
);
...
...
@@ -388,21 +394,21 @@ pub struct Struct {
}
impl
Struct
{
pub
fn
convert
(
name
:
String
,
annotations
:
AnnotationSet
,
decl
:
&
syn
::
VariantData
,
generics
:
&
syn
::
Generics
)
->
Convert
Result
<
Struct
>
pub
fn
load
(
name
:
String
,
annotations
:
AnnotationSet
,
decl
:
&
syn
::
VariantData
,
generics
:
&
syn
::
Generics
)
->
Result
<
Struct
,
String
>
{
let
fields
=
match
decl
{
&
syn
::
VariantData
::
Struct
(
ref
fields
)
=>
{
try
!
(
fields
.iter
()
.try_skip_map
(|
x
|
x
.as_ident_and_type
())
)
fields
.iter
()
.try_skip_map
(|
x
|
x
.as_ident_and_type
())
?
}
&
syn
::
VariantData
::
Tuple
(
ref
fields
)
=>
{
let
mut
out
=
Vec
::
new
();
let
mut
current
=
0
;
for
field
in
fields
{
if
let
Some
(
x
)
=
try
!
(
Type
::
convert
(
&
field
.ty
)
)
{
if
let
Some
(
x
)
=
Type
::
load
(
&
field
.ty
)
?
{
out
.push
((
format!
(
"{}"
,
current
),
x
));
current
+=
1
;
}
...
...
@@ -457,6 +463,7 @@ impl Struct {
}
}
}
impl
Source
for
Struct
{
fn
write
<
F
:
Write
>
(
&
self
,
config
:
&
Config
,
out
:
&
mut
SourceWriter
<
F
>
)
{
assert
!
(
self
.generic_params
.is_empty
());
...
...
@@ -548,6 +555,7 @@ impl OpaqueStruct {
}
}
}
impl
Source
for
OpaqueStruct
{
fn
write
<
F
:
Write
>
(
&
self
,
config
:
&
Config
,
out
:
&
mut
SourceWriter
<
F
>
)
{
if
config
.language
==
Language
::
C
{
...
...
@@ -560,6 +568,15 @@ impl Source for OpaqueStruct {
}
}
#[derive(Debug,
Copy,
Clone,
PartialEq)]
pub
enum
Repr
{
None
,
C
,
U8
,
U16
,
U32
,
}
#[derive(Debug,
Clone)]
pub
struct
Enum
{
pub
name
:
String
,
...
...
@@ -569,10 +586,10 @@ pub struct Enum {
}