kosame_dsl 0.3.0

Macro-based Rust ORM focused on developer ergonomics
Documentation
use std::borrow::Cow;

use crate::pretty::RingBuffer;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextMode {
    Always,
    NoBreak,
    Break,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum BreakMode {
    Consistent,
    Inconsistent,
}

#[derive(Debug)]
pub(super) enum Token<'a> {
    Text(TextToken<'a>),
    Break(BreakToken),
    ForceBreak,
    Begin(BeginToken),
    End,
}

#[derive(Debug)]
pub(super) struct TextToken<'a> {
    string: Cow<'a, str>,
    mode: TextMode,
}

impl<'a> TextToken<'a> {
    pub(super) fn new(string: Cow<'a, str>, mode: TextMode) -> Self {
        Self { string, mode }
    }

    pub(super) fn string(&self) -> &str {
        &self.string
    }

    pub(super) fn mode(&self) -> TextMode {
        self.mode
    }
}

#[derive(Debug)]
pub(super) struct BreakToken {
    len: isize,
    indent: isize,
}

impl BreakToken {
    pub(super) fn new(len: isize, indent: isize) -> Self {
        Self { len, indent }
    }

    pub fn push_len(&mut self, len: isize) {
        self.len += len;
    }

    pub(super) fn len(&self) -> isize {
        self.len
    }

    pub(super) fn indent(&self) -> isize {
        self.indent
    }
}

#[derive(Debug)]
pub(super) struct BeginToken {
    mode: BreakMode,
    len: isize,
}

impl BeginToken {
    pub fn push_len(&mut self, len: isize) {
        self.len += len;
    }

    pub(super) fn mode(&self) -> BreakMode {
        self.mode
    }

    pub fn len(&self) -> isize {
        self.len
    }
}

impl BeginToken {
    pub(super) fn new(mode: BreakMode, len: isize) -> Self {
        Self { mode, len }
    }
}

pub(super) struct TokenBuffer<'a> {
    tokens: RingBuffer<Token<'a>>,
    last_break: Option<usize>,
    begin_stack: Vec<usize>,
}

impl<'a> TokenBuffer<'a> {
    pub fn new() -> Self {
        Self {
            tokens: RingBuffer::new(),
            last_break: None,
            begin_stack: Vec::new(),
        }
    }

    pub fn last_break_mut(&mut self) -> Option<&mut BreakToken> {
        match &self.last_break {
            Some(index) => match &mut self.tokens[*index] {
                Token::Break(break_token) => Some(break_token),
                _ => unreachable!(),
            },
            _ => None,
        }
    }

    pub fn current_begin_mut(&mut self) -> Option<&mut BeginToken> {
        match self.begin_stack.last() {
            Some(index) => match &mut self.tokens[*index] {
                Token::Begin(begin_token) => Some(begin_token),
                _ => unreachable!(),
            },
            _ => None,
        }
    }

    pub fn push_len(&mut self, len: isize) {
        if let Some(last_break) = self.last_break_mut() {
            last_break.push_len(len);
        }
        if let Some(current_begin) = self.current_begin_mut() {
            current_begin.push_len(len);
        }
    }

    pub fn push_back(&mut self, token: Token<'a>) {
        match &token {
            Token::Text(_) => {}
            Token::Break(_) => self.last_break = Some(self.tokens.next_index()),
            Token::ForceBreak => {}
            Token::Begin(_) => self.begin_stack.push(self.tokens.next_index()),
            Token::End => {
                self.begin_stack.pop();
                self.last_break = None;
            }
        }
        self.tokens.push_back(token);
    }

    pub fn pop_front(&mut self) -> Option<Token<'a>> {
        self.tokens.pop_front()
    }

    pub fn is_empty(&self) -> bool {
        self.tokens.is_empty()
    }
}