1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071pub const SIGNATURE_SIZE_LIMIT: usize = 256;727374#[derive(Debug)]75pub struct SignatureUnit {76 77 pub data: [u8; SIGNATURE_SIZE_LIMIT],78 79 pub len: usize,80}8182impl SignatureUnit {83 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 96 pub fn as_str(&self) -> Option<&str> {97 core::str::from_utf8(&self.data[0..self.len]).ok()98 }99}100101102103104105106107108#[macro_export]109macro_rules! make_signature {110 (new $($tt:tt)*) => {111 ($crate::custom_signature::SignatureUnit {112 data: {113 let mut out = [0u8; $crate::custom_signature::SIGNATURE_SIZE_LIMIT];114 let mut dst_offset = 0;115 $crate::make_signature!(@data(out, dst_offset); $($tt)*);116 out117 },118 len: {0 + $crate::make_signature!(@size; $($tt)*)},119 })120 };121122 (@size;) => {123 0124 };125 (@size; fixed($expr:expr) $($tt:tt)*) => {126 $expr.len() + $crate::make_signature!(@size; $($tt)*)127 };128 (@size; nameof($expr:expr) $($tt:tt)*) => {129 $expr.len + $crate::make_signature!(@size; $($tt)*)130 };131 (@size; numof($expr:expr) $($tt:tt)*) => {132 {133 let mut out = 0;134 let mut v = $expr;135 if v == 0 {136 out = 1;137 } else {138 while v > 0 {139 out += 1;140 v /= 10;141 }142 }143 out144 } + $crate::make_signature!(@size; $($tt)*)145 };146 (@size; shift_left($expr:expr) $($tt:tt)*) => {147 $crate::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 $crate::make_signature!(@copy(data, $dst, data_len, $dst_offset));156 }157 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)158 };159 (@data($dst:ident, $dst_offset:ident); nameof($expr:expr) $($tt:tt)*) => {160 {161 $crate::make_signature!(@copy(&$expr.data, $dst, $expr.len, $dst_offset));162 }163 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)164 };165 (@data($dst:ident, $dst_offset:ident); numof($expr:expr) $($tt:tt)*) => {166 {167 let mut v = $expr;168 let mut need_to_swap = 0;169 if v == 0 {170 $dst[$dst_offset] = b'0';171 $dst_offset += 1;172 } else {173 while v > 0 {174 let n = (v % 10) as u8;175 $dst[$dst_offset] = b'0' + n;176 v /= 10;177 need_to_swap += 1;178 $dst_offset += 1;179 }180 }181 let mut i = 0;182 #[allow(clippy::manual_swap)]183 while i < need_to_swap / 2 {184 let a = $dst_offset - i - 1;185 let b = $dst_offset - need_to_swap + i;186 let v = $dst[a];187 $dst[a] = $dst[b];188 $dst[b] = v;189 i += 1;190 }191 }192 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)193 };194 (@data($dst:ident, $dst_offset:ident); shift_left($expr:expr) $($tt:tt)*) => {195 $dst_offset -= $expr;196 $crate::make_signature!(@data($dst, $dst_offset); $($tt)*)197 };198199 (@copy($src:expr, $dst:expr, $src_len:expr, $dst_offset:ident)) => {200 {201 let mut src_offset = 0;202 let src_len: usize = $src_len;203 while src_offset < src_len {204 $dst[$dst_offset] = $src[src_offset];205 $dst_offset += 1;206 src_offset += 1;207 }208 }209 }210}211212#[cfg(test)]213mod test {214 use core::str::from_utf8;215216 use super::{SIGNATURE_SIZE_LIMIT, SignatureUnit};217218 trait Name {219 const NAME: SignatureUnit;220221 fn name() -> &'static str {222 from_utf8(&Self::NAME.data[..Self::NAME.len]).expect("bad utf-8")223 }224 }225226 impl Name for u8 {227 const NAME: SignatureUnit = make_signature!(new fixed("uint8"));228 }229 impl Name for u32 {230 const NAME: SignatureUnit = make_signature!(new fixed("uint32"));231 }232 impl<T: Name> Name for Vec<T> {233 const NAME: SignatureUnit = make_signature!(new nameof(T::NAME) fixed("[]"));234 }235 impl<A: Name, B: Name> Name for (A, B) {236 const NAME: SignatureUnit =237 make_signature!(new fixed("(") nameof(A::NAME) fixed(",") nameof(B::NAME) fixed(")"));238 }239 impl<A: Name> Name for (A,) {240 const NAME: SignatureUnit =241 make_signature!(new fixed("(") nameof(A::NAME) fixed(",") shift_left(1) fixed(")"));242 }243 impl<A: Name, const SIZE: usize> Name for [A; SIZE] {244 const NAME: SignatureUnit =245 make_signature!(new nameof(A::NAME) fixed("[") numof(SIZE) fixed("]"));246 }247248 struct MaxSize();249 impl Name for MaxSize {250 const NAME: SignatureUnit = SignatureUnit {251 data: [b'!'; SIGNATURE_SIZE_LIMIT],252 len: SIGNATURE_SIZE_LIMIT,253 };254 }255256 #[test]257 fn simple() {258 assert_eq!(u8::name(), "uint8");259 assert_eq!(u32::name(), "uint32");260 }261262 #[test]263 fn vector_of_simple() {264 assert_eq!(<Vec<u8>>::name(), "uint8[]");265 assert_eq!(<Vec<u32>>::name(), "uint32[]");266 }267268 #[test]269 fn vector_of_vector() {270 assert_eq!(<Vec<Vec<u8>>>::name(), "uint8[][]");271 }272273 #[test]274 fn tuple_of_simple() {275 assert_eq!(<(u32, u8)>::name(), "(uint32,uint8)");276 }277278 #[test]279 fn tuple_of_tuple() {280 assert_eq!(281 <((u32, u8), (u8, u32))>::name(),282 "((uint32,uint8),(uint8,uint32))"283 );284 }285286 #[test]287 fn vector_of_tuple() {288 assert_eq!(<Vec<(u32, u8)>>::name(), "(uint32,uint8)[]");289 }290291 #[test]292 fn tuple_of_vector() {293 assert_eq!(<(Vec<u32>, u8)>::name(), "(uint32[],uint8)");294 }295296 #[test]297 fn complex() {298 assert_eq!(299 <(Vec<u32>, (u32, Vec<u8>))>::name(),300 "(uint32[],(uint32,uint8[]))"301 );302 }303304 #[test]305 fn max_size() {306 assert_eq!(<MaxSize>::name(), "!".repeat(SIGNATURE_SIZE_LIMIT));307 }308309 #[test]310 fn shift() {311 assert_eq!(<(u32,)>::name(), "(uint32)");312 }313314 #[test]315 fn num() {316 assert_eq!(<[u8; 0]>::name(), "uint8[0]");317 assert_eq!(<[u8; 1234]>::name(), "uint8[1234]");318 assert_eq!(<[u8; 12345]>::name(), "uint8[12345]");319 }320321 #[test]322 fn over_max_size() {323 let t = trybuild::TestCases::new();324 t.compile_fail("tests/build_failed/custom_signature_over_max_size.rs");325 }326}