Skip to content

Commit

Permalink
sort define_service (#441)
Browse files Browse the repository at this point in the history
  • Loading branch information
chenyan-dfinity authored Jun 30, 2023
1 parent e73a8c9 commit f1d573c
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 29 deletions.
7 changes: 3 additions & 4 deletions rust/candid/src/parser/grammar.lalrpop
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::types::value::{IDLField, IDLValue, IDLArgs, VariantValue};
use crate::types::{TypeEnv, FuncMode};
use super::typing::check_unique;
use crate::utils::check_unique;
use super::types::{IDLType, PrimType, TypeField, FuncType, Binding, Dec, IDLProg, IDLTypes};
use super::test::{Assert, Input, Test};
use super::token::{Token, error2, LexicalError, Span};
Expand Down Expand Up @@ -241,9 +241,8 @@ FuncMode: FuncMode = {
ActorTyp: Vec<Binding> = {
"{" <mut fs:Sp<SepBy<MethTyp, ";">>> "}" =>? {
let span = fs.1.clone();
fs.0.sort_unstable_by_key(|Binding { id, .. }| id.clone());
let labs: Vec<_> = fs.0.iter().map(|f| f.id.clone()).collect();
check_unique(labs.iter()).map_err(|e| error2(e, span))?;
fs.0.sort_unstable_by(|a,b| a.id.partial_cmp(&b.id).unwrap());
check_unique(fs.0.iter().map(|f| &f.id)).map_err(|e| error2(e, span))?;
Ok(fs.0)
}
}
Expand Down
19 changes: 0 additions & 19 deletions rust/candid/src/parser/typing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,25 +100,6 @@ pub fn check_type(env: &Env, t: &IDLType) -> Result<Type> {
}
}

pub fn check_unique<'a, I, T>(sorted: I) -> Result<()>
where
T: 'a + PartialEq + std::fmt::Display,
I: Iterator<Item = &'a T>,
{
let mut prev: Option<&T> = None;
for lab in sorted {
if let Some(prev) = prev {
if lab == prev {
return Err(Error::msg(format!(
"label '{lab}' hash collision with '{prev}'"
)));
}
}
prev = Some(lab);
}
Ok(())
}

fn check_fields(env: &Env, fs: &[TypeField]) -> Result<Vec<Field>> {
// field label duplication is checked in the parser
let mut res = Vec::new();
Expand Down
11 changes: 8 additions & 3 deletions rust/candid/src/types/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,9 +435,14 @@ macro_rules! func {
///
/// `service!{ "f": func!((HttpRequest) -> ()) }` expands to `Type(Rc::new(TypeInner::Service(...)))`
macro_rules! service {
{ $($meth:tt : $ty:expr);* } => {
Into::<$crate::types::Type>::into($crate::types::TypeInner::Service(vec![ $(($meth.to_string(), $ty)),* ]))
}
{ $($meth:tt : $ty:expr);* } => {{
let mut ms = vec![ $(($meth.to_string(), $ty)),* ];
ms.sort_unstable_by(|a, b| a.0.as_str().partial_cmp(b.0.as_str()).unwrap());
if let Err(e) = $crate::utils::check_unique(ms.iter().map(|m| &m.0)) {
panic!(e);
}
Into::<$crate::types::Type>::into($crate::types::TypeInner::Service(ms))
}}
}

#[derive(Debug, PartialEq, TryFromPrimitive)]
Expand Down
23 changes: 21 additions & 2 deletions rust/candid/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,34 @@
use crate::de::IDLDeserialize;
use crate::ser::IDLBuilder;
use crate::{CandidType, Result};
use crate::{CandidType, Error, Result};
use serde::de::Deserialize;

#[cfg(feature = "parser")]
use crate::{check_prog, pretty_check_file};
#[cfg(feature = "parser")]
use crate::{pretty_parse, types::Type, Error, TypeEnv};
use crate::{pretty_parse, types::Type, TypeEnv};
#[cfg(feature = "parser")]
use std::path::Path;

pub fn check_unique<'a, I, T>(sorted: I) -> Result<()>
where
T: 'a + PartialEq + std::fmt::Display,
I: Iterator<Item = &'a T>,
{
let mut prev: Option<&T> = None;
for lab in sorted {
if let Some(prev) = prev {
if lab == prev {
return Err(Error::msg(format!(
"label '{lab}' hash collision with '{prev}'"
)));
}
}
prev = Some(lab);
}
Ok(())
}

#[cfg_attr(docsrs, doc(cfg(feature = "parser")))]
#[cfg(feature = "parser")]
pub enum CandidSource<'a> {
Expand Down
2 changes: 1 addition & 1 deletion rust/candid/tests/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn test_reference() {
);
let bytes = hex("4449444c016a00017f000100010100016d");
test_decode(&bytes, &None::<CustomFunc>);
define_service!(MyService: { "f": CustomFunc::ty(); "g": func!(() -> () query) });
define_service!(MyService: { "g": func!(() -> () query); "f": CustomFunc::ty() });
all_check(
MyService::new(principal),
"4449444c0369020166010167026a00017d006a0000010101000103caffee",
Expand Down

0 comments on commit f1d573c

Please sign in to comment.