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 data: [u8; SIGNATURE_SIZE_LIMIT],17 pub len: usize,1819 preferences: SignaturePreferences,20}2122impl FunctionSignature {23 pub const fn new(preferences: SignaturePreferences) -> FunctionSignature {24 let mut dst = [0_u8; SIGNATURE_SIZE_LIMIT];25 let mut dst_offset = 0;26 if let Some(ref name) = preferences.open_name {27 crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));28 }29 if let Some(ref delimiter) = preferences.open_delimiter {30 crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));31 }32 FunctionSignature {33 data: dst,34 len: dst_offset,35 preferences,36 }37 }3839 pub const fn add_param(40 signature: FunctionSignature,41 param: SignatureUnit,42 ) -> FunctionSignature {43 let mut dst = signature.data;44 let mut dst_offset = signature.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 data: dst,51 len: dst_offset,52 ..signature53 }54 }5556 pub const fn done(signature: FunctionSignature, owerride: bool) -> FunctionSignature {57 let mut dst = signature.data;58 let mut dst_offset = signature.len - if owerride { 1 } else { 0 };59 if let Some(ref delimiter) = signature.preferences.close_delimiter {60 crate::make_signature!(@copy(delimiter.data, dst, delimiter.len, dst_offset));61 }62 if let Some(ref name) = signature.preferences.close_name {63 crate::make_signature!(@copy(name.data, dst, name.len, dst_offset));64 }65 FunctionSignature {66 data: dst,67 len: dst_offset,68 ..signature69 }70 }7172 pub fn as_str(&self) -> &str {73 from_utf8(&self.data[..self.len]).expect("bad utf-8")74 }75}7677#[derive(Debug)]78pub struct SignatureUnit {79 pub data: [u8; SIGNATURE_SIZE_LIMIT],80 pub len: usize,81}8283impl SignatureUnit {84 pub const fn new(name: &'static str) -> SignatureUnit {85 let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];86 let name = name.as_bytes();87 let name_len = name.len();88 let mut dst_offset = 0;89 crate::make_signature!(@copy(name, signature, name_len, dst_offset));90 SignatureUnit {91 data: signature,92 len: name_len,93 }94 }95}9697#[macro_export]98#[allow(missing_docs)]99macro_rules! make_signature { 100 (new fn($func:expr)$(,)+) => {101 {102 let fs = FunctionSignature::new($func);103 let fs = FunctionSignature::done(fs, false);104 fs105 }106 };107 (new fn($func:expr), $($tt:tt,)*) => {108 {109 let fs = FunctionSignature::new($func);110 let fs = make_signature!(@param; fs, $($tt),*);111 fs112 }113 };114115 (@param; $func:expr) => {116 FunctionSignature::done($func, true)117 };118 (@param; $func:expr, $param:expr) => {119 make_signature!(@param; FunctionSignature::add_param($func, $param))120 };121 (@param; $func:expr, $param:expr, $($tt:tt),*) => {122 make_signature!(@param; FunctionSignature::add_param($func, $param), $($tt),*)123 };124125 (new $($tt:tt)*) => {126 const SIGNATURE: SignatureUnit = SignatureUnit {127 data: {128 let mut out = [0u8; SIGNATURE_SIZE_LIMIT];129 let mut dst_offset = 0;130 make_signature!(@data(out, dst_offset); $($tt)*);131 out132 },133 len: {0 + make_signature!(@size; $($tt)*)},134 };135 };136137 (@size;) => {138 0139 };140 (@size; fixed($expr:expr) $($tt:tt)*) => {141 $expr.len() + make_signature!(@size; $($tt)*)142 };143 (@size; nameof($expr:ty) $($tt:tt)*) => {144 <$expr>::SIGNATURE.len + make_signature!(@size; $($tt)*)145 };146 (@size; shift_left($expr:expr) $($tt:tt)*) => {147 make_signature!(@size; $($tt)*) - $expr148 };149150 (@data($dst:ident, $dst_offset:ident);) => {};151 (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {152 {153 let data = $expr.as_bytes();154 let data_len = data.len();155 make_signature!(@copy(data, $dst, data_len, $dst_offset));156 }157 make_signature!(@data($dst, $dst_offset); $($tt)*)158 };159 (@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {160 {161 make_signature!(@copy(&<$expr>::SIGNATURE.data, $dst, <$expr>::SIGNATURE.len, $dst_offset));162 }163 make_signature!(@data($dst, $dst_offset); $($tt)*)164 };165 (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {166 $dst_offset -= $expr;167 make_signature!(@data($dst, $dst_offset); $($tt)*)168 };169170 (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {171 {172 let mut src_offset = 0;173 let src_len: usize = $src_len;174 while src_offset < src_len {175 $dst[$dst_offset] = $src[src_offset];176 $dst_offset += 1;177 src_offset += 1;178 }179 }180 }181}182183#[cfg(test)]184mod test {185 use core::str::from_utf8;186187 use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit, FunctionSignature, SignaturePreferences};188189 trait Name {190 const SIGNATURE: SignatureUnit;191192 fn name() -> &'static str {193 from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")194 }195 }196197 impl Name for u8 {198 make_signature!(new fixed("uint8"));199 }200 impl Name for u32 {201 make_signature!(new fixed("uint32"));202 }203 impl<T: Name> Name for Vec<T> {204 make_signature!(new nameof(T) fixed("[]"));205 }206 impl<A: Name, B: Name> Name for (A, B) {207 make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));208 }209 impl<A: Name> Name for (A,) {210 make_signature!(new fixed("(") nameof(A) fixed(",") shift_left(1) fixed(")"));211 }212213 struct MaxSize();214 impl Name for MaxSize {215 const SIGNATURE: SignatureUnit = SignatureUnit {216 data: [b'!'; SIGNATURE_SIZE_LIMIT],217 len: SIGNATURE_SIZE_LIMIT,218 };219 }220221 const SIGNATURE_PREFERENCES: SignaturePreferences = SignaturePreferences {222 open_name: Some(SignatureUnit::new("some_funk")),223 open_delimiter: Some(SignatureUnit::new("(")),224 param_delimiter: Some(SignatureUnit::new(",")),225 close_delimiter: Some(SignatureUnit::new(")")),226 close_name: None,227 };228229 #[test]230 fn simple() {231 assert_eq!(u8::name(), "uint8");232 assert_eq!(u32::name(), "uint32");233 }234235 #[test]236 fn vector_of_simple() {237 assert_eq!(<Vec<u8>>::name(), "uint8[]");238 assert_eq!(<Vec<u32>>::name(), "uint32[]");239 }240241 #[test]242 fn vector_of_vector() {243 assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");244 }245246 #[test]247 fn tuple_of_simple() {248 assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");249 }250251 #[test]252 fn tuple_of_tuple() {253 assert_eq!(254 <((u32, u8), (u8, u32))>::name(),255 "((uint32,uint8),(uint8,uint32))"256 );257 }258259 #[test]260 fn vector_of_tuple() {261 assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");262 }263264 #[test]265 fn tuple_of_vector() {266 assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");267 }268269 #[test]270 fn complex() {271 assert_eq!(272 <(Vec<u32>, (u32, Vec<u8>))>::name(),273 "(uint32[],(uint32,uint8[]))"274 );275 }276277 #[test]278 fn max_size() {279 assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));280 }281282 283 284 285 286 287288 #[test]289 fn make_func_without_args() {290 const SIG: FunctionSignature = make_signature!(291 new fn(SIGNATURE_PREFERENCES),292 );293 let name = SIG.as_str();294 similar_asserts::assert_eq!(name, "some_funk()");295 }296297 #[test]298 fn make_func_with_1_args() {299 const SIG: FunctionSignature = make_signature!(300 new fn(SIGNATURE_PREFERENCES),301 (<u8>::SIGNATURE),302 );303 let name = SIG.as_str();304 similar_asserts::assert_eq!(name, "some_funk(uint8)");305 }306307 #[test]308 fn make_func_with_2_args() {309 const SIG: FunctionSignature = make_signature!(310 new fn(SIGNATURE_PREFERENCES),311 (u8::SIGNATURE),312 (<Vec<u32>>::SIGNATURE),313 );314 let name = SIG.as_str();315 similar_asserts::assert_eq!(name, "some_funk(uint8,uint32[])");316 }317318 #[test]319 fn make_func_with_3_args() {320 const SIG: FunctionSignature = make_signature!(321 new fn(SIGNATURE_PREFERENCES),322 (<u8>::SIGNATURE),323 (<u32>::SIGNATURE),324 (<Vec<u32>>::SIGNATURE),325 );326 let name = SIG.as_str();327 similar_asserts::assert_eq!(name, "some_funk(uint8,uint32,uint32[])");328 }329330 #[test]331 fn make_slice_from_signature() {332 const SIG: FunctionSignature = make_signature!(333 new fn(SIGNATURE_PREFERENCES),334 (<u8>::SIGNATURE),335 (<u32>::SIGNATURE),336 (<Vec<u32>>::SIGNATURE),337 );338 const NAME: [u8; SIG.len] = {339 let mut name: [u8; SIG.len] = [0; SIG.len];340 let mut i = 0;341 while i < SIG.len {342 name[i] = SIG.data[i];343 i += 1;344 }345 name346 };347 similar_asserts::assert_eq!(&NAME, b"some_funk(uint8,uint32,uint32[])");348 }349350 #[test]351 fn shift() {352 assert_eq!(<(u32,)>::name(), "(uint32)");353 }354}