1use core::str::from_utf8;23pub const SIGNATURE_SIZE_LIMIT: usize = 256;45#[derive(Debug)]6pub struct SignaturePreferences {7 pub open_name: Option<SignatureUnit>,8 pub open_delimiter: Option<SignatureUnit>,9 pub param_delimiter: Option<SignatureUnit>,10 pub close_delimiter: Option<SignatureUnit>,11 pub close_name: Option<SignatureUnit>,12}1314#[derive(Debug)]15pub struct FunctionSignature {16 pub unit: SignatureUnit,17 preferences: SignaturePreferences,18}1920impl FunctionSignature {21 pub const fn new(preferences: SignaturePreferences) -> FunctionSignature {22 let mut dst = [0_u8; SIGNATURE_SIZE_LIMIT];23 let mut dst_offset = 0;24 if let Some(ref name) = preferences.open_name {25 crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));26 }27 if let Some(ref delimiter) = preferences.open_delimiter {28 crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));29 }30 FunctionSignature {31 unit: SignatureUnit {32 data: dst,33 len: dst_offset,34 },35 preferences,36 }37 }3839 pub const fn add_param(40 signature: FunctionSignature,41 param: SignatureUnit,42 ) -> FunctionSignature {43 let mut dst = signature.unit.data;44 let mut dst_offset = signature.unit.len;45 crate::make_signature!(@copy(param.data, dst, param.len, dst_offset));46 if let Some(ref delimiter) = signature.preferences.param_delimiter {47 crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));48 }49 FunctionSignature {50 unit: SignatureUnit {51 data: dst,52 len: dst_offset,53 },54 ..signature55 }56 }5758 pub const fn done(signature: FunctionSignature, owerride: bool) -> FunctionSignature {59 let mut dst = signature.unit.data;60 let mut dst_offset = signature.unit.len - if owerride { 1 } else { 0 };61 if let Some(ref delimiter) = signature.preferences.close_delimiter {62 crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));63 }64 if let Some(ref name) = signature.preferences.close_name {65 crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));66 }67 FunctionSignature {68 unit: SignatureUnit {69 data: dst,70 len: dst_offset,71 },72 ..signature73 }74 }7576 pub fn as_str(&self) -> &str {77 from_utf8(&self.unit.data[..self.unit.len]).expect("bad utf-8")78 }79}8081#[derive(Debug)]82pub struct SignatureUnit {83 pub data: [u8; SIGNATURE_SIZE_LIMIT],84 pub len: usize,85}8687impl SignatureUnit {88 pub const fn new(name: &'static str) -> SignatureUnit {89 let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];90 let name = name.as_bytes();91 let name_len = name.len();92 let mut dst_offset = 0;93 crate::make_signature!(@copy(name, signature, name_len, dst_offset));94 SignatureUnit {95 data: signature,96 len: name_len,97 }98 }99}100101#[macro_export]102#[allow(missing_docs)]103macro_rules! make_signature { 104 (new fn($func:expr)$(,)+) => {105 {106 let fs = FunctionSignature::new($func);107 let fs = FunctionSignature::done(fs, false);108 fs109 }110 };111 (new fn($func:expr), $($tt:tt,)*) => {112 {113 let fs = FunctionSignature::new($func);114 let fs = make_signature!(@param; fs, $($tt),*);115 fs116 }117 };118119 (@param; $func:expr) => {120 FunctionSignature::done($func, true)121 };122 (@param; $func:expr, $param:expr) => {123 make_signature!(@param; FunctionSignature::add_param($func, $param))124 };125 (@param; $func:expr, $param:expr, $($tt:tt),*) => {126 make_signature!(@param; FunctionSignature::add_param($func, $param), $($tt),*)127 };128129 (new $($tt:tt)*) => {130 const SIGNATURE: SignatureUnit = SignatureUnit {131 data: {132 let mut out = [0u8; SIGNATURE_SIZE_LIMIT];133 let mut dst_offset = 0;134 make_signature!(@data(out, dst_offset); $($tt)*);135 out136 },137 len: {0 + make_signature!(@size; $($tt)*)},138 };139 };140141 (@size;) => {142 0143 };144 (@size; fixed($expr:expr) $($tt:tt)*) => {145 $expr.len() + make_signature!(@size; $($tt)*)146 };147 (@size; nameof($expr:ty) $($tt:tt)*) => {148 <$expr>::SIGNATURE.len + make_signature!(@size; $($tt)*)149 };150 (@size; shift_left($expr:expr) $($tt:tt)*) => {151 make_signature!(@size; $($tt)*) - $expr152 };153154 (@data($dst:ident, $dst_offset:ident);) => {};155 (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {156 {157 let data = $expr.as_bytes();158 let data_len = data.len();159 make_signature!(@copy(data, $dst, data_len, $dst_offset));160 }161 make_signature!(@data($dst, $dst_offset); $($tt)*)162 };163 (@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {164 {165 make_signature!(@copy(&<$expr>::SIGNATURE.data, $dst, <$expr>::SIGNATURE.len, $dst_offset));166 }167 make_signature!(@data($dst, $dst_offset); $($tt)*)168 };169 (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {170 $dst_offset -= $expr;171 make_signature!(@data($dst, $dst_offset); $($tt)*)172 };173174 (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {175 {176 let mut src_offset = 0;177 let src_len: usize = $src_len;178 while src_offset < src_len {179 $dst[$dst_offset] = $src[src_offset];180 $dst_offset += 1;181 src_offset += 1;182 }183 }184 }185}186187#[cfg(test)]188mod test {189 use core::str::from_utf8;190191 use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit, FunctionSignature, SignaturePreferences};192193 trait Name {194 const SIGNATURE: SignatureUnit;195196 fn name() -> &'static str {197 from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")198 }199 }200201 impl Name for u8 {202 make_signature!(new fixed("uint8"));203 }204 impl Name for u32 {205 make_signature!(new fixed("uint32"));206 }207 impl<T: Name> Name for Vec<T> {208 make_signature!(new nameof(T) fixed("[]"));209 }210 impl<A: Name, B: Name> Name for (A, B) {211 make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));212 }213 impl<A: Name> Name for (A,) {214 make_signature!(new fixed("(") nameof(A) fixed(",") shift_left(1) fixed(")"));215 }216217 struct MaxSize();218 impl Name for MaxSize {219 const SIGNATURE: SignatureUnit = SignatureUnit {220 data: [b'!'; SIGNATURE_SIZE_LIMIT],221 len: SIGNATURE_SIZE_LIMIT,222 };223 }224225 const SIGNATURE_PREFERENCES: SignaturePreferences = SignaturePreferences {226 open_name: Some(SignatureUnit::new("some_funk")),227 open_delimiter: Some(SignatureUnit::new("(")),228 param_delimiter: Some(SignatureUnit::new(",")),229 close_delimiter: Some(SignatureUnit::new(")")),230 close_name: None,231 };232233 #[test]234 fn simple() {235 assert_eq!(u8::name(), "uint8");236 assert_eq!(u32::name(), "uint32");237 }238239 #[test]240 fn vector_of_simple() {241 assert_eq!(<Vec<u8>>::name(), "uint8[]");242 assert_eq!(<Vec<u32>>::name(), "uint32[]");243 }244245 #[test]246 fn vector_of_vector() {247 assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");248 }249250 #[test]251 fn tuple_of_simple() {252 assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");253 }254255 #[test]256 fn tuple_of_tuple() {257 assert_eq!(258 <((u32, u8), (u8, u32))>::name(),259 "((uint32,uint8),(uint8,uint32))"260 );261 }262263 #[test]264 fn vector_of_tuple() {265 assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");266 }267268 #[test]269 fn tuple_of_vector() {270 assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");271 }272273 #[test]274 fn complex() {275 assert_eq!(276 <(Vec<u32>, (u32, Vec<u8>))>::name(),277 "(uint32[],(uint32,uint8[]))"278 );279 }280281 #[test]282 fn max_size() {283 assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));284 }285286 287 288 289 290 291292 #[test]293 fn make_func_without_args() {294 const SIG: FunctionSignature = make_signature!(295 new fn(SIGNATURE_PREFERENCES),296 );297 let name = SIG.as_str();298 similar_asserts::assert_eq!(name, "some_funk()");299 }300301 #[test]302 fn make_func_with_1_args() {303 const SIG: FunctionSignature = make_signature!(304 new fn(SIGNATURE_PREFERENCES),305 (<u8>::SIGNATURE),306 );307 let name = SIG.as_str();308 similar_asserts::assert_eq!(name, "some_funk(uint8)");309 }310311 #[test]312 fn make_func_with_2_args() {313 const SIG: FunctionSignature = make_signature!(314 new fn(SIGNATURE_PREFERENCES),315 (u8::SIGNATURE),316 (<Vec<u32>>::SIGNATURE),317 );318 let name = SIG.as_str();319 similar_asserts::assert_eq!(name, "some_funk(uint8,uint32[])");320 }321322 #[test]323 fn make_func_with_3_args() {324 const SIG: FunctionSignature = make_signature!(325 new fn(SIGNATURE_PREFERENCES),326 (<u8>::SIGNATURE),327 (<u32>::SIGNATURE),328 (<Vec<u32>>::SIGNATURE),329 );330 let name = SIG.as_str();331 similar_asserts::assert_eq!(name, "some_funk(uint8,uint32,uint32[])");332 }333334 #[test]335 fn make_slice_from_signature() {336 const SIG: FunctionSignature = make_signature!(337 new fn(SIGNATURE_PREFERENCES),338 (<u8>::SIGNATURE),339 (<u32>::SIGNATURE),340 (<Vec<u32>>::SIGNATURE),341 );342 const NAME: [u8; SIG.unit.len] = {343 let mut name: [u8; SIG.unit.len] = [0; SIG.unit.len];344 let mut i = 0;345 while i < SIG.unit.len {346 name[i] = SIG.unit.data[i];347 i += 1;348 }349 name350 };351 similar_asserts::assert_eq!(&NAME, b"some_funk(uint8,uint32,uint32[])");352 }353354 #[test]355 fn shift() {356 assert_eq!(<(u32,)>::name(), "(uint32)");357 }358}