Plug baseXX into Address.

This commit is contained in:
Adam Ierymenko 2023-03-29 19:28:14 -04:00
parent 07e1923cc7
commit 1c46541452
3 changed files with 41 additions and 7 deletions

View file

@ -9,10 +9,8 @@ use std::str::FromStr;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use zerotier_utils::base24;
use zerotier_utils::error::InvalidParameterError;
use zerotier_utils::hex;
use zerotier_utils::memory;
use zerotier_utils::{base24, base62, hex, memory};
/// A full (V2) ZeroTier address.
///
@ -102,7 +100,17 @@ impl Borrow<[u8; Self::SIZE_BYTES]> for Address {
impl ToString for Address {
#[inline(always)]
fn to_string(&self) -> String {
base24::encode(&self.0)
let mut s = String::with_capacity(48 * 2);
base24::encode_into(&self.0[..4], &mut s);
s.push('-');
base24::encode_into(&self.0[4..8], &mut s);
s.push('-');
base24::encode_into(&self.0[8..12], &mut s);
s.push('-');
base24::encode_into(&self.0[12..16], &mut s);
s.push('-');
base62::encode_into(&self.0[16..], &mut s, 43);
s
}
}
@ -111,7 +119,19 @@ impl FromStr for Address {
#[inline]
fn from_str(s: &str) -> Result<Self, Self::Err> {
base24::decode(s.as_bytes()).and_then(|b| Self::from_bytes(b.as_slice()))
let mut a = Self([0u8; Self::SIZE_BYTES]);
let mut f = 0;
for ss in s.split('-') {
if f <= 3 {
base24::decode_into_slice(ss.as_bytes(), &mut a.0[f * 4..(f + 1) * 4])?;
} else if f == 4 {
base62::decode_into_slice(ss.as_bytes(), &mut a.0[16..]).map_err(|_| InvalidParameterError("invalid base62"))?;
} else {
return Err(InvalidParameterError("too many sections"));
}
f += 1;
}
return Ok(a);
}
}
@ -488,7 +508,10 @@ mod tests {
for _ in 0..64 {
let mut tmp = Address::new_uninitialized();
random::fill_bytes_secure(&mut tmp.0);
println!("{}", tmp.to_string());
let s = tmp.to_string();
println!("{}", s);
let tmp2 = Address::from_str(s.as_str()).unwrap();
assert!(tmp == tmp2);
}
}
}

View file

@ -66,7 +66,7 @@ fn decode_up_to_u32(s: &[u8]) -> Result<u32, InvalidParameterError> {
}
/// Decode a base24 ASCII slice into bytes (no padding, length determines output length)
pub fn decode_into(s: &[u8], b: &mut Vec<u8>) -> Result<(), InvalidParameterError> {
pub fn decode_into<W: Write>(s: &[u8], b: &mut W) -> Result<(), InvalidParameterError> {
let mut s = s.as_ref();
while s.len() >= 7 {
@ -88,6 +88,11 @@ pub fn decode_into(s: &[u8], b: &mut Vec<u8>) -> Result<(), InvalidParameterErro
return Ok(());
}
#[inline]
pub fn decode_into_slice(s: &[u8], mut b: &mut [u8]) -> Result<(), InvalidParameterError> {
decode_into(s, &mut b)
}
pub fn encode(b: &[u8]) -> String {
let mut tmp = String::with_capacity(((b.len() / 4) * 7) + 2);
encode_into(b, &mut tmp);

View file

@ -85,6 +85,12 @@ pub fn decode_into<W: Write>(s: &[u8], b: &mut W, output_length: usize) -> std::
return Ok(());
}
#[inline]
pub fn decode_into_slice(s: &[u8], mut b: &mut [u8]) -> std::io::Result<()> {
let l = b.len();
decode_into(s, &mut b, l)
}
/// Decode into and return an array whose length is the desired output_length.
/// None is returned if there is an error.
#[inline]