use alloc::vec::Vec;
use core::fmt;
use crate::allocation::{AllocationContext, AllocationError};
use crate::bytes::{Payload, PayloadByteCount};
use crate::limits::SourceByteCount;
use crate::materialized::{CanonicalRuleSourceDomain, MaterializedBytes, PayloadInspectionDomain};
use crate::rule::Rule;
use crate::source::SourceLineNumber;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RuleCount {
value: usize,
}
impl RuleCount {
#[must_use]
pub(crate) const fn new(value: usize) -> Self {
Self { value }
}
#[must_use]
pub const fn get(self) -> usize {
self.value
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OnceRuleCount {
value: usize,
}
impl OnceRuleCount {
#[must_use]
pub(crate) const fn new(value: usize) -> Self {
Self { value }
}
#[must_use]
pub const fn get(self) -> usize {
self.value
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RuleNumber {
one_based: usize,
}
impl RuleNumber {
fn from_zero_based(zero_based: usize) -> Option<Self> {
let one_based = zero_based.checked_add(1)?;
Some(Self { one_based })
}
#[must_use]
pub const fn get(self) -> usize {
self.one_based
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RulePosition {
number: RuleNumber,
}
impl RulePosition {
pub(crate) fn from_zero_based(zero_based: usize) -> Option<Self> {
let number = RuleNumber::from_zero_based(zero_based)?;
Some(Self { number })
}
#[must_use]
pub const fn number(self) -> RuleNumber {
self.number
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleRepeat {
Always,
Once,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleAnchor {
Anywhere,
Start,
End,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct PayloadView<'program> {
payload: &'program Payload,
}
#[derive(Debug, PartialEq, Eq)]
pub struct PayloadBytes {
bytes: MaterializedBytes<PayloadInspectionDomain>,
}
#[derive(Debug, PartialEq, Eq)]
pub struct CanonicalRuleSource {
bytes: MaterializedBytes<CanonicalRuleSourceDomain>,
}
impl<'program> PayloadView<'program> {
pub(crate) fn new(payload: &'program Payload) -> Self {
Self { payload }
}
#[must_use]
pub fn byte_count(self) -> PayloadByteCount {
self.payload.byte_count()
}
#[must_use]
pub fn is_empty(self) -> bool {
self.byte_count().is_zero()
}
pub(crate) fn materialized_bytes(self) -> impl Iterator<Item = u8> + 'program {
self.payload.bytes()
}
pub(crate) fn to_vec_with_context(
self,
context: AllocationContext,
) -> Result<Vec<u8>, AllocationError> {
self.payload.to_vec_with_context(context)
}
pub fn materialize(self) -> Result<PayloadBytes, AllocationError> {
Ok(PayloadBytes {
bytes: MaterializedBytes::from_vec(
self.to_vec_with_context(AllocationContext::PayloadView)?,
),
})
}
}
impl PayloadBytes {
#[must_use]
pub fn as_slice(&self) -> &[u8] {
self.bytes.as_slice()
}
#[must_use]
pub fn into_raw_bytes(self) -> Vec<u8> {
self.bytes.into_raw_bytes()
}
#[must_use]
pub fn byte_count(&self) -> PayloadByteCount {
PayloadByteCount::new(self.bytes.len())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl CanonicalRuleSource {
#[must_use]
pub fn as_slice(&self) -> &[u8] {
self.bytes.as_slice()
}
#[must_use]
pub fn into_raw_bytes(self) -> Vec<u8> {
self.bytes.into_raw_bytes()
}
#[must_use]
pub fn byte_count(&self) -> SourceByteCount {
SourceByteCount::new(self.bytes.len())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.bytes.is_empty()
}
}
impl fmt::Debug for PayloadView<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries((*self).materialized_bytes())
.finish()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuleActionView<'program> {
Replace(PayloadView<'program>),
MoveStart(PayloadView<'program>),
MoveEnd(PayloadView<'program>),
Return(PayloadView<'program>),
}
#[derive(Clone, Copy)]
pub struct RuleView<'program> {
rule: &'program Rule,
}
impl core::fmt::Debug for RuleView<'_> {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter
.debug_struct("RuleView")
.field("position", &self.position())
.field("line_number", &self.line_number())
.field("repeat", &self.repeat())
.field("anchor", &self.anchor())
.field("lhs", &self.lhs())
.field("action", &self.action())
.finish()
}
}
impl PartialEq for RuleView<'_> {
fn eq(&self, other: &Self) -> bool {
self.position() == other.position()
&& self.line_number() == other.line_number()
&& self.repeat() == other.repeat()
&& self.anchor() == other.anchor()
&& self.lhs() == other.lhs()
&& self.action() == other.action()
}
}
impl Eq for RuleView<'_> {}
impl<'program> RuleView<'program> {
pub(crate) const fn new(rule: &'program Rule) -> Self {
Self { rule }
}
#[must_use]
pub const fn position(self) -> RulePosition {
self.rule.position()
}
#[must_use]
pub fn line_number(self) -> SourceLineNumber {
self.rule.line_number()
}
#[must_use]
pub fn repeat(self) -> RuleRepeat {
self.rule.repeat()
}
#[must_use]
pub fn anchor(self) -> RuleAnchor {
self.rule.anchor().public_anchor()
}
#[must_use]
pub fn lhs(self) -> PayloadView<'program> {
PayloadView::new(self.rule.lhs())
}
#[must_use]
pub fn action(self) -> RuleActionView<'program> {
self.rule.action().view()
}
pub fn canonical_source(self) -> Result<CanonicalRuleSource, AllocationError> {
Ok(CanonicalRuleSource {
bytes: MaterializedBytes::from_vec(crate::rule::canonical_source(self.rule)?),
})
}
}