Skip to content

Commit

Permalink
add support for serde attributes (#18)
Browse files Browse the repository at this point in the history
  • Loading branch information
littledivy authored Oct 19, 2021
1 parent 722f9f0 commit 3ca55e7
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 79 deletions.
49 changes: 49 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ quote = "1"
syn = { version = "1", features = ["full", "extra-traits"] }
serde = { version = "1.0.59", features = ["derive"] }
serde_json = "1.0.59"

Inflector = "0.11.4"
115 changes: 41 additions & 74 deletions example/bindings/bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,97 +6,64 @@ function encode(v: string | Uint8Array): Uint8Array {
}
const opts = {
name: "add",
url: "target/debug",
url: "target/debug"
};
const _lib = await Plug.prepare(opts, {
sleep: { parameters: ["u64"], result: "void", nonblocking: true },
test_mixed_order: {
parameters: ["i32", "buffer", "usize", "i32"],
result: "i32",
nonblocking: false,
},
test_str: {
parameters: ["buffer", "usize"],
result: "void",
nonblocking: false,
},
test_mixed: {
parameters: ["isize", "buffer", "usize"],
result: "i32",
nonblocking: false,
},
add2: { parameters: ["buffer", "usize"], result: "i32", nonblocking: false },
test_serde: {
parameters: ["buffer", "usize"],
result: "u8",
nonblocking: false,
},
add: { parameters: ["i32", "i32"], result: "i32", nonblocking: false },
test_buf: {
parameters: ["buffer", "usize"],
result: "u8",
nonblocking: false,
},
});
test_buf: { parameters: [ "buffer", "usize" ], result: "u8", nonblocking: false }, test_serde: { parameters: [ "buffer", "usize" ], result: "u8", nonblocking: false }, test_mixed_order: { parameters: [ "i32", "buffer", "usize", "i32" ], result: "i32", nonblocking: false }, add: { parameters: [ "i32", "i32" ], result: "i32", nonblocking: false }, test_str: { parameters: [ "buffer", "usize" ], result: "void", nonblocking: false }, sleep: { parameters: [ "u64" ], result: "void", nonblocking: true }, add2: { parameters: [ "buffer", "usize" ], result: "i32", nonblocking: false }, test_mixed: { parameters: [ "isize", "buffer", "usize" ], result: "i32", nonblocking: false } });
export type PlainEnum = { a: {
a: string;
} } |
"b" |
"c";
export type OptionStruct = {
maybe: string | undefined | null;
maybe: string | undefined | null;
};
export type MyStruct = {
arr: Array<string>;
};
/**
* Doc comment for `Input` struct.
* ...testing multiline
*/
* Doc comment for `Input` struct.
* ...testing multiline
**/
export type Input = {
/**
* Doc comments get
* transformed to JS doc
* comments.
*/
* Doc comments get
* transformed to JS doc
* comments.
**/
a: number;
b: number;
};
export type PlainEnum =
| {
A: {
a: string;
};
}
| "B"
| "C";
export type MyStruct = {
arr: Array<string>;
};
export function sleep(a0: number) {
return _lib.symbols.sleep(a0) as Promise<null>;
export function test_buf(a0: Uint8Array) {
const a0_buf = encode((a0));
return _lib.symbols.test_buf(a0_buf, a0_buf.byteLength) as number
}
export function test_serde(a0: MyStruct) {
const a0_buf = encode(JSON.stringify(a0));
return _lib.symbols.test_serde(a0_buf, a0_buf.byteLength) as number
}
export function test_mixed_order(a0: number, a1: Input, a2: number) {
export function test_mixed_order(a0: number,a1: Input,a2: number) {
const a1_buf = encode(JSON.stringify(a1));
return _lib.symbols.test_mixed_order(
a0,
a1_buf,
a1_buf.byteLength,
a2,
) as number;
return _lib.symbols.test_mixed_order(a0, a1_buf, a1_buf.byteLength, a2) as number
}
export function add(a0: number,a1: number) {

return _lib.symbols.add(a0, a1) as number
}
export function test_str(a0: string) {
const a0_buf = encode(a0);
return _lib.symbols.test_str(a0_buf, a0_buf.byteLength) as null;
const a0_buf = encode((a0));
return _lib.symbols.test_str(a0_buf, a0_buf.byteLength) as null
}
export function test_mixed(a0: number, a1: Input) {
const a1_buf = encode(JSON.stringify(a1));
return _lib.symbols.test_mixed(a0, a1_buf, a1_buf.byteLength) as number;
export function sleep(a0: number) {

return _lib.symbols.sleep(a0) as Promise<null>
}
export function add2(a0: Input) {
const a0_buf = encode(JSON.stringify(a0));
return _lib.symbols.add2(a0_buf, a0_buf.byteLength) as number;
return _lib.symbols.add2(a0_buf, a0_buf.byteLength) as number
}
export function test_serde(a0: MyStruct) {
const a0_buf = encode(JSON.stringify(a0));
return _lib.symbols.test_serde(a0_buf, a0_buf.byteLength) as number;
}
export function add(a0: number, a1: number) {
return _lib.symbols.add(a0, a1) as number;
}
export function test_buf(a0: Uint8Array) {
const a0_buf = encode(a0);
return _lib.symbols.test_buf(a0_buf, a0_buf.byteLength) as number;
export function test_mixed(a0: number,a1: Input) {
const a1_buf = encode(JSON.stringify(a1));
return _lib.symbols.test_mixed(a0, a1_buf, a1_buf.byteLength) as number
}

1 change: 1 addition & 0 deletions example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ fn test_buf(b: &[u8]) -> u8 {
}

#[deno_bindgen]
#[serde(rename_all = "lowercase")]
enum PlainEnum {
A { a: String },
B,
Expand Down
71 changes: 67 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#![feature(box_patterns)]

use inflector::Inflector;
use proc_macro::TokenStream;
use quote::format_ident;
use quote::quote;
Expand Down Expand Up @@ -356,8 +357,10 @@ fn process_struct(
let mut fmap = HashMap::new();
let mut typescript: Vec<String> = vec![];

let serde_attrs = get_serde_attrs(&input.attrs);

for field in fields.iter() {
let ident = field
let mut ident = field
.ident
.as_ref()
.expect("Field without ident")
Expand All @@ -372,6 +375,10 @@ fn process_struct(
_ => unimplemented!(),
};

for attr in &serde_attrs {
ident = attr.transform(&ident);
}

let doc_str = get_docs(&field.attrs);
typescript.push(format!(
"{} {}: {};",
Expand Down Expand Up @@ -400,13 +407,19 @@ fn process_struct(
for variant in variants {
let mut variant_fields: Vec<String> = vec![];
let fields = &variant.fields;

let serde_attrs = get_serde_attrs(&input.attrs);
for field in fields {
let ident = field
let mut ident = field
.ident
.as_ref()
.expect("Field without ident")
.to_string();

for attr in &serde_attrs {
ident = attr.transform(&ident);
}

let doc_str = get_docs(&field.attrs);
variant_fields.push(format!(
"{} {}: {};",
Expand All @@ -416,16 +429,22 @@ fn process_struct(
));
}

let mut ident = variant.ident.to_string();

for attr in &serde_attrs {
ident = attr.transform(&ident);
}

let doc_str = get_docs(&variant.attrs);
let variant_str = if variant_fields.len() > 0 {
format!(
"{} {{ {}: {{\n {}\n}} }}",
doc_str,
&variant.ident,
&ident,
variant_fields.join("\n")
)
} else {
format!("{} \"{}\"", doc_str, &variant.ident)
format!("{} \"{}\"", doc_str, &ident)
};

typescript.push(variant_str);
Expand Down Expand Up @@ -470,6 +489,50 @@ fn get_docs(attrs: &Vec<syn::Attribute>) -> String {
doc_str
}

#[derive(Debug)]
enum SerdeAttr {
RenameAll(String),
}

impl SerdeAttr {
pub fn transform(&self, s: &str) -> String {
match self {
SerdeAttr::RenameAll(t) => match t.as_ref() {
"lowercase" => s.to_lowercase(),
"UPPERCASE" => s.to_uppercase(),
"camelCase" => s.to_camel_case(),
"snake_case" => s.to_snake_case(),
"PascalCase" => s.to_pascal_case(),
"SCREAMING_SNAKE_CASE" => s.to_screaming_snake_case(),
_ => panic!("Invalid attribute value: {}", s),
},
}
}
}

fn get_serde_attrs(attrs: &Vec<syn::Attribute>) -> Vec<SerdeAttr> {
attrs
.iter()
.filter(|i| i.path.is_ident("serde"))
.flat_map(|attr| match attr.parse_meta() {
Ok(syn::Meta::List(l)) => l.nested.iter().find_map(|meta| match meta {
syn::NestedMeta::Meta(syn::Meta::NameValue(v)) => {
if v.path.is_ident("rename_all") {
match &v.lit {
syn::Lit::Str(s) => Some(SerdeAttr::RenameAll(s.value())),
_ => None,
}
} else {
None
}
}
_ => None,
}),
_ => None,
})
.collect::<Vec<_>>()
}

fn types_to_ts(ty: &syn::Type) -> String {
match ty {
syn::Type::Array(_) => String::from("any"),
Expand Down

0 comments on commit 3ca55e7

Please sign in to comment.