Initial commit.

Signed-off-by: Pavel Kirilin <win10@list.ru>
This commit is contained in:
2023-02-20 01:20:41 +04:00
parent 9a04acd753
commit faae5e4898
39 changed files with 3420 additions and 2 deletions

139
src/utils/inter_join.rs Normal file
View File

@ -0,0 +1,139 @@
use std::iter::Peekable;
use rand::{seq::SliceRandom, Rng};
/// Trait for creating random intersperse.
///
/// It's implemented for all iterables.
///
/// The usage is the following:
/// ```
/// let words = &[4, 5, 6];
/// let result = [1, 2, 3]
/// .into_iter()
/// .random_itersperse(words, &mut rand::thread_rng())
/// .collect::<Vec<_>>();
/// ```
///
/// Now if you print the result, you'll see that
/// after every word from the source slice,
/// placed one word from the `words` slice.
/// Like this: `[1, 6, 2, 4, 3]`.
pub trait RandomIntersperse<'a, L, R>
where
L: IntoIterator,
R: Rng,
{
fn random_itersperse(
self,
choises: &'a [L::Item],
random: &'a mut R,
) -> RandomIntersperseStruct<'a, L, R>;
}
/// Struct used to create `random_intresperse`.
/// It has a peekable iterator, a reference to a
/// random generator, a slice for items to choose from
/// and boolean to check current state.
///
/// The iterator is peekable, because we need to check
/// if next item exists, to avoid inserting
/// a generated value at the end of iterator.
#[derive(Debug)]
pub struct RandomIntersperseStruct<'a, L, R>
where
L: IntoIterator,
R: Rng,
{
iterator: Peekable<L::IntoIter>,
choices: &'a [L::Item],
random: &'a mut R,
use_iter: bool,
}
/// Implement a `RandomIntersperse` trait for all
/// items that can be turned in iterators.
impl<'a, L, R> RandomIntersperse<'a, L, R> for L
where
L: IntoIterator,
R: Rng,
{
fn random_itersperse(
self,
choices: &'a [L::Item],
random: &'a mut R,
) -> RandomIntersperseStruct<'a, L, R> {
RandomIntersperseStruct {
random,
choices,
use_iter: true,
iterator: self.into_iter().peekable(),
}
}
}
/// Implementation of an interator for a randomitersperse structure,
/// so it can be used in chain.
impl<'a, L, R> Iterator for RandomIntersperseStruct<'a, L, R>
where
L: IntoIterator,
R: Rng,
L::Item: Clone,
{
// The type of item is the same as for
// original iterator.
type Item = L::Item;
fn next(&mut self) -> Option<Self::Item> {
// Peek a value from the iterator to check if we have values.
self.iterator.peek()?;
let choise = self.choices.choose(self.random);
if choise.is_none() {
self.use_iter = true;
}
if self.use_iter {
// We change use_iter, so a random
// value is chosen on the next step.
self.use_iter = false;
self.iterator.next()
} else {
self.use_iter = true;
self.choices.choose(self.random).cloned()
}
}
}
#[cfg(test)]
mod tests {
use crate::utils::inter_join::RandomIntersperse;
#[test]
pub fn success() {
let randoms = &[4, 5, 6];
let result = [1, 2, 3]
.into_iter()
.random_itersperse(randoms, &mut rand::thread_rng())
.collect::<Vec<_>>();
for value in [1, 2, 3] {
assert!(result.contains(&value));
}
assert_eq!(result.len(), 5);
}
#[test]
pub fn empty_array() {
let randoms = &[];
let result = [1, 2, 3]
.into_iter()
.random_itersperse(randoms, &mut rand::thread_rng())
.collect::<Vec<_>>();
for value in [1, 2, 3] {
assert!(result.contains(&value));
}
assert_eq!(result.len(), 3);
}
}

9
src/utils/messages.rs Normal file
View File

@ -0,0 +1,9 @@
use grammers_client::{types::Message, Update};
#[must_use]
pub fn get_message(update: &Update) -> Option<&Message> {
match update {
Update::NewMessage(msg) | Update::MessageEdited(msg) => Some(msg),
_ => None,
}
}

2
src/utils/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod inter_join;
pub mod messages;