use alloc::{rc::Rc, string::String, vec::Vec};
use core::{cell::RefCell, convert::From};
use std::hash::{Hash, Hasher};
use grammartec::{
newtypes::NodeID,
rule::RuleIDOrCustom,
tree::{Tree, TreeLike},
};
use serde::{Deserialize, Serialize};
use crate::{
bolts::HasLen,
generators::nautilus::NautilusContext,
inputs::{BytesInput, Input, InputConverter},
Error,
};
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct NautilusInput {
pub tree: Tree,
}
impl Input for NautilusInput {
#[must_use]
fn generate_name(&self, idx: usize) -> String {
format!("id:{idx}")
}
}
impl From<NautilusInput> for Rc<RefCell<NautilusInput>> {
fn from(input: NautilusInput) -> Self {
Rc::new(RefCell::new(input))
}
}
impl HasLen for NautilusInput {
#[inline]
fn len(&self) -> usize {
self.tree.size()
}
}
impl NautilusInput {
#[must_use]
pub fn new(tree: Tree) -> Self {
Self { tree }
}
#[must_use]
pub fn empty() -> Self {
Self {
tree: Tree {
rules: vec![],
sizes: vec![],
paren: vec![],
},
}
}
pub fn unparse(&self, context: &NautilusContext, bytes: &mut Vec<u8>) {
bytes.clear();
self.tree.unparse(NodeID::from(0), &context.ctx, bytes);
}
#[must_use]
pub fn tree(&self) -> &Tree {
&self.tree
}
#[must_use]
pub fn tree_mut(&mut self) -> &mut Tree {
&mut self.tree
}
}
impl Hash for NautilusInput {
fn hash<H: Hasher>(&self, state: &mut H) {
self.tree().paren.hash(state);
for r in &self.tree().rules {
match r {
RuleIDOrCustom::Custom(a, b) => {
a.hash(state);
b.hash(state);
}
RuleIDOrCustom::Rule(a) => a.hash(state),
}
}
self.tree().sizes.hash(state);
}
}
#[derive(Debug)]
pub struct NautilusToBytesInputConverter<'a> {
ctx: &'a NautilusContext,
}
impl<'a> NautilusToBytesInputConverter<'a> {
#[must_use]
pub fn new(ctx: &'a NautilusContext) -> Self {
Self { ctx }
}
}
impl<'a> InputConverter for NautilusToBytesInputConverter<'a> {
type From = NautilusInput;
type To = BytesInput;
fn convert(&mut self, input: Self::From) -> Result<Self::To, Error> {
let mut bytes = vec![];
input.unparse(self.ctx, &mut bytes);
Ok(BytesInput::new(bytes))
}
}