Add token struct and traits

Signed-off-by: trivernis <trivernis@protonmail.com>
pull/1/head
trivernis 3 years ago
parent 3df49ca9a9
commit 7298b79c5a
Signed by: Trivernis
GPG Key ID: DFFFCC2C7A02DB45

@ -14,6 +14,7 @@ repository = "https://github.com/Trivernis/charred-rs"
[dependencies]
thiserror = "1.0.24"
log = "0.4.14"
async-trait = "0.1.50"
[dependencies.tokio]
version = "1.5.0"

@ -5,13 +5,13 @@ use tokio::io::{AsyncBufRead, AsyncBufReadExt};
/// An Input reader to asynchronously read a type
/// that implements AsyncBufRead and AsyncSeek.
pub struct InputReader {
inner: Box<dyn AsyncBufRead + Unpin>,
inner: Box<dyn AsyncBufRead + Unpin + Send>,
buf: String,
index: usize,
}
impl InputReader {
pub fn new<T: AsyncBufRead + Unpin + 'static>(inner: T) -> Self {
pub fn new<T: AsyncBufRead + Unpin + Send + 'static>(inner: T) -> Self {
Self {
inner: Box::new(inner),
buf: String::new(),
@ -37,7 +37,7 @@ impl InputReader {
/// Returns if EOF has been reached
#[inline]
pub async fn check_eof(&mut self) -> bool {
if let Err(TapeError::EOF) = self.read_next().await {
if let Err(TapeError::EOF) = self.peek().await {
true
} else {
false

@ -1,5 +1,6 @@
pub mod error;
pub mod input_reader;
pub mod token;
#[cfg(test)]
mod tests;

@ -1 +1,2 @@
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…
Cancel
Save