remediate 0.2.1

Library for thinking and learning
Documentation
use ast::DocumentParser;
pub use ast::Rule;
use from_pest::FromPest;
use pest::{error::Error, Parser};
use rkyv::{Archive, Deserialize, Serialize};
use std::{rc::Rc, str};

#[derive(Debug)]
pub struct Document {
    rems: Rc<[Rem]>,
}

#[derive(Debug)]
pub struct Rem {
    id: Rc<str>,
    content: Rc<[Content]>,
    children: Rc<[Rem]>,
}

#[derive(Debug, Clone, Archive, Serialize, Deserialize, Eq, PartialEq)]
#[archive_attr(derive(Debug))]
pub enum Content {
    Text(Text),
    Closure(Group, Text),
}

pub type Group = (Rc<str>, Rc<str>);

pub type Text = Rc<str>;

#[derive(Debug, Clone, Archive, Serialize, Deserialize, Eq, PartialEq)]
#[archive_attr(derive(Debug))]
pub enum Segment {
    NewLine,
    Line(Box<str>),
}

impl Document {
    pub fn parse(input: &str) -> Result<Self, Error<Rule>> {
        let mut pairs = DocumentParser::parse(Rule::document, input)?;
        Ok(ast::Document::from_pest(&mut pairs).unwrap().into())
    }

    pub fn rems(&self) -> Rc<[Rem]> {
        self.rems.clone()
    }
}

impl Rem {
    pub fn id(&self) -> Rc<str> {
        self.id.clone()
    }

    pub fn content(&self) -> Rc<[Content]> {
        self.content.clone()
    }

    pub fn children(&self) -> Rc<[Rem]> {
        self.children.clone()
    }
}

impl Content {
    pub fn group(&self) -> Option<Group> {
        match self {
            Self::Closure(group, _) => Some(group.clone()),
            _ => None,
        }
    }
}

mod ast {
    use pest::Span;
    use pest_ast::FromPest;
    use pest_derive::Parser;
    use std::rc::Rc;

    #[derive(Parser)]
    #[grammar = "deck/document.pest"]
    pub struct DocumentParser;

    #[derive(Debug, FromPest)]
    #[pest_ast(rule(Rule::document))]
    pub struct Document {
        rems: Vec<Rem>,
    }

    impl From<Document> for super::Document {
        fn from(value: Document) -> Self {
            fn resolve_text(lines: Vec<Segment>) -> super::Text {
                lines
                    .iter()
                    .map(|line| match line {
                        Segment::Line(Line(line)) => line.as_ref(),
                        Segment::NewLine(_) => "\n",
                    })
                    .flat_map(|s| s.chars())
                    .collect::<String>()
                    .into()
            }
            fn resolve_rem((mut parents, rem): (Vec<Rc<str>>, Rem)) -> super::Rem {
                parents.push(rem.id.0.clone());
                super::Rem {
                    id: rem.id.0,
                    content: rem
                        .content
                        .into_iter()
                        .map(|content| match content {
                            Content::Text(Text(text)) => super::Content::Text(resolve_text(text)),
                            Content::Closure(Closure {
                                location: Location(location),
                                group: Group(group),
                                text: Text(text),
                            }) => super::Content::Closure(
                                (parents[parents.len() - location - 1].clone(), group),
                                resolve_text(text),
                            ),
                        })
                        .collect::<Vec<_>>()
                        .into(),
                    children: rem
                        .children
                        .into_iter()
                        .map(|rem| (parents.clone(), rem))
                        .map(resolve_rem)
                        .collect::<Vec<_>>()
                        .into(),
                }
            }
            Self {
                rems: value
                    .rems
                    .into_iter()
                    .map(|rem| (Vec::<Rc<str>>::new(), rem))
                    .map(resolve_rem)
                    .collect::<Vec<_>>()
                    .into(),
            }
        }
    }

    #[derive(Debug, FromPest)]
    #[pest_ast(rule(Rule::rem))]
    struct Rem {
        id: Id,
        content: Vec<Content>,
        children: Vec<Rem>,
    }

    #[derive(Debug, FromPest)]
    #[pest_ast(rule(Rule::id))]
    struct Id(#[pest_ast(outer(with(as_str)))] Rc<str>);

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::content))]
    enum Content {
        Text(Text),
        Closure(Closure),
    }

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::text))]
    struct Text(Vec<Segment>);

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::segment))]
    enum Segment {
        Line(Line),
        NewLine(NewLine),
    }

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::line))]
    struct Line(#[pest_ast(outer(with(as_str)))] Rc<str>);

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::newline))]
    struct NewLine(#[pest_ast(outer(with(empty)))] ());

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::closure))]
    struct Closure {
        location: Location,
        group: Group,
        text: Text,
    }

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::location))]
    struct Location(#[pest_ast(outer(with(count)))] usize);

    #[derive(Debug, FromPest, Clone)]
    #[pest_ast(rule(Rule::group))]
    struct Group(#[pest_ast(outer(with(as_str)))] Rc<str>);

    fn count(span: Span) -> usize {
        span.as_str().len()
    }

    fn as_str(span: Span) -> Rc<str> {
        span.as_str().into()
    }

    fn empty(_: Span) -> () {
        ()
    }
}