use core::iter::repeat;
use alloc::{vec::Vec, vec};
use crate::{error::NodeError, nav::{self, MoveVerticalDirection, NavPath, NavPathNavigator}, render::{Glyph, LayoutBlock, Layoutable, Renderer, Viewport, ViewportVisibility, LayoutComputationProperties, CalculatedPoint}};
use super::{common, parser, structured::StructuredNode, function::Function};
#[derive(Clone)]
pub enum UnstructuredItem<'a> {
Node(&'a UnstructuredNode),
List(&'a UnstructuredNodeList),
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum Token {
Add,
Subtract,
Multiply,
Divide,
Digit(u8),
Point,
Variable(char),
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum UnstructuredNode {
Token(Token),
Sqrt(UnstructuredNodeList),
Fraction(UnstructuredNodeList, UnstructuredNodeList),
Parentheses(UnstructuredNodeList),
Power(UnstructuredNodeList),
FunctionCall(Function, Vec<UnstructuredNodeList>),
}
impl UnstructuredNode {
pub fn new_function_call(func: Function) -> Self {
let arg_vec = repeat(UnstructuredNodeList::new()).take(func.argument_count()).collect();
Self::FunctionCall(func, arg_vec)
}
}
#[derive(PartialEq, Eq, Debug, Clone, Default)]
pub struct UnstructuredNodeList {
pub items: Vec<UnstructuredNode>
}
impl UnstructuredNodeList {
pub fn new() -> Self {
Self::default()
}
}
#[derive(PartialEq, Eq, Debug, Clone, Default)]
pub struct UnstructuredNodeRoot {
pub root: UnstructuredNodeList
}
impl UnstructuredNodeRoot {
pub fn new() -> Self {
Self::default()
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum MoveResult {
MovedWithin,
MovedOut,
}
pub trait Navigable {
fn navigate(&mut self, path: &mut NavPathNavigator) -> (&mut UnstructuredNodeList, usize) {
self.navigate_trace(path, |_| {})
}
fn navigate_trace<F>(&mut self, path: &mut NavPathNavigator, trace: F) -> (&mut UnstructuredNodeList, usize)
where F : FnMut(UnstructuredItem);
}
impl Navigable for UnstructuredNode {
fn navigate_trace<F>(&mut self, path: &mut NavPathNavigator, mut trace: F) -> (&mut UnstructuredNodeList, usize)
where F : FnMut(UnstructuredItem)
{
trace(UnstructuredItem::Node(&self.clone()));
if path.here() {
panic!("navigation path must end on unstructured node");
}
let next_index = path.next();
let step_path = &mut path.step();
match self {
UnstructuredNode::Sqrt(inner) => {
if next_index != 0 {
panic!("index out of range for sqrt navigation")
}
inner.navigate_trace(step_path, trace)
},
UnstructuredNode::Parentheses(inner) => {
if next_index != 0 {
panic!("index out of range for parens navigation")
}
inner.navigate_trace(step_path, trace)
},
UnstructuredNode::Fraction(top, bottom) => {
if next_index == 0 {
top.navigate_trace(step_path, trace)
} else if next_index == 1 {
bottom.navigate_trace(step_path, trace)
} else {
panic!("index out of range for divide navigation")
}
},
UnstructuredNode::Power(exp) => {
if next_index != 0 {
panic!("index out of range for power navigation")
}
exp.navigate_trace(step_path, trace)
}
UnstructuredNode::FunctionCall(_, args) => {
if next_index >= args.len() {
panic!("index out of range for function call navigation")
}
args[next_index].navigate_trace(step_path, trace)
}
UnstructuredNode::Token(_) => panic!("cannot navigate into token"),
}
}
}
impl Navigable for UnstructuredNodeList {
fn navigate_trace<F>(&mut self, path: &mut NavPathNavigator, mut trace: F) -> (&mut UnstructuredNodeList, usize)
where F : FnMut(UnstructuredItem)
{
trace(UnstructuredItem::List(&self.clone()));
if path.here() {
return (self, path.next());
}
self.items[path.next()].navigate_trace(&mut path.step(), trace)
}
}
impl UnstructuredNodeRoot {
pub fn ensure_cursor_visible(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>) {
if let Some(viewport) = viewport {
let cursor_visibility = renderer.cursor_visibility(
self,
&mut path.to_navigator(),
Some(&*viewport),
);
if let ViewportVisibility::Clipped { top_clip, bottom_clip, left_clip, right_clip, .. } = cursor_visibility {
match (top_clip, bottom_clip) {
(0, 0) => (),
(_, 0) => viewport.offset.y -= top_clip,
(0, _) => viewport.offset.y += bottom_clip,
_ => panic!("cursor does not fit vertically in viewport"),
}
match (left_clip, right_clip) {
(0, 0) => (),
(_, 0) => viewport.offset.x -= left_clip,
(0, _) => viewport.offset.x += right_clip,
_ => panic!("cursor does not fit horizontally in viewport"),
}
}
}
}
pub fn move_right(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>) {
let (current_node, index) = self.root.navigate(&mut path.to_navigator());
let children = ¤t_node.items;
if index == children.len() {
if !path.root() {
let mut outer_path = path.clone();
outer_path.pop(2);
let (outer_node, index) = self.root.navigate(&mut outer_path.to_navigator());
if let UnstructuredNode::FunctionCall(_, args) = &outer_node.items[index] {
let current_arg_index = path[path.len() - 2];
if current_arg_index < args.len() - 1 {
path.pop(2);
path.push(current_arg_index + 1);
path.push(0);
return
}
}
path.pop(2);
path.offset(1);
} else {
}
} else {
let right_child = &children[index];
match right_child {
UnstructuredNode::Sqrt(_) | UnstructuredNode::Fraction(_, _) | UnstructuredNode::Parentheses(_) | UnstructuredNode::Power(_) | UnstructuredNode::FunctionCall(_, _) => {
path.push(0);
path.push(0);
},
UnstructuredNode::Token(_) => path.offset(1),
}
}
self.ensure_cursor_visible(path, renderer, viewport);
}
pub fn move_left(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>) {
let (current_node, index) = self.root.navigate(&mut path.to_navigator());
let children = ¤t_node.items;
if index == 0 {
if !path.root() {
let mut outer_path = path.clone();
outer_path.pop(2);
let (outer_node, index) = self.root.navigate(&mut outer_path.to_navigator());
if let UnstructuredNode::FunctionCall(_, args) = &outer_node.items[index] {
let current_arg_index = path[path.len() - 2];
if current_arg_index > 0 {
path.pop(2);
path.push(current_arg_index - 1);
path.push(args[current_arg_index - 1].items.len());
return
}
}
path.pop(2);
} else {
}
} else {
path.offset(-1);
let left_child = &children[index - 1];
match left_child {
UnstructuredNode::Sqrt(n) | UnstructuredNode::Fraction(n, _) | UnstructuredNode::Parentheses(n) | UnstructuredNode::Power(n) => {
path.push(0);
path.push(n.items.len());
},
UnstructuredNode::FunctionCall(_, args) => {
path.push(args.len() - 1);
path.push(args.last().expect("no args in call").items.len());
}
UnstructuredNode::Token(_) => (),
}
}
self.ensure_cursor_visible(path, renderer, viewport);
}
fn move_vertically(
&mut self,
path: &mut NavPath,
direction: MoveVerticalDirection,
renderer: &mut impl Renderer,
viewport: Option<&mut Viewport>
) -> MoveResult {
let mut moved_within = false;
for (i, ri, item) in self.nav_nodes_outwards(path) {
if let UnstructuredNode::Fraction(ref top, ref bottom) = item {
let (index_allowing_movement, index_to_move_to) = match direction {
MoveVerticalDirection::Up => (1, 0),
MoveVerticalDirection::Down => (0, 1),
};
if path[i] == index_allowing_movement {
let match_points = nav::match_vertical_cursor_points(
renderer, top, bottom, direction
);
let new_index = match_points[path[i + 1]];
path.pop(ri + 1);
path.push(index_to_move_to);
path.push(new_index);
moved_within = true;
break;
} else {
}
}
}
self.ensure_cursor_visible(path, renderer, viewport);
if moved_within {
MoveResult::MovedWithin
} else {
MoveResult::MovedOut
}
}
pub fn move_down(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>) -> MoveResult {
self.move_vertically(path, MoveVerticalDirection::Down, renderer, viewport)
}
pub fn move_up(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>) -> MoveResult {
self.move_vertically(path, MoveVerticalDirection::Up, renderer, viewport)
}
pub fn insert(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, viewport: Option<&mut Viewport>, new_node: UnstructuredNode) {
let (current_node, index) = self.root.navigate(&mut path.to_navigator());
current_node.items.insert(index, new_node.clone());
match new_node {
UnstructuredNode::Sqrt(_) | UnstructuredNode::Fraction(_, _) | UnstructuredNode::Parentheses(_) | UnstructuredNode::Power(_) | UnstructuredNode::FunctionCall(_, _) => {
path.push(0);
path.push(0);
},
UnstructuredNode::Token(_) => path.offset(1),
}
self.ensure_cursor_visible(path, renderer, viewport);
}
pub fn delete(&mut self, path: &mut NavPath, renderer: &mut impl Renderer, mut viewport: Option<&mut Viewport>) {
let (current_node, index) = self.root.navigate(&mut path.to_navigator());
if index > 0 {
current_node.items.remove(index - 1);
path.offset(-1);
} else {
if !path.root() {
self.move_right(path, renderer, viewport.as_mut().map(|x| x as _));
self.delete(path, renderer, viewport.as_mut().map(|x| x as _));
}
}
self.ensure_cursor_visible(path, renderer, viewport.as_mut().map(|x| x as _));
}
pub fn clear(&mut self, path: &mut NavPath, _renderer: &mut impl Renderer, mut viewport: Option<&mut Viewport>) {
self.root.items = vec![];
*path = NavPath::new(vec![0]);
viewport.as_mut().map(|x| x.offset = CalculatedPoint { x: 0, y: 0 });
}
fn nav_node_list(&mut self, path: &mut NavPath) -> Vec<Option<UnstructuredNode>> {
let mut nav_items = vec![];
self.root.navigate_trace(
&mut path.to_navigator(),
|item| {
if let UnstructuredItem::Node(node) = item {
nav_items.push(Some(node.clone()));
} else {
nav_items.push(None);
}
}
);
nav_items
}
fn nav_nodes_outwards(&mut self, path: &mut NavPath) -> Vec<(usize, usize, UnstructuredNode)> {
let mut result = vec![];
let nav_items = self.nav_node_list(path);
let nav_items_len = nav_items.len();
for (i, item) in nav_items.into_iter().rev().enumerate() {
if let Some(node) = item {
let true_index = (nav_items_len - i) - 1;
result.push((true_index, i, node));
}
}
result
}
}
pub trait Upgradable {
fn upgrade(&self) -> Result<StructuredNode, NodeError>;
}
impl Upgradable for UnstructuredNodeList {
fn upgrade(&self) -> Result<StructuredNode, NodeError> {
parser::Parser {
index: 0,
nodes: &self.items[..]
}.parse()
}
}
impl Upgradable for UnstructuredNodeRoot {
fn upgrade(&self) -> Result<StructuredNode, NodeError> {
self.root.upgrade()
}
}
impl Upgradable for UnstructuredNode {
fn upgrade(&self) -> Result<StructuredNode, NodeError> {
match self {
UnstructuredNode::Sqrt(inner)
=> Ok(StructuredNode::Sqrt(box inner.upgrade()?)),
UnstructuredNode::Parentheses(inner)
=> Ok(StructuredNode::Parentheses(box inner.upgrade()?)),
UnstructuredNode::Fraction(a, b)
=> Ok(StructuredNode::Divide(box a.upgrade()?, box b.upgrade()?)),
UnstructuredNode::Power(_)
=> Err(NodeError::PowerMissingBase),
UnstructuredNode::FunctionCall(func, args)
=> Ok(StructuredNode::FunctionCall(*func,
args.iter().map(|a| a.upgrade()).collect::<Result<Vec<_>, _>>()?
)),
UnstructuredNode::Token(_) => Err(NodeError::CannotUpgradeToken),
}
}
}
impl Layoutable for UnstructuredNodeRoot {
fn layout(&self, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock {
self.root.layout(renderer, path, properties)
}
}
impl Layoutable for UnstructuredNode {
fn layout(&self, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> crate::render::LayoutBlock {
match self {
UnstructuredNode::Token(token)
=> LayoutBlock::from_glyph(renderer, (*token).into(), properties),
UnstructuredNode::Sqrt(inner)
=> common::layout_sqrt(inner, renderer, path, properties),
UnstructuredNode::Fraction(top, bottom)
=> common::layout_fraction(top, bottom, renderer, path, properties),
UnstructuredNode::Parentheses(inner)
=> common::layout_parentheses(inner, renderer, path, properties),
UnstructuredNode::Power(exp)
=> common::layout_power(None, exp, renderer, path, properties),
UnstructuredNode::FunctionCall(func, args)
=> common::layout_function_call(*func, args, renderer, path, properties),
}
}
}
impl Layoutable for UnstructuredNodeList {
fn layout(&self, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> LayoutBlock {
let children = &self.items;
let mut paths = vec![];
let mut cursor_insertion_index = None;
unsafe {
if let Some(p) = path {
let p = p as *mut NavPathNavigator;
for i in 0..children.len() {
paths.push({
if p.as_mut().unwrap().next() == i && !p.as_mut().unwrap().here() {
Some(p.as_mut().unwrap().step())
} else {
None
}
})
}
if p.as_mut().unwrap().here() {
cursor_insertion_index = Some(p.as_mut().unwrap().next());
}
} else {
for _ in 0..children.len() {
paths.push(None);
}
}
}
let mut layouts = children
.iter()
.enumerate()
.map(|(i, node)| node.layout(
renderer,
(&mut paths[i]).as_mut(),
properties,
))
.collect::<Vec<_>>();
if let Some(idx) = cursor_insertion_index {
let temp_layout;
let cursor_match_layout = if layouts.is_empty() {
temp_layout = Some(LayoutBlock::from_glyph(renderer, Glyph::Digit {
number: 0
}, properties));
&temp_layout.as_ref().unwrap()
} else if idx == 0 {
&layouts[idx]
} else if idx == layouts.len() {
&layouts[idx - 1]
} else {
let after = &layouts[idx];
let before = &layouts[idx - 1];
if after.area.height > before.area.height {
after
} else {
before
}
};
let cursor_height = cursor_match_layout.area.height;
let cursor_baseline = cursor_match_layout.baseline;
let mut cursor_layout = LayoutBlock::from_glyph(renderer, Glyph::Cursor {
height: cursor_height,
}, properties);
cursor_layout.baseline = cursor_baseline;
layouts.insert(idx, cursor_layout)
}
if layouts.is_empty() {
layouts.push(LayoutBlock::from_glyph(renderer, Glyph::Placeholder, properties))
}
LayoutBlock::layout_horizontal(&layouts[..])
}
}
impl<'a> Layoutable for UnstructuredItem<'a> {
fn layout(&self, renderer: &mut impl Renderer, path: Option<&mut NavPathNavigator>, properties: LayoutComputationProperties) -> crate::render::LayoutBlock {
match self {
UnstructuredItem::Node(node) => node.layout(renderer, path, properties),
UnstructuredItem::List(children) => children.layout(renderer, path, properties),
}
}
}
pub trait Serializable where Self: Sized {
fn serialize(&self) -> Vec<u8>;
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self>;
}
impl<T : num_traits::PrimInt> Serializable for T {
fn serialize(&self) -> Vec<u8> {
if self < &Self::zero() { panic!("cannot serialize negative numbers"); }
let mut result = vec![];
let mut current = *self;
while current >= Self::from(0xFF).unwrap() {
current = current - Self::from(0xFF).unwrap();
result.push(0xFF);
}
result.push(num_traits::cast(current).unwrap());
result
}
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self> {
let mut result = Self::zero();
loop {
let byte = bytes.next()?;
result = result + Self::from(byte).unwrap();
if byte != 0xFF { break; }
}
Some(result)
}
}
impl Serializable for UnstructuredNodeRoot {
fn serialize(&self) -> Vec<u8> {
self.root.serialize()
}
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self> {
Some(UnstructuredNodeRoot {
root: UnstructuredNodeList::deserialize(bytes)?
})
}
}
impl Serializable for UnstructuredNode {
fn serialize(&self) -> Vec<u8> {
match self {
UnstructuredNode::Token(t) => {
let mut token_bytes = t.serialize();
if token_bytes[0] > 0b01111111 { panic!(); }
token_bytes[0] |= 0b10000000;
token_bytes
},
UnstructuredNode::Sqrt(i) => {
let mut n = vec![1];
n.append(&mut i.serialize());
n
},
UnstructuredNode::Fraction(t, b) => {
let mut n = vec![2];
n.append(&mut t.serialize());
n.append(&mut b.serialize());
n
}
UnstructuredNode::Parentheses(i) => {
let mut n = vec![3];
n.append(&mut i.serialize());
n
},
UnstructuredNode::Power(e) => {
let mut n = vec![4];
n.append(&mut e.serialize());
n
},
UnstructuredNode::FunctionCall(func, args) => {
let mut n = vec![5];
n.append(&mut func.serialize());
n.append(&mut vec![args.len() as u8]);
for arg in args {
n.append(&mut arg.serialize());
}
n
}
}
}
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self> {
let first_byte = bytes.next()?;
match first_byte {
_ if first_byte & 0b10000000 > 0 =>
Some(UnstructuredNode::Token(
Token::deserialize(&mut vec![first_byte & 0b01111111]
.into_iter()
.chain(bytes))?)
),
1 => Some(UnstructuredNode::Sqrt(UnstructuredNodeList::deserialize(bytes)?)),
2 => Some(UnstructuredNode::Fraction(
UnstructuredNodeList::deserialize(bytes)?,
UnstructuredNodeList::deserialize(bytes)?,
)),
3 => Some(UnstructuredNode::Parentheses(UnstructuredNodeList::deserialize(bytes)?)),
4 => Some(UnstructuredNode::Power(
UnstructuredNodeList::deserialize(bytes)?,
)),
5 => {
let func = Function::deserialize(bytes)?;
let arg_count = bytes.next()?;
let mut args = vec![];
for _ in 0..arg_count {
args.push(UnstructuredNodeList::deserialize(bytes)?);
}
Some(UnstructuredNode::FunctionCall(func, args))
},
_ => None,
}
}
}
impl Serializable for UnstructuredNodeList {
fn serialize(&self) -> Vec<u8> {
let mut result = vec![];
result.append(&mut self.items.len().serialize());
for item in &self.items {
result.append(&mut item.serialize());
}
result
}
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self> {
let len = usize::deserialize(bytes)?;
let mut result = vec![];
for _ in 0..len {
result.push(UnstructuredNode::deserialize(bytes)?);
}
Some(UnstructuredNodeList { items: result })
}
}
impl Serializable for Token {
fn serialize(&self) -> Vec<u8> {
vec![match self {
Token::Add => 1,
Token::Subtract => 2,
Token::Multiply => 3,
Token::Divide => 4,
Token::Digit(d) => 5 + *d,
Token::Point => 15,
Token::Variable(c) => return vec![16, *c as u8],
}]
}
fn deserialize(bytes: &mut dyn Iterator<Item = u8>) -> Option<Self> {
let byte = bytes.next()?;
Some(match byte {
1 => Token::Add,
2 => Token::Subtract,
3 => Token::Multiply,
4 => Token::Divide,
5..=14 => Token::Digit(byte - 5),
15 => Token::Point,
16 => Token::Variable(bytes.next()? as char),
_ => return None,
})
}
}