#[cfg(feature = "bevy")]
use bevy_reflect::prelude::*;
use crate::{
collections::HashSet,
layout::{LayoutParser, Rule},
};
use pest::Parser;
use serde::{Deserialize, Serialize};
use std::{
error::Error,
str::{Bytes, Chars, FromStr},
};
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "bevy", derive(Reflect), reflect(Debug))]
pub struct Token(Vec<Sequence>);
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
#[cfg_attr(feature = "bevy", derive(Reflect), reflect(Debug))]
#[serde(transparent)]
pub struct Sequence(String);
impl Sequence {
#[inline]
pub fn new(s: impl AsRef<str>) -> Option<Self> {
let s = s.as_ref();
if s.is_empty() {
None
} else {
Some(Self(s.to_string()))
}
}
pub fn new_unchecked(s: impl Into<String>) -> Self {
Self(s.into())
}
#[inline]
pub fn as_str(&self) -> &str {
&self.0
}
#[inline]
pub fn chars(&self) -> Chars<'_> {
self.0.chars()
}
#[inline]
pub fn bytes(&self) -> Bytes<'_> {
self.0.bytes()
}
#[inline]
pub fn len(&self) -> usize {
self.0.chars().count()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl From<Vec<Sequence>> for Token {
#[inline]
fn from(sub_tokens: Vec<Sequence>) -> Self {
Self(sub_tokens)
}
}
impl From<Sequence> for Token {
#[inline]
fn from(sub_token: Sequence) -> Self {
Token(vec![sub_token])
}
}
impl From<char> for Token {
#[inline]
fn from(c: char) -> Self {
Token::from(Sequence::from(c))
}
}
impl From<char> for Sequence {
#[inline]
fn from(c: char) -> Self {
Sequence(c.to_string())
}
}
impl AsRef<[u8]> for Sequence {
#[inline]
fn as_ref(&self) -> &[u8] {
self.0.as_bytes()
}
}
impl AsRef<str> for Sequence {
#[inline]
fn as_ref(&self) -> &str {
&self.0
}
}
#[derive(Debug)]
pub enum IntoSequenceError {
ExpectedSingleSequence(Token),
EmptyToken,
}
impl Error for IntoSequenceError {}
impl std::fmt::Display for IntoSequenceError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IntoSequenceError::ExpectedSingleSequence(token) => {
write!(f, "Expected exactly one sequence in token, found {}", token)
}
IntoSequenceError::EmptyToken => {
write!(f, "Cannot convert empty token into a sequence")
}
}
}
}
impl TryFrom<Token> for Sequence {
type Error = IntoSequenceError;
#[inline]
fn try_from(token: Token) -> Result<Self, Self::Error> {
if token.len() > 1 {
Err(IntoSequenceError::ExpectedSingleSequence(token))
} else {
token
.into_iter()
.next()
.ok_or(IntoSequenceError::EmptyToken)
}
}
}
impl Token {
#[inline]
pub fn parse(input: &str) -> Result<Self, TokenParsingError> {
input.parse()
}
pub fn iter(&self) -> std::slice::Iter<'_, Sequence> {
self.0.iter()
}
#[inline]
pub fn first(&self) -> Option<&Sequence> {
self.0.first()
}
#[inline]
pub fn len(&self) -> usize {
self.0.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl IntoIterator for Token {
type Item = Sequence;
type IntoIter = std::vec::IntoIter<Sequence>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl Serialize for Token {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl std::fmt::Display for Token {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut iter = self.iter().peekable();
while let Some(sub) = iter.next() {
match sub.len() {
0 => write!(f, ""),
1 => write!(f, "{}", sub.0),
_ => write!(f, "$({})", sub.0),
}?;
if iter.peek().is_some() {
write!(f, "|")?;
}
}
Ok(())
}
}
impl std::fmt::Display for Sequence {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug)]
pub enum TokenParsingError {
PestError(pest::error::Error<Rule>),
EmptyToken,
UnexpectedEOI,
}
impl Error for TokenParsingError {}
impl From<pest::error::Error<Rule>> for TokenParsingError {
fn from(e: pest::error::Error<Rule>) -> Self {
TokenParsingError::PestError(e)
}
}
impl std::fmt::Display for TokenParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TokenParsingError::PestError(e) => write!(f, "{}", e),
TokenParsingError::EmptyToken => write!(f, "Empty token is not allowed"),
TokenParsingError::UnexpectedEOI => write!(f, "Unexpected end of input"),
}
}
}
impl FromStr for Token {
type Err = TokenParsingError;
fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
let mut pairs = match LayoutParser::parse(Rule::single_token, input) {
Ok(pairs) => pairs,
Err(e) => {
return Err(TokenParsingError::PestError(e.renamed_rules(
|r| match *r {
Rule::EOI => "EOI (Too many chars for a subtoken)".to_string(),
_ => format!("{:?}", r),
},
)));
}
};
let Some(pair) = pairs.next() else {
return Err(TokenParsingError::EmptyToken);
};
let mut sub_tokens = Vec::new();
match pair.as_rule() {
Rule::any_char => {
if let Some(sequence) = Sequence::new(pair.as_str()) {
sub_tokens.push(sequence);
}
}
Rule::multi_union => {
let sub_sequences = pair.into_inner();
let mut string = String::new();
for sub in sub_sequences {
debug_assert!(
matches!(sub.as_rule(), Rule::sub),
"Expected sub rule in multi_union sequence, found {:?}",
sub.as_rule()
);
for seq in sub.into_inner() {
debug_assert!(
matches!(seq.as_rule(), Rule::any_char | Rule::RESERVED),
"Expected any_char or RESERVED rule in multi_union::sub::seq, found {:?}",
seq.as_rule()
);
let s = seq.as_str();
string.push_str(s);
}
if string.is_empty() {
return Err(TokenParsingError::EmptyToken);
}
sub_tokens.push(Sequence(std::mem::take(&mut string)));
}
}
Rule::EOI => {
return Err(TokenParsingError::UnexpectedEOI);
}
_ => unreachable!(),
}
Ok(Self(sub_tokens))
}
}
impl<'de> Deserialize<'de> for Token {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct TokenVisitor;
impl<'de> serde::de::Visitor<'de> for TokenVisitor {
type Value = Token;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a raster font layout token string")
}
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_err(serde::de::Error::custom)
}
fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
v.parse().map_err(serde::de::Error::custom)
}
fn visit_char<E>(self, v: char) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Token::from(v))
}
}
deserializer.deserialize_any(TokenVisitor)
}
}
#[cfg(test)]
mod parser_tests {
use super::*;
#[test]
fn test_simple() {
println!("{}", Token::parse("$(:))").unwrap());
}
#[test]
fn token_parser() {
assert_eq!(Token::from('a'), Token::from(Sequence::new_unchecked("a")));
assert!(Token::from_str(r#"$a"#).is_err());
assert_eq!(
Token::from_str(r#"$($a)"#).unwrap(),
Token::from(Sequence::new_unchecked("$a"))
);
assert_eq!(
Token::from_str("$($bc)").unwrap(),
Token::from(Sequence::new_unchecked("$bc"))
);
assert_eq!(
Token::from_str("$(abc)").unwrap(),
Token::from(Sequence::new_unchecked("abc"))
);
assert_eq!(
Token::from_str("$(\\|)").unwrap(),
Token::from(Sequence::new_unchecked("|"))
);
assert!(Token::from_str(r#"\$(abc)"#).is_err());
assert_eq!(
Token::from_str(r#"$(\$(abc)"#).unwrap(),
Token::from(Sequence::new_unchecked("$(abc"))
);
assert!(Token::from_str(r#"$(abc\)"#).is_err());
assert_eq!(
Token::from_str(r#"$(abc\))"#).unwrap(),
Token::from(Sequence::new_unchecked("abc)"))
);
assert_eq!(
Token::from_str("$(a|b|c)").unwrap(),
Token::from(vec![
Sequence::new_unchecked("a"),
Sequence::new_unchecked("b"),
Sequence::new_unchecked("c")
])
);
assert_eq!(
Token::from_str(r#"$(a|$bc|\|||foo)"#).unwrap(),
Token::from(vec![
Sequence::new_unchecked("a"),
Sequence::new_unchecked("$bc"),
Sequence::new_unchecked("|"),
Sequence::new_unchecked("foo")
])
);
assert_eq!(
Token::from_str(r#"$(a|$bc|\||foo|\$($dc\))"#).unwrap(),
Token::from(vec![
Sequence::new_unchecked("a"),
Sequence::new_unchecked("$bc"),
Sequence::new_unchecked("|"),
Sequence::new_unchecked("foo"),
Sequence::new_unchecked("$($dc)")
])
);
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Unique<'a> {
pub sequences: HashSet<&'a Sequence>,
pub num_regions: usize,
}
impl<'a, I> From<I> for Unique<'a>
where
I: IntoIterator<Item = &'a Token>,
{
fn from(tokens: I) -> Self {
let mut sequences = HashSet::new();
let num_regions = tokens
.into_iter()
.map(|token| {
let mut con = 1;
for seq in token.iter() {
if sequences.contains(seq) {
con = 0;
}
sequences.insert(seq);
}
con
})
.sum();
Self {
sequences,
num_regions,
}
}
}