use crate::*;
struct Wrapper<'a> {
buf: &'a mut [u8],
offset: usize,
}
impl<'a> Wrapper<'a> {
fn new(buf: &'a mut [u8]) -> Self {
Wrapper { buf, offset: 0 }
}
fn borrow_str(&self) -> &str {
match core::str::from_utf8(&self.buf[..self.offset]) {
Ok(slice_as_str) => slice_as_str,
Err(_e) => panic!("assembled byte slice contains invalid UTF-8")
}
}
}
impl<'a> core::fmt::Write for Wrapper<'a> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let bytes = s.as_bytes();
let remainder = &mut self.buf[self.offset..];
if remainder.len() < bytes.len() { return Err(core::fmt::Error); }
let remainder = &mut remainder[..bytes.len()];
remainder.copy_from_slice(bytes);
self.offset += bytes.len();
Ok(())
}
}
#[test]
fn write_macro() {
use crate::write;
let mut sc = StrConstrue::<11>::new();
write!(sc, "Test", 123u8, " ");
write!(sc, ":^)");
let arr = sc.store_bytes();
let txt = StrConstrue::borrow_str(&arr);
assert_eq!(txt, "Test123 :^)");
}
#[test]
fn display_char() {
const MAX_SIZE: usize = 4;
let chars = "Construe".chars();
let numbers = "01234567890".chars();
let special = [char::MAX, char::REPLACEMENT_CHARACTER];
let weird = "🤔 🫠🫥 🇨 🇧🇧 🫵 🦘 🇹🇰".chars();
for ch in chars.chain(numbers).chain(special).chain(weird) {
let mut sc = StrConstrue::<MAX_SIZE>::new();
sc = Display(ch).write(sc);
let ch_size = sc.len();
while sc.len() < MAX_SIZE {
sc = sc.push_str(" ");
}
let arr = sc.store_bytes();
let text = StrConstrue::borrow_str(&arr[0..ch_size]);
let mut buf = [0u8; MAX_SIZE];
let mut writer = Wrapper::new(&mut buf);
core::fmt::write(&mut writer, format_args!("{ch}")).unwrap();
let text_2 = writer.borrow_str();
assert_eq!(text, text_2);
}
}
#[test]
fn display_str() {
let mut sc = StrConstrue::<10>::new();
sc = Display("1234567890").write(sc);
let x = sc.store_bytes();
assert_eq!(StrConstrue::borrow_str(&x), "1234567890");
}
#[test]
fn itoa() {
const MAX_SIZE: usize = 40;
macro_rules! check_ints {
($i:ty => $c:expr) => {
let cases = $c.iter().chain(&[<$i>::MIN, <$i>::MAX]);
let check_case = |case: $i| {
let mut sc = StrConstrue::<MAX_SIZE>::new();
sc = Display::<$i>(case).write(sc);
let int_size = sc.len();
while sc.len() < MAX_SIZE {
sc = sc.push_str(" ");
}
let arr = sc.store_bytes();
let text = StrConstrue::borrow_str(&arr[0..int_size]);
let mut buf = [0u8; MAX_SIZE];
let mut writer = Wrapper::new(&mut buf);
core::fmt::write(
&mut writer,
format_args!("{case}")
).unwrap();
let text_2 = writer.borrow_str();
assert_eq!(text, text_2);
};
for &case in cases {
check_case(case);
case.checked_neg().map(check_case);
}
};
($($i:ty => $c:expr),*) => {
$( check_ints!($i => $c) );*
};
}
check_ints!(
u8 => [1, 12, 123],
u16 => [1, 12, 123, 1234, 12345],
u32 => [1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
u64 => [1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
u128 => [1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
usize => [1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890]
);
check_ints!(
i8 => [0, 1, 12, 123],
i16 => [0, 1, 12, 123, 1234, 12345],
i32 => [0, 1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
i64 => [0, 1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
i128 => [0, 1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890],
isize => [0, 1, 12, 123, 1234, 12345, 123456, 1234567, 1234567890]
);
}
#[test]
fn try_construe() {
const fn multiply<const N: usize, T: Copy>(mut slice: &[T], times: usize)
-> Construe<T, N>
{
let mut c = Construe::new();
while let [item, rest @ ..] = slice {
slice = rest;
let mut i = 0;
while i < times {
c = c.push(*item).0;
i += 1;
}
}
c
}
const fn concat<const N: usize>(mut slice: &[&str], times: usize)
-> StrConstrue<N>
{
let mut sc = StrConstrue::new();
while let [s, rest @ ..] = slice {
slice = rest;
let mut i = 0;
while i < times {
sc = sc.push_str(s);
i += 1;
}
}
sc
}
const WORDS: &[&str] = &{
const LEN: usize = multiply(&["hey", "you"], 2).needs_len();
const ARRAY: [&str; LEN] = multiply(&["hey", "you"], 2).finish();
ARRAY
};
assert_eq!(WORDS, &["hey", "hey", "you", "you"]);
const WORDS2: &[&str] = construe!(&[&str] => multiply(&["hey", "you"], 2));
assert_eq!(WORDS, WORDS2);
construe!(const WORDS3: &[&str] = multiply(&["hey", "you"], 2));
assert_eq!(WORDS, WORDS3);
construe!(const WORDS4: [&str; _] = multiply(&["hey", "you"], 2));
assert_eq!(WORDS, &WORDS4);
construe!(const ONE_WORD: &str = concat(&["hey", "you"], 2));
assert_eq!(ONE_WORD, "heyheyyouyou");
trait Trait {
const STR: &'static str;
const ARR: &'static [u8];
}
impl Trait for () {
construe!(const STR: &'static str = concat(&["a", "b"], 10));
construe!(const ARR: &'static [u8] = multiply(&[1, 2, 3], 9));
}
}