Add token struct and traits
Signed-off-by: trivernis <trivernis@protonmail.com>pull/1/head
parent
3df49ca9a9
commit
7298b79c5a
@ -1,5 +1,6 @@
|
|||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod input_reader;
|
pub mod input_reader;
|
||||||
|
pub mod token;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -1 +1,2 @@
|
|||||||
mod test_input;
|
mod test_input;
|
||||||
|
mod test_token;
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
use crate::error::TapeResult;
|
||||||
|
use crate::input_reader::InputReader;
|
||||||
|
use crate::token::{ProtoToken, Token};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct TestToken(i32);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl ProtoToken for TestToken {
|
||||||
|
async fn try_parse(reader: &mut InputReader) -> TapeResult<Option<Token>> {
|
||||||
|
let mut num = String::new();
|
||||||
|
while !reader.check_eof().await && reader.peek().await?.is_numeric() {
|
||||||
|
num.push(reader.consume().await?);
|
||||||
|
}
|
||||||
|
if num.is_empty() {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Ok(Some(Token::new(TestToken(num.parse::<i32>().unwrap()))))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn it_parses() {
|
||||||
|
let mut reader = InputReader::new(Cursor::new("128"));
|
||||||
|
let token = TestToken::try_parse(&mut reader).await.unwrap();
|
||||||
|
assert!(token.is_some());
|
||||||
|
let token = token.unwrap().try_into::<TestToken>().unwrap();
|
||||||
|
assert_eq!(token.0, 128);
|
||||||
|
|
||||||
|
let mut reader = InputReader::new(Cursor::new("string a12 24\n"));
|
||||||
|
let token = TestToken::try_parse(&mut reader).await.unwrap();
|
||||||
|
assert!(token.is_none());
|
||||||
|
reader.seek_to(8).await.unwrap();
|
||||||
|
|
||||||
|
let token = TestToken::try_parse(&mut reader).await.unwrap();
|
||||||
|
assert!(token.is_some());
|
||||||
|
let token = token.unwrap().try_into::<TestToken>().unwrap();
|
||||||
|
assert_eq!(token.0, 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn it_converts() {
|
||||||
|
let token = Token::new(TestToken(12));
|
||||||
|
assert!(token.is::<TestToken>());
|
||||||
|
|
||||||
|
let test_token = token.try_as::<TestToken>();
|
||||||
|
assert!(test_token.is_some());
|
||||||
|
assert_eq!(test_token.unwrap().0, 12);
|
||||||
|
|
||||||
|
let test_token = token.try_into::<TestToken>();
|
||||||
|
assert!(test_token.is_some());
|
||||||
|
assert_eq!(test_token.unwrap().0, 12);
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
use crate::error::TapeResult;
|
||||||
|
use crate::input_reader::InputReader;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use std::any::{Any, TypeId};
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait ProtoToken {
|
||||||
|
/// Tries parsing the token
|
||||||
|
async fn try_parse(reader: &mut InputReader) -> TapeResult<Option<Token>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Token {
|
||||||
|
inner: Box<dyn Any>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Token {
|
||||||
|
/// Constructs a new token
|
||||||
|
pub fn new<A: Any>(inner: A) -> Self {
|
||||||
|
Self {
|
||||||
|
inner: Box::new(inner),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries downcasting the value to a concrete type
|
||||||
|
pub fn try_as<T: 'static>(&self) -> Option<&T> {
|
||||||
|
self.inner.downcast_ref::<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_into<T: 'static>(self) -> Option<T> {
|
||||||
|
match self.inner.downcast() {
|
||||||
|
Ok(value) => Some(*value),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks if the inner value is of a given concrete type
|
||||||
|
pub fn is<T: 'static>(&self) -> bool {
|
||||||
|
self.inner.as_ref().type_id() == TypeId::of::<T>()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue