remediate 0.2.1

Library for thinking and learning
Documentation
pub mod fs;

use crate::{loc, loc_root, root};
use std::{
    io::{Read, Write},
    rc::Rc,
    slice::from_ref,
};

pub trait Component: std::fmt::Debug + Clone + for<'a> From<&'a str> + 'static {}

pub enum Access {
    Read,
    Write,
}

pub trait Workspace {
    type Component: Component;
    type Source: Read + Write;

    fn get_source(&self, location: &[Self::Component], access: Access) -> Self::Source;
    fn make_component(&self, location: &[Self::Component]);
    fn insert_descendants(
        &self,
        descendants: &mut Vec<Rc<[Self::Component]>>,
        location: &[Self::Component],
        skip: usize,
    );

    fn read<R: Root<Self::Component>, T: IntoComponents<Self::Component>>(
        &self,
        location: T,
    ) -> Rc<[u8]> {
        let mut vec = Vec::new();
        let location = loc_root!(R, [location] as Self::Component).into_components();
        self.get_source(location.as_components(), Access::Read)
            .read_to_end(&mut vec)
            .unwrap();
        vec.into()
    }

    fn write<R: Root<Self::Component>, T: IntoComponents<Self::Component>>(
        &self,
        location: T,
        bytes: &[u8],
    ) {
        let location = loc_root!(R, [location] as Self::Component).into_components();
        let components = location.as_components();
        self.make_component(&components[..components.len() - 1]);
        self.get_source(location.as_components(), Access::Write)
            .write_all(bytes)
            .unwrap();
    }

    fn descendants_from<R: Root<Self::Component>, T: IntoComponents<Self::Component>>(
        &self,
        location: T,
    ) -> Vec<Rc<[Self::Component]>> {
        let location = loc_root!(R, [location] as Self::Component).into_components();
        let components = location.as_components();
        let mut descendants = Vec::new();
        self.insert_descendants(&mut descendants, components, components.len());
        descendants
    }
}

pub trait IntoComponents<C> {
    type Output: AsComponents<C>;

    fn into_components(self) -> Self::Output;
}

impl<C: Component> IntoComponents<C> for &[&dyn AsComponents<C>] {
    type Output = Rc<[C]>;

    fn into_components(self) -> Self::Output {
        let mut vec = Vec::new();
        for item in self.into_iter() {
            for component in item.as_components().into_iter() {
                vec.push(component.clone());
            }
        }
        vec.into()
    }
}

impl<'a, C: Component> IntoComponents<C> for &'a str {
    type Output = C;

    fn into_components(self) -> Self::Output {
        self.into()
    }
}

impl<C: Component> IntoComponents<C> for C {
    type Output = C;

    fn into_components(self) -> Self::Output {
        self
    }
}

impl<'a, C: Component> IntoComponents<C> for &'a [C] {
    type Output = &'a [C];

    fn into_components(self) -> Self::Output {
        self
    }
}

impl<C: Component> IntoComponents<C> for Rc<[C]> {
    type Output = Rc<[C]>;

    fn into_components(self) -> Self::Output {
        self
    }
}

impl<C: Component> IntoComponents<C> for () {
    type Output = Rc<[C]>;

    fn into_components(self) -> Self::Output {
        Rc::from([])
    }
}

pub trait AsComponents<C> {
    fn as_components(&self) -> &[C];
}

impl<C: Component> AsComponents<C> for C {
    fn as_components(&self) -> &[C] {
        from_ref(self)
    }
}

impl<'a, C: Component> AsComponents<C> for &'a [C] {
    fn as_components(&self) -> &[C] {
        self
    }
}

impl<C: Component> AsComponents<C> for Rc<[C]> {
    fn as_components(&self) -> &[C] {
        self.as_ref()
    }
}

pub trait Root<C: Component> {
    type Output: AsComponents<C>;

    fn get_root() -> Self::Output;
}

root!(pub type WorkspaceRoot = []);

#[macro_export]
macro_rules! loc {
    ([$($x:expr),*] as $sty:ty) => {
        &[$(&<_ as IntoComponents<$sty>>::into_components($x).as_components() as &dyn AsComponents<$sty>),*] as &[&dyn AsComponents<$sty>]
    };
}

#[macro_export]
macro_rules! root {
    ($v:vis type $i:ident = [$($x:expr),*]) => {
        $v struct $i;

        impl<C: Component> Root<C> for $i {
            type Output = Rc<[C]>;

            fn get_root() -> Self::Output {
                loc!([$($x),*] as C).into_components()
            }
        }
    };
    ($v:vis type $i:ident: $j:ident = [$($x:expr),*]) => {
        $v struct $i;

        impl<C: Component> Root<C> for $i {
            type Output = Rc<[C]>;

            fn get_root() -> Self::Output {
                loc_root!($j, [$($x),*] as C).into_components()
            }
        }
    };
}

#[macro_export]
macro_rules! loc_root {
    ($i:ident, [$($x:expr),*] as $sty:ty) => {
        loc!([<_ as AsComponents<$sty>>::as_components(&$i::get_root()), $($x),*] as $sty)
    };
}