nsid 0.0.1

NameSpaced IDs (NSIDs) for the AT Protocol.
Documentation
use std::iter::Peekable;

use crate::lexer::{Lexer, Token, TokenKind};

/// An error from parsing an NSID.
#[derive(Debug, PartialEq, Eq)]
pub enum ParseNsidError {
    /// The NSID contained too few segments.
    ///
    /// NSIDs must contain a minimum of three (3) segments.
    TooFewSegments,

    /// A syntax error was encountered while parsing the NSID.
    SyntaxError(String),
}

pub struct Parser<'a> {
    lexer: Peekable<Lexer<'a>>,
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Self {
        Self {
            lexer: Lexer::new(input).peekable(),
        }
    }

    pub fn parse(self) -> Result<Vec<String>, ParseNsidError> {
        let tokens: Vec<Token> = self.lexer.collect();

        let mut segments: Vec<String> = Vec::new();
        let mut current_segment: Option<String> = None;

        let tokens_len = tokens.len();
        for (index, token) in tokens.into_iter().enumerate() {
            match current_segment.as_mut() {
                Some(segment) => match token.kind {
                    TokenKind::Alpha | TokenKind::Number | TokenKind::Dash => {
                        *segment += token.lexeme;
                    }
                    TokenKind::Delim => {
                        segments.push(segment.to_string());
                        current_segment = None;
                    }
                    TokenKind::Star => {
                        *segment += token.lexeme;
                    }
                    TokenKind::Error => Err(ParseNsidError::SyntaxError(token.lexeme.to_string()))?,
                },
                None => match token.kind {
                    TokenKind::Alpha => {
                        current_segment = Some(token.lexeme.to_string());
                    }
                    TokenKind::Number | TokenKind::Dash | TokenKind::Delim => {
                        Err(ParseNsidError::SyntaxError(token.lexeme.to_string()))?
                    }
                    TokenKind::Star => {
                        if index == tokens_len - 1 {
                            current_segment = Some(token.lexeme.to_string())
                        } else {
                            Err(ParseNsidError::SyntaxError(token.lexeme.to_string()))?
                        }
                    }
                    TokenKind::Error => Err(ParseNsidError::SyntaxError(token.lexeme.to_string()))?,
                },
            }
        }

        if let Some(current_segment) = current_segment {
            segments.push(current_segment);
        }

        Ok(segments)
    }
}