Skip to content

Commit

Permalink
fix rename proc macro to take any string (#522)
Browse files Browse the repository at this point in the history
* fix rename proc macro to take any string

* add pretty_wrap
  • Loading branch information
chenyan-dfinity committed Feb 14, 2024
1 parent 495526e commit 8f96d79
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 28 deletions.
19 changes: 19 additions & 0 deletions rust/candid/tests/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,25 @@ fn test_field_rename() {
}
let v = E1::Field2;
all_check(v, "4449444c016b02617f627f010001");
#[derive(CandidType, Deserialize, PartialEq, Debug)]
enum E2 {
#[serde(rename = "1-2 + 3")]
A(i8),
#[serde(rename = "a-b")]
B(u8),
}
all_check(E2::A(42), "4449444c016b02b684a7027bb493ee970d770100012a");
#[derive(CandidType, Deserialize, PartialEq, Debug)]
struct S2 {
#[serde(rename = "1-2 + 3")]
a: i8,
#[serde(rename = "a-b")]
b: u8,
}
all_check(
S2 { a: 42, b: 42 },
"4449444c016c02b684a7027bb493ee970d7701002a2a",
);
}

#[test]
Expand Down
28 changes: 16 additions & 12 deletions rust/candid_derive/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub(crate) fn derive_idl_type(

struct Variant {
real_ident: syn::Ident,
renamed_ident: syn::Ident,
renamed_ident: String,
hash: u32,
ty: TokenStream,
members: Vec<Ident>,
Expand Down Expand Up @@ -100,11 +100,12 @@ fn enum_from_ast(
let id = variant.ident.clone();
let attrs = get_attrs(&variant.attrs);
let (renamed_ident, hash) = match attrs.rename {
Some(ref rename) => (
proc_macro2::Ident::new(rename, proc_macro2::Span::call_site()),
idl_hash(rename),
),
None => (id.clone(), idl_hash(&id.unraw().to_string())),
Some(ref rename) => (rename.clone(), idl_hash(rename)),
None => {
let id = id.unraw().to_string();
let hash = idl_hash(&id);
(id, hash)
}
};
let (ty, idents, _, style) = struct_from_ast(&variant.fields, custom_candid_path);
Variant {
Expand All @@ -122,9 +123,7 @@ fn enum_from_ast(
assert_eq!(unique.len(), fs.len());
fs.sort_unstable_by_key(|Variant { hash, .. }| *hash);

let id = fs
.iter()
.map(|Variant { renamed_ident, .. }| renamed_ident.unraw().to_string());
let id = fs.iter().map(|Variant { renamed_ident, .. }| renamed_ident);
let ty = fs.iter().map(|Variant { ty, .. }| ty);
let candid = candid_path(custom_candid_path);
let ty_gen = quote! {
Expand Down Expand Up @@ -234,20 +233,24 @@ fn struct_from_ast(
#[derive(Clone)]
enum Ident {
Named(syn::Ident),
Renamed(String),
Unnamed(u32),
}

impl Ident {
fn to_token(&self) -> TokenStream {
match self {
Ident::Named(ident) => quote! { #ident },
Ident::Unnamed(ref i) => syn::parse_str::<TokenStream>(&format!("{i}")).unwrap(),
Ident::Renamed(_) => unreachable!(),
}
}
}
impl std::fmt::Display for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match *self {
Ident::Named(ref ident) => f.write_fmt(format_args!("{ident}")),
Ident::Renamed(ref ident) => f.write_fmt(format_args!("{ident}")),
Ident::Unnamed(ref i) => f.write_fmt(format_args!("{}", *i)),
}
}
Expand Down Expand Up @@ -336,9 +339,7 @@ fn fields_from_ast(
let real_ident = Ident::Named(ident.clone());
match attrs.rename {
Some(ref renamed) => {
let ident =
proc_macro2::Ident::new(renamed, proc_macro2::Span::call_site());
let renamed_ident = Ident::Named(ident);
let renamed_ident = Ident::Renamed(renamed.clone());
(real_ident, renamed_ident, idl_hash(renamed))
}
None => (
Expand Down Expand Up @@ -370,6 +371,9 @@ fn fields_from_ast(
let name = id.unraw().to_string();
quote! { #candid::types::Label::Named(#name.to_string()).into() }
}
Ident::Renamed(ref id) => {
quote! { #candid::types::Label::Named(#id.to_string()).into() }
}
Ident::Unnamed(ref i) => quote! { #candid::types::Label::Id(#i).into() },
});
let ty = fs.iter().map(|Field { ty, .. }| ty);
Expand Down
13 changes: 13 additions & 0 deletions rust/candid_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,19 @@ where
})
}

/// Wrap the parser error and pretty print the error message.
/// ```
/// use candid_parser::{pretty_wrap, parse_idl_args};
/// pretty_wrap("parse IDL args", "(42, record {})", parse_idl_args)?;
/// # Ok::<(), candid_parser::Error>(())
/// ```
pub fn pretty_wrap<T>(name: &str, str: &str, f: impl FnOnce(&str) -> Result<T>) -> Result<T> {
f(str).or_else(|e| {
pretty_diagnose(name, str, &e)?;
Err(e)
})
}

pub fn pretty_diagnose(file_name: &str, source: &str, e: &Error) -> Result<()> {
let writer = StandardStream::stderr(term::termcolor::ColorChoice::Auto);
let config = term::Config::default();
Expand Down
2 changes: 1 addition & 1 deletion rust/candid_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@
#![cfg_attr(docsrs, feature(doc_cfg))]

pub mod error;
pub use error::{pretty_parse, Error, Result};
pub use error::{pretty_parse, pretty_wrap, Error, Result};

pub mod bindings;
pub mod grammar;
Expand Down
21 changes: 6 additions & 15 deletions tools/didc/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use anyhow::{bail, Result};
use candid_parser::candid::types::{subtype, Type};
use candid_parser::{
error::pretty_diagnose,
parse_idl_args, parse_idl_value, pretty_check_file, pretty_parse,
parse_idl_args, parse_idl_value, pretty_check_file, pretty_parse, pretty_wrap,
types::{IDLType, IDLTypes},
typing::ast_to_type,
Error, IDLArgs, IDLValue, TypeEnv,
Expand Down Expand Up @@ -153,10 +152,7 @@ impl TypeAnnotation {
}

fn parse_args(str: &str) -> Result<IDLArgs, Error> {
parse_idl_args(str).map_err(|e| {
let _ = pretty_diagnose("candid arguments", str, &e);
e
})
pretty_wrap("candid arguments", str, parse_idl_args)
}
fn parse_types(str: &str) -> Result<IDLTypes, Error> {
pretty_parse("type annotations", str)
Expand Down Expand Up @@ -289,15 +285,10 @@ fn main() -> Result<()> {
.filter(|c| !c.is_whitespace())
.collect::<String>(),
)?,
"blob" => {
match parse_idl_value(&blob).map_err(|e| {
let _ = pretty_diagnose("blob", &blob, &e);
e
})? {
IDLValue::Blob(blob) => blob,
_ => unreachable!(),
}
}
"blob" => match pretty_wrap("blob", &blob, parse_idl_value)? {
IDLValue::Blob(blob) => blob,
_ => unreachable!(),
},
_ => unreachable!(),
};
let value = if annotate.is_empty() {
Expand Down

0 comments on commit 8f96d79

Please sign in to comment.