1use core::str::from_utf8;23pub const SIGNATURE_SIZE_LIMIT: usize = 256;45pub trait Name {6 const SIGNATURE: [u8; SIGNATURE_SIZE_LIMIT];7 const SIGNATURE_LEN: usize;89 fn name() -> &'static str {10 from_utf8(&Self::SIGNATURE[..Self::SIGNATURE_LEN]).expect("bad utf-8")11 }12}1314#[derive(Debug)]15pub struct FunctionSignature {16 pub signature: [u8; SIGNATURE_SIZE_LIMIT],17 pub signature_len: usize,18}1920impl FunctionSignature {21 pub const fn new(name: &'static FunctionName) -> FunctionSignature {22 let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];23 let name_len = name.signature_len;24 let name = name.signature;25 let mut dst_offset = 0;26 let bracket_open = {27 let mut b = [0_u8; SIGNATURE_SIZE_LIMIT];28 b[0] = b"("[0];29 b30 };31 crate::make_signature!(@copy(name, signature, name_len, dst_offset));32 crate::make_signature!(@copy(bracket_open, signature, 1, dst_offset));33 FunctionSignature {34 signature,35 signature_len: dst_offset,36 }37 }3839 pub const fn add_param(40 signature: FunctionSignature,41 param: ([u8; SIGNATURE_SIZE_LIMIT], usize),42 ) -> FunctionSignature {43 let mut dst = signature.signature;44 let mut dst_offset = signature.signature_len;45 let (param_name, param_len) = param;46 let comma = {47 let mut b = [0_u8; SIGNATURE_SIZE_LIMIT];48 b[0] = b","[0];49 b50 };51 FunctionSignature {52 signature: {53 crate::make_signature!(@copy(param_name, dst, param_len, dst_offset));54 crate::make_signature!(@copy(comma, dst, 1, dst_offset));55 dst56 },57 signature_len: dst_offset,58 }59 }6061 pub const fn done(signature: FunctionSignature, owerride: bool) -> FunctionSignature {62 let mut dst = signature.signature;63 let mut dst_offset = signature.signature_len - if owerride { 1 } else { 0 };64 let bracket_close = {65 let mut b = [0_u8; SIGNATURE_SIZE_LIMIT];66 b[0] = b")"[0];67 b68 };69 FunctionSignature {70 signature: {71 crate::make_signature!(@copy(bracket_close, dst, 1, dst_offset));72 dst73 },74 signature_len: dst_offset,75 }76 }7778 79 80 81}8283#[derive(Debug)]84pub struct FunctionName {85 signature: [u8; SIGNATURE_SIZE_LIMIT],86 signature_len: usize,87}8889impl FunctionName {90 pub const fn new(name: &'static str) -> FunctionName {91 let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];92 let name = name.as_bytes();93 let name_len = name.len();94 let mut dst_offset = 0;95 crate::make_signature!(@copy(name, signature, name_len, dst_offset));96 FunctionName {97 signature,98 signature_len: name_len,99 }100 }101}102103#[macro_export]104#[allow(missing_docs)]105macro_rules! make_signature { 106 (new fn($func:expr)$(,)+) => {107 {108 let fs = FunctionSignature::new(& $func);109 let fs = FunctionSignature::done(fs, false);110 fs111 }112 };113 (new fn($func:expr), $($tt:tt)*) => {114 {115 let fs = FunctionSignature::new(& $func);116 let fs = make_signature!(@param; fs, $($tt),*);117 fs118 }119 };120121 (@param; $func:expr) => {122 FunctionSignature::done($func, true)123 };124 (@param; $func:expr, $param:expr) => {125 make_signature!(@param; FunctionSignature::add_param($func, $param))126 };127 (@param; $func:expr, $param:expr, $($tt:tt),*) => {128 make_signature!(@param; FunctionSignature::add_param($func, $param), $($tt),*)129 };130131 (new $($tt:tt)*) => {132 const SIGNATURE: [u8; SIGNATURE_SIZE_LIMIT] = {133 let mut out = [0u8; SIGNATURE_SIZE_LIMIT];134 let mut dst_offset = 0;135 make_signature!(@data(out, dst_offset); $($tt)*);136 out137 };138 const SIGNATURE_LEN: usize = 0 + make_signature!(@size; $($tt)*);139 };140141 142143 (@size;) => {144 0145 };146 (@size; fixed($expr:expr) $($tt:tt)*) => {147 $expr.len() + make_signature!(@size; $($tt)*)148 };149 (@size; nameof($expr:ty) $($tt:tt)*) => {150 <$expr>::SIGNATURE_LEN + make_signature!(@size; $($tt)*)151 };152153 (@data($dst:ident, $dst_offset:ident);) => {};154 (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {155 {156 let data = $expr.as_bytes();157 let data_len = data.len();158 make_signature!(@copy(data, $dst, data_len, $dst_offset));159 }160 make_signature!(@data($dst, $dst_offset); $($tt)*)161 };162 (@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {163 {164 let data = &<$expr>::SIGNATURE;165 let data_len = <$expr>::SIGNATURE_LEN;166 make_signature!(@copy(data, $dst, data_len, $dst_offset));167 }168 make_signature!(@data($dst, $dst_offset); $($tt)*)169 };170171 (@copy($src:ident, $dst:ident, $src_len:expr, $dst_offset:ident)) => {172 {173 let mut src_offset = 0;174 let src_len: usize = $src_len;175 while src_offset < src_len {176 $dst[$dst_offset] = $src[src_offset];177 $dst_offset += 1;178 src_offset += 1;179 }180 }181 }182}183184#[cfg(test)]185mod test {186 use core::str::from_utf8;187188 use frame_support::sp_runtime::app_crypto::sp_core::hexdisplay::AsBytesRef;189190 use super::{Name, SIGNATURE_SIZE_LIMIT, FunctionName, FunctionSignature};191192 impl Name for u8 {193 make_signature!(new fixed("uint8"));194 }195 impl Name for u32 {196 make_signature!(new fixed("uint32"));197 }198 impl<T: Name> Name for Vec<T> {199 make_signature!(new nameof(T) fixed("[]"));200 }201 impl<A: Name, B: Name> Name for (A, B) {202 make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));203 }204205 struct MaxSize();206 impl Name for MaxSize {207 const SIGNATURE: [u8; SIGNATURE_SIZE_LIMIT] = [b'!'; SIGNATURE_SIZE_LIMIT];208 const SIGNATURE_LEN: usize = SIGNATURE_SIZE_LIMIT;209 }210211 #[test]212 fn simple() {213 assert_eq!(u8::name(), "uint8");214 assert_eq!(u32::name(), "uint32");215 }216217 #[test]218 fn vector_of_simple() {219 assert_eq!(<Vec<u8>>::name(), "uint8[]");220 assert_eq!(<Vec<u32>>::name(), "uint32[]");221 }222223 #[test]224 fn vector_of_vector() {225 assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");226 }227228 #[test]229 fn tuple_of_simple() {230 assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");231 }232233 #[test]234 fn tuple_of_tuple() {235 assert_eq!(236 <((u32, u8), (u8, u32))>::name(),237 "((uint32,uint8),(uint8,uint32))"238 );239 }240241 #[test]242 fn vector_of_tuple() {243 assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");244 }245246 #[test]247 fn tuple_of_vector() {248 assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");249 }250251 #[test]252 fn complex() {253 assert_eq!(254 <(Vec<u32>, (u32, Vec<u8>))>::name(),255 "(uint32[],(uint32,uint8[]))"256 );257 }258259 #[test]260 fn max_size() {261 assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));262 }263264 265 266 267 268 269270 #[test]271 fn make_func_without_args() {272 const SOME_FUNK_NAME: FunctionName = FunctionName::new("some_funk");273 const SIG: FunctionSignature = make_signature!(274 new fn(&SOME_FUNK_NAME),275 );276 let name = from_utf8(&SIG.signature[..SIG.signature_len]).unwrap();277 assert_eq!(name, "some_funk()");278 }279280 #[test]281 fn make_func_with_1_args() {282 const SOME_FUNK_NAME: FunctionName = FunctionName::new("some_funk");283 const SIG: FunctionSignature = make_signature!(284 new fn(&SOME_FUNK_NAME),285 (u8::SIGNATURE, u8::SIGNATURE_LEN)286 );287 let name = from_utf8(&SIG.signature[..SIG.signature_len]).unwrap();288 assert_eq!(name, "some_funk(uint8)");289 }290291 #[test]292 fn make_func_with_2_args() {293 const SOME_FUNK_NAME: FunctionName = FunctionName::new("some_funk");294 const SIG: FunctionSignature = make_signature!(295 new fn(&SOME_FUNK_NAME),296 (u8::SIGNATURE, u8::SIGNATURE_LEN)297 (<Vec<u32>>::SIGNATURE, <Vec<u32>>::SIGNATURE_LEN)298 );299 let name = from_utf8(&SIG.signature[..SIG.signature_len]).unwrap();300 assert_eq!(name, "some_funk(uint8,uint32[])");301 }302303 #[test]304 fn make_func_with_3_args() {305 const SOME_FUNK_NAME: FunctionName = FunctionName::new("some_funk");306 const SIG: FunctionSignature = make_signature!(307 new fn(&SOME_FUNK_NAME),308 (u8::SIGNATURE, u8::SIGNATURE_LEN)309 (u32::SIGNATURE, u32::SIGNATURE_LEN)310 (<Vec<u32>>::SIGNATURE, <Vec<u32>>::SIGNATURE_LEN)311 );312 let name = from_utf8(&SIG.signature[..SIG.signature_len]).unwrap();313 assert_eq!(name, "some_funk(uint8,uint32,uint32[])");314 }315316 #[test]317 fn make_slice_from_signature() {318 const SOME_FUNK_NAME: FunctionName = FunctionName::new("some_funk");319 const SIG: FunctionSignature = make_signature!(320 new fn(&SOME_FUNK_NAME),321 (u8::SIGNATURE, u8::SIGNATURE_LEN)322 (u32::SIGNATURE, u32::SIGNATURE_LEN)323 (<Vec<u32>>::SIGNATURE, <Vec<u32>>::SIGNATURE_LEN)324 );325 const NAME: [u8; SIG.signature_len] = {326 let mut name: [u8; SIG.signature_len] = [0; SIG.signature_len];327 let mut i = 0;328 while i < SIG.signature_len {329 name[i] = SIG.signature[i];330 i += 1;331 }332 name333 };334 assert_eq!(&NAME, b"some_funk(uint8,uint32,uint32[])");335 }336}