use super::error::*;
use std::borrow::Cow;
pub enum Primative {
UInt,
Int,
BStr,
TStr,
Bool,
Unresolved(String),
}
impl Primative {
pub fn constrain(self, size: u64) -> FlattenResult<ConstrainedPrimative> {
match (self, size) {
(Primative::Int, 1) => Ok(ConstrainedPrimative::I8),
(Primative::Int, 2) => Ok(ConstrainedPrimative::I16),
(Primative::Int, 4) => Ok(ConstrainedPrimative::I32),
(Primative::Int, 8) => Ok(ConstrainedPrimative::I64),
(Primative::UInt, 1) => Ok(ConstrainedPrimative::U8),
(Primative::UInt, 2) => Ok(ConstrainedPrimative::U16),
(Primative::UInt, 4) => Ok(ConstrainedPrimative::U32),
(Primative::UInt, 8) => Ok(ConstrainedPrimative::U64),
(Primative::TStr, n) => Ok(ConstrainedPrimative::Str(n)),
(Primative::BStr, n) => Ok(ConstrainedPrimative::Bytes(n)),
(prim, size) => Err(FlattenError::InvalidSizeConstraint(prim.into(), size)),
}
}
}
impl From<String> for Primative {
fn from(value: String) -> Self {
match value.as_ref() {
"int" => Primative::Int,
"uint" => Primative::UInt,
"tstr" | "text" => Primative::TStr,
"bstr" | "bytes" => Primative::BStr,
"bool" | "boolean" => Primative::Bool,
_ => Primative::Unresolved(value),
}
}
}
impl From<Primative> for String {
fn from(value: Primative) -> Self {
match value {
Primative::Int => "int".to_string(),
Primative::UInt => "uint".to_string(),
Primative::TStr => "tstr".to_string(),
Primative::BStr => "bstr".to_string(),
Primative::Bool => "bool".to_string(),
Primative::Unresolved(s) => s,
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub enum ConstrainedPrimative {
U8,
I8,
U16,
I16,
U32,
I32,
U64,
I64,
Bool,
Str(u64),
Bytes(u64),
}
#[derive(Debug, PartialEq, Clone)]
pub enum Literal {
Int(i64),
UInt(u64),
Bool(bool),
Str(String),
Char(char),
Bytes(Vec<u8>),
}
impl From<String> for Literal {
fn from(value: String) -> Self {
if value.len() == 1 {
value
.chars()
.next()
.map(Literal::Char)
.unwrap_or_else(|| Literal::Str(value))
} else {
Literal::Str(value)
}
}
}
impl From<Vec<u8>> for Literal {
fn from(value: Vec<u8>) -> Self {
match std::str::from_utf8(&value) {
Ok(s) => Literal::from(s.to_string()),
_ => {
if value.len() == 1 {
value
.iter()
.next()
.map(|val| Literal::Int(*val as i64))
.unwrap_or_else(|| Literal::Bytes(value))
} else {
Literal::Bytes(value)
}
}
}
}
}
macro_rules! from_ty {
($enum:ident, $ty:ty) => {
impl From<$ty> for Literal {
fn from(value: $ty) -> Self {
Literal::$enum(value)
}
}
};
}
macro_rules! from_int {
($ty:ty) => {
impl From<$ty> for Literal {
fn from(value: $ty) -> Self {
Literal::Int(value.into())
}
}
};
}
macro_rules! from_uint {
($ty:ty) => {
impl From<$ty> for Literal {
fn from(value: $ty) -> Self {
Literal::UInt(value.into())
}
}
};
}
from_ty!(Bool, bool);
from_ty!(Char, char);
from_ty!(Int, i64);
from_ty!(UInt, u64);
from_int!(i32);
from_int!(i16);
from_int!(i8);
from_uint!(u32);
from_uint!(u16);
from_uint!(u8);
#[derive(Clone, Debug, PartialEq)]
pub struct KeyVal(pub(crate) String, pub(crate) Box<Node>);
impl KeyVal {
pub fn new<'a, K: Into<Cow<'a, str>>>(key: K, node: Node) -> KeyVal {
KeyVal(key.into().into(), Box::new(node))
}
}
impl From<(&str, Node)> for KeyVal {
fn from((key, node): (&str, Node)) -> Self {
KeyVal::new(key, node)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Array {
pub len: usize,
pub ty: Box<Node>,
}
impl Array {
pub fn new(node: Node, len: usize) -> Array {
Array {
ty: Box::new(node),
len,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Group {
pub members: Vec<Node>,
}
#[derive(Clone, Debug, PartialEq)]
pub enum Node {
Literal(Literal),
Primative(ConstrainedPrimative),
Array(Array),
Group(Group),
Map(Group),
KeyVal(KeyVal),
Foreign(String),
}
impl From<ConstrainedPrimative> for Node {
fn from(ty: ConstrainedPrimative) -> Node {
Node::Primative(ty)
}
}
impl From<Literal> for Node {
fn from(value: Literal) -> Self {
Node::Literal(value)
}
}
impl From<KeyVal> for Node {
fn from(kv: KeyVal) -> Node {
Node::KeyVal(kv)
}
}
impl From<Array> for Node {
fn from(value: Array) -> Node {
Node::Array(value)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Fields {
pub members: Vec<LinkedKeyVal>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct LinkedKeyVal(pub String, pub LinkedNode);
impl LinkedKeyVal {
#[allow(unused)]
pub fn new<'a, K: Into<Cow<'a, str>>>(key: K, node: LinkedNode) -> LinkedKeyVal {
LinkedKeyVal(key.into().into(), node)
}
#[allow(unused)]
pub fn key(&self) -> &str {
&self.0
}
#[allow(unused)]
pub fn val(&self) -> &LinkedNode {
&self.1
}
#[allow(unused)]
pub fn into_key(self) -> String {
self.0
}
#[allow(unused)]
pub fn into_val(self) -> LinkedNode {
self.1
}
}
impl From<(String, LinkedNode)> for LinkedKeyVal {
fn from(t: (String, LinkedNode)) -> LinkedKeyVal {
LinkedKeyVal(t.0, t.1)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct LinkedArray {
pub len: usize,
pub ty: Box<LinkedNode>,
}
impl LinkedArray {
pub fn new(node: LinkedNode, len: usize) -> LinkedArray {
LinkedArray {
ty: Box::new(node),
len,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum LinkedNode {
Literal(Literal),
Primative(ConstrainedPrimative),
Array(LinkedArray),
Fields(Fields),
Struct(Fields),
ForeignStruct(String),
}
impl From<ConstrainedPrimative> for LinkedNode {
fn from(value: ConstrainedPrimative) -> Self {
LinkedNode::Primative(value)
}
}
impl From<LinkedArray> for LinkedNode {
fn from(value: LinkedArray) -> Self {
LinkedNode::Array(value)
}
}