marktwin 0.5.0

Marktwin format support for Eternaltwin.
Documentation
use std::borrow::Cow;

/// Describes all the elements of a syntax.
pub trait Syntax: Sized {
  type Root: Root<Ast = Self>;

  type Block: Block<Ast = Self>;
  type Admin: Admin<Ast = Self>;
  type Mod: Mod<Ast = Self>;

  type Inline: Inline<Ast = Self>;
  type Emphasis: Emphasis<Ast = Self>;
  type Icon: Icon<Ast = Self>;
  type Link: Link<Ast = Self>;
  type Newline: Newline;
  type Strikethrough: Strikethrough<Ast = Self>;
  type Strong: Strong<Ast = Self>;
  type Text: Text<Ast = Self>;
}

/// A `Cow` variant that does not require `ToOwned`.
///
/// It is intended as a workaround until Generic Associated Types are improved.
/// Once rust-lang/rust#30472 is fixed, this type could be removed.
#[derive(Debug)]
pub enum MaybeOwned<'a, T>
where
  T: 'a,
{
  Borrowed(&'a T),
  Owned(T),
}

impl<T> std::ops::Deref for MaybeOwned<'_, T> {
  type Target = T;
  fn deref(&self) -> &T {
    match self {
      MaybeOwned::Borrowed(borrowed) => borrowed,
      MaybeOwned::Owned(ref owned) => owned,
    }
  }
}

/// Trait representing a container for block and inline nodes.
pub trait BlockContainer {
  type Ast: Syntax;

  fn children<'a>(&'a self) -> Box<dyn Iterator<Item = MaybeOwned<'a, <Self::Ast as Syntax>::Block>> + 'a>;
}

/// Trait representing a container for inline nodes.
pub trait InlineContainer {
  type Ast: Syntax;

  fn children<'a>(&'a self) -> Box<dyn Iterator<Item = MaybeOwned<'a, <Self::Ast as Syntax>::Inline>> + 'a>;
}

/// Message root node
pub trait Root: BlockContainer {
  type Ast: Syntax;
}

/// Trait representing any block or inline node
pub trait Block {
  type Ast: Syntax;

  /// Downcast the statement to its concrete type.
  fn cast(&self) -> BlockCast<Self::Ast>;
}

/// Represents the result of downcasting a block or inline node.
pub enum BlockCast<'a, S: Syntax> {
  Admin(MaybeOwned<'a, S::Admin>),
  Mod(MaybeOwned<'a, S::Mod>),
  // Inline nodes
  Emphasis(MaybeOwned<'a, S::Emphasis>),
  Icon(MaybeOwned<'a, S::Icon>),
  Link(MaybeOwned<'a, S::Link>),
  Newline(MaybeOwned<'a, S::Newline>),
  Strikethrough(MaybeOwned<'a, S::Strikethrough>),
  Strong(MaybeOwned<'a, S::Strong>),
  Text(MaybeOwned<'a, S::Text>),
}

/// Admin block
pub trait Admin: BlockContainer {
  type Ast: Syntax;
}

/// Mod block
pub trait Mod: BlockContainer {
  type Ast: Syntax;
}

/// Trait representing any inline node
pub trait Inline {
  type Ast: Syntax;

  /// Downcast the statement to its concrete type.
  fn cast(&self) -> InlineCast<Self::Ast>;
}

/// Represents the result of downcasting an inline node.
pub enum InlineCast<'a, S: Syntax> {
  Emphasis(MaybeOwned<'a, S::Emphasis>),
  Icon(MaybeOwned<'a, S::Icon>),
  Link(MaybeOwned<'a, S::Link>),
  Newline(MaybeOwned<'a, S::Newline>),
  Strikethrough(MaybeOwned<'a, S::Strikethrough>),
  Strong(MaybeOwned<'a, S::Strong>),
  Text(MaybeOwned<'a, S::Text>),
}

/// Emphasis span
pub trait Emphasis: InlineContainer {
  type Ast: Syntax;
}

pub trait Icon {
  type Ast: Syntax;

  fn key(&self) -> Cow<str>;
}

pub trait Link: InlineContainer {
  type Ast: Syntax;

  fn uri(&self) -> Cow<str>;
}

pub trait Newline {}

pub trait Strikethrough: InlineContainer {
  type Ast: Syntax;
}

/// Strong span
pub trait Strong: InlineContainer {
  type Ast: Syntax;
}

pub trait Text {
  type Ast: Syntax;

  fn text(&self) -> Cow<str>;
}