aozora 0.5.0

Aozora Bunko notation parser with incremental document snapshots
Documentation
use super::intern::StrId;
use super::payload::{
    AngleQuote, Content, Directive, ForwardFormat, ForwardPayload, Gaiji, GaijiCanonicalOwned,
    Heading, HeadingHint, Illustration, Kaeriten, MarginNote, Node, Ruby, Segment,
};
use super::registry::NodeRef;
use super::store::{ContentRange, NodeStore, SegRange};

impl NodeStore {
    pub(crate) fn graft_node_ref(&mut self, source: &Self, node: NodeRef) -> NodeRef {
        match node {
            NodeRef::Inline(node) => NodeRef::Inline(self.graft_node(source, node)),
            NodeRef::BlockLeaf(node) => NodeRef::BlockLeaf(self.graft_node(source, node)),
            NodeRef::BlockOpen(format) => NodeRef::BlockOpen(format),
            NodeRef::BlockClose(close) => NodeRef::BlockClose(close),
        }
    }

    fn graft_node(&mut self, source: &Self, node: Node) -> Node {
        match node {
            Node::Ruby(ruby) => Node::Ruby(Ruby {
                base: graft_content_range(source, self, ruby.base),
                reading: graft_content_range(source, self, ruby.reading),
                side: ruby.side,
                base_emphasis: ruby.base_emphasis,
            }),
            Node::Format(format) => Node::Format(ForwardFormat {
                attr: format.attr,
                target: graft_content_range(source, self, format.target),
                origin: format.origin,
                payload: match format.payload {
                    ForwardPayload::AccentBody(id) => {
                        ForwardPayload::AccentBody(graft_str(source, self, id))
                    }
                    payload => payload,
                },
            }),
            Node::Gaiji(gaiji) => Node::Gaiji(graft_gaiji(source, self, gaiji)),
            Node::Line(format) => Node::Line(format),
            Node::PageBreak => Node::PageBreak,
            Node::SectionBreak(kind) => Node::SectionBreak(kind),
            Node::BodyEnd => Node::BodyEnd,
            Node::ForcedBreak => Node::ForcedBreak,
            Node::Heading(heading) => Node::Heading(Heading {
                kind: heading.kind,
                style: heading.style,
                text: graft_content_range(source, self, heading.text),
            }),
            Node::HeadingHint(hint) => Node::HeadingHint(HeadingHint {
                level: hint.level,
                style: hint.style,
                target: graft_str(source, self, hint.target),
                self_contained: hint.self_contained,
            }),
            Node::Illustration(illustration) => Node::Illustration(Illustration {
                file: graft_str(source, self, illustration.file),
                number: illustration.number.map(|id| graft_str(source, self, id)),
                dimensions: illustration
                    .dimensions
                    .map(|id| graft_str(source, self, id)),
                caption: illustration
                    .caption
                    .map(|content| graft_content(source, self, content)),
                description: illustration
                    .description
                    .map(|id| graft_str(source, self, id)),
            }),
            Node::Kaeriten(kaeriten) => Node::Kaeriten(Kaeriten {
                mark: graft_str(source, self, kaeriten.mark),
            }),
            Node::Directive(directive) => Node::Directive(Directive {
                raw: graft_str(source, self, directive.raw),
                kind: directive.kind,
            }),
            Node::AngleQuote(quote) => Node::AngleQuote(AngleQuote {
                content: graft_content_range(source, self, quote.content),
            }),
            Node::MarginNote(margin) => Node::MarginNote(MarginNote {
                kind: margin.kind,
                base: graft_content_range(source, self, margin.base),
                note: graft_content_range(source, self, margin.note),
            }),
        }
    }
}

fn graft_str(source: &NodeStore, target: &mut NodeStore, id: StrId) -> StrId {
    target.intern(source.resolve_str(id))
}

fn graft_content_range(
    source: &NodeStore,
    target: &mut NodeStore,
    range: ContentRange,
) -> ContentRange {
    let contents = source.resolve_content_range(range).to_vec();
    let contents = contents
        .into_iter()
        .map(|content| graft_content(source, target, content))
        .collect::<Vec<_>>();
    target.push_contents(&contents)
}

fn graft_content(source: &NodeStore, target: &mut NodeStore, content: Content) -> Content {
    match content {
        Content::Plain(id) => Content::Plain(graft_str(source, target, id)),
        Content::Segments(range) => Content::Segments(graft_segment_range(source, target, range)),
    }
}

fn graft_segment_range(source: &NodeStore, target: &mut NodeStore, range: SegRange) -> SegRange {
    let segments = source.resolve_seg_range(range).to_vec();
    let segments = segments
        .into_iter()
        .map(|segment| graft_segment(source, target, segment))
        .collect::<Vec<_>>();
    target.push_segments(&segments)
}

fn graft_segment(source: &NodeStore, target: &mut NodeStore, segment: Segment) -> Segment {
    match segment {
        Segment::Text(id) => Segment::Text(graft_str(source, target, id)),
        Segment::Gaiji(gaiji) => Segment::Gaiji(graft_gaiji(source, target, gaiji)),
        Segment::Directive(directive) => Segment::Directive(Directive {
            raw: graft_str(source, target, directive.raw),
            kind: directive.kind,
        }),
    }
}

fn graft_gaiji(source: &NodeStore, target: &mut NodeStore, gaiji: Gaiji) -> Gaiji {
    let canonical = match gaiji.canonical {
        GaijiCanonicalOwned::MenKuTen(value) => GaijiCanonicalOwned::MenKuTen(value),
        GaijiCanonicalOwned::Unicode(value) => GaijiCanonicalOwned::Unicode(value),
        GaijiCanonicalOwned::Unresolved { mencode } => GaijiCanonicalOwned::Unresolved {
            mencode: mencode.map(|id| graft_str(source, target, id)),
        },
    };
    Gaiji {
        hint: graft_str(source, target, gaiji.hint),
        canonical,
        mencode_separator: gaiji.mencode_separator,
        standalone: gaiji.standalone,
    }
}