euphony 0.1.1

music composition environment for programmers
Documentation
use crate::prelude::Beat;
use ::rand::distributions;
use core::future::Future;
use once_cell::sync::Lazy;

pub use bach::rand::*;

pub fn rhythm(length: Beat, durations: impl IntoIterator<Item = Beat>) -> Vec<Beat> {
    let durations: Vec<_> = durations.into_iter().collect();
    let mut beats = vec![];
    let mut total = Beat(0, 1);
    while total < length {
        let b = *one_of(&durations);
        let new_total = total + b;
        if new_total > length {
            let b = length - total;
            beats.push(b);
            break;
        } else {
            total = new_total;
            beats.push(b);
        }
    }
    beats
}

pub fn with_seed<F: FnOnce() -> R, R>(seed: u64, f: F) -> R {
    scope::with(Scope::new(seed), f)
}

pub static SEED: Lazy<u64> = Lazy::new(|| {
    if let Ok(seed) = std::env::var("EUPHONY_SEED") {
        u64::from_str_radix(&seed, 16).unwrap()
    } else {
        0
    }
});

pub trait OneOfExt<'a> {
    type Output;

    fn one_of(&'a self) -> Self::Output;

    fn pick(&'a self) -> Self::Output {
        self.one_of()
    }
}

impl<'a, T: 'a> OneOfExt<'a> for [T] {
    type Output = &'a T;

    fn one_of(&'a self) -> Self::Output {
        one_of(self)
    }
}

impl<'a> OneOfExt<'a> for usize {
    type Output = usize;

    fn one_of(&'a self) -> Self::Output {
        (0..*self).one_of()
    }
}

impl<'a> OneOfExt<'a> for u64 {
    type Output = u64;

    fn one_of(&'a self) -> Self::Output {
        (0..*self).one_of()
    }
}

macro_rules! one_of_range {
    ($range:ident) => {
        impl<'a, T> OneOfExt<'a> for core::ops::$range<T>
        where
            core::ops::$range<T>: distributions::uniform::SampleRange<T>,
            T: Copy + distributions::uniform::SampleUniform + PartialOrd,
        {
            type Output = T;

            fn one_of(&'a self) -> Self::Output {
                gen_range(self.clone())
            }
        }
    };
}

one_of_range!(Range);
one_of_range!(RangeTo);
one_of_range!(RangeInclusive);
one_of_range!(RangeToInclusive);

pub trait TaskExt: Sized {
    fn seed(self, seed: u64) -> Task<Self>;
    fn inhert_seed(self) -> Task<Self>;
}

impl<T> TaskExt for T
where
    T: Future,
{
    fn seed(self, seed: u64) -> Task<Self> {
        Task::new(self, Scope::new(seed))
    }

    fn inhert_seed(self) -> Task<Self> {
        Task::new(self, scope::borrow_with(|v| v.clone()))
    }
}