From b03a90f4939ed1ea3817f35ee61ef4c6d6f0fa80 Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 1 Oct 2020 00:19:11 +0100 Subject: [PATCH] more exts --- src/ext.rs | 185 +++++++++++++++++++++++++++++++++++++--------------- src/main.rs | 2 +- 2 files changed, 134 insertions(+), 53 deletions(-) diff --git a/src/ext.rs b/src/ext.rs index bb5ede4..c0161b1 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -17,6 +17,52 @@ use tokio::{ }; use futures::future::Future; +#[derive(Debug)] +pub struct GroupIter(std::iter::Fuse, Vec, usize); + +impl, T> Iterator for GroupIter +{ + type Item = Box<[T]>; + fn next(&mut self) -> Option + { + if self.1.len() == 0 { + // fill + for (_, item) in (0..self.2).zip(&mut self.0) + { + self.1.push(item); + } + } + if self.1.len() == 0 { + None + } else{ + Some(std::mem::replace(&mut self.1, Vec::with_capacity(self.2)).into()) + } + } + + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.0.size_hint(); + (low / self.2, high.map(|x| (x / self.2) + 1)) //not too sure if this is right... + } +} +impl, T> std::iter::FusedIterator for GroupIter{} + +pub trait GroupIterExt: Sized +{ + /// Group this iterator to return a boxed slice of every `n` items. + /// + /// # Notes + /// If there isn't `n` items left in the iterator, then the rest is returned. + fn group(self, n: usize) -> GroupIter; +} + +impl GroupIterExt<::IntoIter, ::Item> for T +{ + fn group(self, every: usize) -> GroupIter<::IntoIter, ::Item> + { + GroupIter(self.into_iter().fuse(), Vec::with_capacity(every), every) + } +} + pub trait JoinStrsExt: Sized { /// Join an iterator of `str` with a seperator @@ -24,14 +70,15 @@ pub trait JoinStrsExt: Sized } impl JoinStrsExt for I -where I: Iterator, +where I: IntoIterator, T: AsRef { + /// Join an iterator of `str` with a seperator fn join(self, with: &str) -> String { let mut output = String::new(); let mut first=true; - for string in self + for string in self.into_iter() { if !first { output.push_str(with); @@ -44,60 +91,99 @@ where I: Iterator, } } -/*macro_rules! typed_swap { -(@ [] $($reversed:tt)*) => { -fn swap(self) -> ($($reversed)*); - }; - (@ [$first:tt $($rest:tt)*] $($reversed:tt)*) => { - typed_swap!{@ [$($rest)*] $first $($reversed)*} - }; - (@impl {$($body:tt)*} [] $($reversed:tt)*) => { - fn swap(self) -> ($($reversed)*) - { - $($body)* +#[derive(Debug, Clone)] +pub struct StrChunks<'a, T: ?Sized>(&'a str, usize, PhantomData<&'a T>); + +impl<'a, T: ?Sized> StrChunks<'a, T> +{ + /// The rest of the string + pub fn as_str(&self) -> &'a str + { + &self.0[..] + } + /// The number of chars to break at + pub fn every(&self) -> usize + { + self.1 + } + /// Set the number of chars to break at. + /// + /// # Note + /// Probably don't do this unless you know what you're doing. + pub fn every_mut(&mut self) -> &mut usize + { + &mut self.1 + } +} +impl<'a, T: ?Sized> Iterator for StrChunks<'a, T> +{ + type Item = &'a str; + fn next(&mut self) -> Option + { + match self.0.char_indices().nth(self.1).map(|x| x.0) { + None if self.0.len() > 0 => Some(std::mem::replace(&mut self.0, "")), + Some(i) => { + let (left, right) = self.0.split_at(i); + self.0 = right; + Some(left) + }, + _ => None, } - }; - (@impl {$($body:tt)*} [$first:tt $($rest:tt)*] $($reversed:tt)*) => { - typed_swap!{@impl {$($body)*} [$($rest)*] $first $($reversed)*} - }; - () => {}; - ({$($params:tt)*} $($rest:tt)*) => { - mod swap { - pub trait SwapTupleExt<$($params)*>: Sized - { - typed_swap!(@ [$($params)*]); - } + } - impl<$($params)*> SwapTupleExt<$($params)*> for ($($params)*) - { - typed_swap!(@impl { - todo!() - } [$($params)*]); - } - - typed_swap!($($rest)*); + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.0.chars().size_hint(); + (low / self.1, high.map(|x| (x / self.1) + 1)) //not too sure if this is right... + } +} +impl<'a, T: ?Sized> std::iter::FusedIterator for StrChunks<'a, T>{} + +/// Split a `str` into chunks on char boundaries +pub trait ChunkStrsExt +{ + /// Split this str into a chunking iterator every specified number of chars. + /// + /// If there are not enough chars left in the string, the rest is returned. + /// # Note + /// This operates on codepoints, not bytes. + fn chunk(&self, every: usize) -> StrChunks<'_, Self>; +} + +#[cfg(test)] +mod chunk_tests +{ + use super::*; + #[test] + fn chunk_test() + { + let string = r"a2eab409c57a829d23139c61ff2d5e479260c96158ebec0ce4d458afb85b76dłこんな僕は生きてるだけ何万人の人が悲しいんで。!?"; + assert_eq!(&string.chunk(8).join("")[..], string); + for chunk in string.chunk(8) { + println!("{}", chunk); } - pub use swap::*; - }; + } + + #[test] + fn group_test() + { - (all $first:tt $($params:tt)+) => { - typed_swap!({$first, $($params),+}); - mod nswap { - typed_swap!(all $($params)+); + let string = r"a2eab409c57a829d23139c61ff2d5e479260c96158ebec0ce4d458afb85b76dłこんな僕は生きてるだけ何万人の人が悲しいんで。!?"; + let astr: String = string.chars().group(8).map(|x| -> String {x.iter().collect()}).collect(); + assert_eq!(&astr[..], string); + for chunk in string.chars().group(8) { + println!("{:?}", chunk); } - }; - (all $($one:tt)?) => {}; + } } -typed_swap!(all A B C D E F G H I J K L M N O P Q R S T U V W X Y Z); -pub use swap::*; -fn test() +impl+?Sized> ChunkStrsExt for T { - let sw = (1, 2).swap(); - -}*/ -// ^ unfortunately not lol + fn chunk(&self, every: usize) -> StrChunks<'_, Self> + { + StrChunks(self.as_ref(), every, PhantomData) + } +} pub trait SwapTupleExt: Sized { @@ -110,11 +196,6 @@ impl SwapTupleExt for (T,U) } } -/*typed_swap!({A, B} - {A, U, V} - {T, U, V, W});*/ - - const ASCII_MAP: [char; 256] = [ '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', diff --git a/src/main.rs b/src/main.rs index 8def5a0..06cf18a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -163,7 +163,7 @@ async fn fuck() -> eyre::Result<()> println!("Wrote {} bytes", written); println!("{}\n", ser.fmt_view()); - println!("As text:\n{}\n", String::from_utf8_lossy(&ser[..])); + println!("As text:\n{}\n", ser.fmt_ascii()); let mut read = &ser[..]; let (reads, readn) = SuperHeader::from_memory(&mut read, serialise::Mode::Binary, |salt| Some(Password::derive(password, salt)))?; // SuperHeader::read_text(read).await?;