1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980pub const SIGNATURE_SIZE_LIMIT: usize = 256;818283#[derive(Debug)]84pub struct SignatureUnit {85 86 pub data: [u8; SIGNATURE_SIZE_LIMIT],87 88 pub len: usize,89}9091impl SignatureUnit {92 93 pub const fn new(name: &'static str) -> SignatureUnit {94 let mut signature = [0_u8; SIGNATURE_SIZE_LIMIT];95 let name = name.as_bytes();96 let name_len = name.len();97 let mut dst_offset = 0;98 crate::make_signature!(@copy(name, signature, name_len, dst_offset));99 SignatureUnit {100 data: signature,101 len: name_len,102 }103 }104 105 pub fn as_str(&self) -> Option<&str> {106 core::str::from_utf8(&self.data[0..self.len]).ok()107 }108}109110111112113114115116117#[macro_export]118macro_rules! make_signature {119 (new $($tt:tt)*) => {120 ($crate::custom_signature::SignatureUnit {121 data: {122 let mut out = [0u8; $crate::custom_signature::SIGNATURE_SIZE_LIMIT];123 let mut dst_offset = 0;124 $crate::make_signature!(@data(out, dst_offset); $($tt)*);125 out126 },127 len: {0 + $crate::make_signature!(@size; $($tt)*)},128 })129 };130131 (@size;) => {132 0133 };134 (@size; fixed($expr:expr) $($tt:tt)*) => {135 $expr.len() + $crate::make_signature!(@size; $($tt)*)136 };137 (@size; nameof($expr:ty) $($tt:tt)*) => {138 <$expr>::SIGNATURE.len + $crate::make_signature!(@size; $($tt)*)139 };140 (@size; shift_left($expr:expr) $($tt:tt)*) => {141 $crate::make_signature!(@size; $($tt)*) - $expr142 };143144 (@data($dst:ident, $dst_offset:ident);) => {};145 (@data($dst:ident, $dst_offset:ident); fixed($expr:expr) $($tt:tt)*) => {146 {147 let data = $expr.as_bytes();148 let data_len = data.len();149 $crate::make_signature!(@copy(data, $dst, data_len, $dst_offset));150 }151 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)152 };153 (@data($dst:ident, $dst_offset:ident); nameof($expr:ty) $($tt:tt)*) => {154 {155 $crate::make_signature!(@copy(&<$expr>::SIGNATURE.data, $dst, <$expr>::SIGNATURE.len, $dst_offset));156 }157 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)158 };159 (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {160 $dst_offset -= $expr;161 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)162 };163164 (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {165 {166 let mut src_offset = 0;167 let src_len: usize = $src_len;168 while src_offset < src_len {169 $dst[$dst_offset] = $src[src_offset];170 $dst_offset += 1;171 src_offset += 1;172 }173 }174 }175}176177#[cfg(test)]178mod test {179 use core::str::from_utf8;180181 use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit};182183 trait Name {184 const SIGNATURE: SignatureUnit;185186 fn name() -> &'static str {187 from_utf8(&Self::SIGNATURE.data[..Self::SIGNATURE.len]).expect("bad utf-8")188 }189 }190191 impl Name for u8 {192 const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint8"));193 }194 impl Name for u32 {195 const SIGNATURE: SignatureUnit = make_signature!(new fixed("uint32"));196 }197 impl<T: Name> Name for Vec<T> {198 const SIGNATURE: SignatureUnit = make_signature!(new nameof(T) fixed("[]"));199 }200 impl<A: Name, B: Name> Name for (A, B) {201 const SIGNATURE: SignatureUnit =202 make_signature!(new fixed("(") nameof(A) fixed(",") nameof(B) fixed(")"));203 }204 impl<A: Name> Name for (A,) {205 const SIGNATURE: SignatureUnit =206 make_signature!(new fixed("(") nameof(A) fixed(",") shift_left(1) fixed(")"));207 }208209 struct MaxSize();210 impl Name for MaxSize {211 const SIGNATURE: SignatureUnit = SignatureUnit {212 data: [b'!'; SIGNATURE_SIZE_LIMIT],213 len: SIGNATURE_SIZE_LIMIT,214 };215 }216217 #[test]218 fn simple() {219 assert_eq!(u8::name(), "uint8");220 assert_eq!(u32::name(), "uint32");221 }222223 #[test]224 fn vector_of_simple() {225 assert_eq!(<Vec<u8>>::name(), "uint8[]");226 assert_eq!(<Vec<u32>>::name(), "uint32[]");227 }228229 #[test]230 fn vector_of_vector() {231 assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");232 }233234 #[test]235 fn tuple_of_simple() {236 assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");237 }238239 #[test]240 fn tuple_of_tuple() {241 assert_eq!(242 <((u32, u8), (u8, u32))>::name(),243 "((uint32,uint8),(uint8,uint32))"244 );245 }246247 #[test]248 fn vector_of_tuple() {249 assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");250 }251252 #[test]253 fn tuple_of_vector() {254 assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");255 }256257 #[test]258 fn complex() {259 assert_eq!(260 <(Vec<u32>, (u32, Vec<u8>))>::name(),261 "(uint32[],(uint32,uint8[]))"262 );263 }264265 #[test]266 fn max_size() {267 assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));268 }269270 #[test]271 fn shift() {272 assert_eq!(<(u32,)>::name(), "(uint32)");273 }274275 #[test]276 fn over_max_size() {277 let t = trybuild::TestCases::new();278 t.compile_fail("tests/build_failed/custom_signature_over_max_size.rs");279 }280}