use sashite_sin::Identifier as Style;
use crate::error::ParseError;
use crate::limits::{MAX_SQUARE_COUNT, MAX_STRING_LENGTH};
use crate::shape::Shape;
use crate::{hands, placement, style_turn};
#[derive(Debug, Clone, Copy)]
pub(crate) struct Parsed<'a> {
pub(crate) placement: &'a [u8],
pub(crate) hands: &'a [u8],
pub(crate) shape: Shape,
pub(crate) board_pieces: u32,
pub(crate) hand_pieces: u32,
pub(crate) active: Style,
pub(crate) inactive: Style,
}
pub(crate) fn parse(input: &str) -> Result<Parsed<'_>, ParseError> {
let bytes = input.as_bytes();
if bytes.len() > MAX_STRING_LENGTH {
return Err(ParseError::InputTooLong);
}
if !input.is_ascii() {
return Err(ParseError::NonAscii);
}
let mut fields = bytes.split(|&b| b == b' ');
let (Some(placement_field), Some(hands_field), Some(style_field), None) =
(fields.next(), fields.next(), fields.next(), fields.next())
else {
return Err(ParseError::FieldCount);
};
if placement_field.is_empty() || hands_field.is_empty() || style_field.is_empty() {
return Err(ParseError::FieldCount);
}
let (shape, board_pieces) = placement::validate(placement_field)?;
let hand_pieces = hands::validate(hands_field)?;
let (active, inactive) = style_turn::validate(style_field)?;
let squares = shape.square_count();
if squares > MAX_SQUARE_COUNT {
return Err(ParseError::TooManySquares);
}
let pieces = board_pieces.saturating_add(hand_pieces);
if pieces > squares {
return Err(ParseError::TooManyPieces);
}
Ok(Parsed {
placement: placement_field,
hands: hands_field,
shape,
board_pieces,
hand_pieces,
active,
inactive,
})
}