use std::{cell::RefCell, rc::Rc};
use bumpalo::Bump;
use crate::{Document, InlineNode, Warning};
#[derive(Debug)]
pub(crate) struct OwnedInput {
pub(crate) source: Box<str>,
pub(crate) arena: Bump,
}
impl OwnedInput {
pub(crate) fn new(source: Box<str>) -> Self {
let arena = Bump::with_capacity(source.len());
Self { source, arena }
}
}
type InlineAst<'a> = Vec<InlineNode<'a>>;
self_cell::self_cell! {
struct ParsedDocumentCell {
owner: OwnedInput,
#[covariant]
dependent: Document,
}
impl {Debug}
}
self_cell::self_cell! {
struct ParsedInlineCell {
owner: OwnedInput,
#[covariant]
dependent: InlineAst,
}
impl {Debug}
}
#[derive(Debug)]
#[must_use = "ignoring a ParseResult drops any warnings the parser produced"]
pub struct ParseResult {
cell: ParsedDocumentCell,
warnings: Vec<Warning>,
}
impl ParseResult {
pub(crate) fn try_new<E>(
owner: OwnedInput,
warnings_handle: Rc<RefCell<Vec<Warning>>>,
builder: impl for<'a> FnOnce(&'a OwnedInput) -> Result<Document<'a>, E>,
) -> Result<Self, E> {
let cell = ParsedDocumentCell::try_new(owner, builder)?;
Ok(Self {
cell,
warnings: recover_warnings(warnings_handle),
})
}
#[must_use]
pub fn document(&self) -> &Document<'_> {
self.cell.borrow_dependent()
}
#[must_use]
pub fn source(&self) -> &str {
&self.cell.borrow_owner().source
}
#[must_use]
pub fn warnings(&self) -> &[Warning] {
&self.warnings
}
pub fn take_warnings(&mut self) -> Vec<Warning> {
std::mem::take(&mut self.warnings)
}
}
#[derive(Debug)]
#[must_use = "ignoring a ParseInlineResult drops any warnings the parser produced"]
pub struct ParseInlineResult {
cell: ParsedInlineCell,
warnings: Vec<Warning>,
}
impl ParseInlineResult {
pub(crate) fn try_new<E>(
owner: OwnedInput,
warnings_handle: Rc<RefCell<Vec<Warning>>>,
builder: impl for<'a> FnOnce(&'a OwnedInput) -> Result<Vec<InlineNode<'a>>, E>,
) -> Result<Self, E> {
let cell = ParsedInlineCell::try_new(owner, builder)?;
Ok(Self {
cell,
warnings: recover_warnings(warnings_handle),
})
}
pub(crate) fn from_infallible(
owner: OwnedInput,
builder: impl for<'a> FnOnce(&'a OwnedInput) -> Vec<InlineNode<'a>>,
) -> Self {
let cell = ParsedInlineCell::new(owner, builder);
Self {
cell,
warnings: Vec::new(),
}
}
#[must_use]
pub fn inlines(&self) -> &[InlineNode<'_>] {
self.cell.borrow_dependent()
}
#[must_use]
pub fn source(&self) -> &str {
&self.cell.borrow_owner().source
}
#[must_use]
pub fn warnings(&self) -> &[Warning] {
&self.warnings
}
pub fn take_warnings(&mut self) -> Vec<Warning> {
std::mem::take(&mut self.warnings)
}
}
fn recover_warnings(handle: Rc<RefCell<Vec<Warning>>>) -> Vec<Warning> {
Rc::try_unwrap(handle).map_or_else(
|shared| std::mem::take(&mut *shared.borrow_mut()),
RefCell::into_inner,
)
}
#[derive(Debug, Clone)]
pub struct OwnedSource(Box<str>);
impl OwnedSource {
#[must_use]
pub fn new(source: impl Into<Box<str>>) -> Self {
Self(source.into())
}
#[must_use]
pub fn source(&self) -> &str {
&self.0
}
}