use crate::types::iterators::FlatteningIntoIterator;
use crate::types::Name;
use std::fmt::{Display, Formatter};
use std::ops::Deref;
pub const TYPE_OBJECT: PrimitiveType = PrimitiveType(Name::new_static("object"));
#[allow(dead_code)]
pub const TYPE_NUMBER: PrimitiveType = PrimitiveType(Name::new_static("number"));
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
pub struct PrimitiveType(Name);
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Type {
Exactly(PrimitiveType),
EitherOf(Vec<PrimitiveType>),
}
impl Type {
pub const OBJECT: Type = Type::Exactly(TYPE_OBJECT);
pub const NUMBER: Type = Type::Exactly(TYPE_NUMBER);
#[doc(alias = "new_exactly")]
pub fn exactly<S: Into<PrimitiveType>>(t: S) -> Self {
Self::Exactly(t.into())
}
pub fn new_exactly<S: Into<PrimitiveType>>(t: S) -> Self {
Self::exactly(t)
}
#[doc(alias = "new_either")]
pub fn either<T: IntoIterator<Item = P>, P: Into<PrimitiveType>>(iter: T) -> Self {
Self::EitherOf(iter.into_iter().map(|x| x.into()).collect())
}
pub fn new_either<T: IntoIterator<Item = P>, P: Into<PrimitiveType>>(iter: T) -> Self {
Self::either(iter)
}
pub fn len(&self) -> usize {
match self {
Type::Exactly(_) => 1,
Type::EitherOf(v) => v.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
impl PrimitiveType {
pub fn new(name: Name) -> Self {
Self(name)
}
}
impl Default for Type {
fn default() -> Self {
Self::Exactly(TYPE_OBJECT)
}
}
impl From<&str> for Type {
fn from(value: &str) -> Self {
Self::Exactly(value.into())
}
}
impl From<Vec<&str>> for Type {
fn from(value: Vec<&str>) -> Self {
Self::EitherOf(value.iter().map(|&x| PrimitiveType::from(x)).collect())
}
}
impl From<PrimitiveType> for Type {
fn from(value: PrimitiveType) -> Self {
Self::Exactly(value)
}
}
impl From<Vec<PrimitiveType>> for Type {
fn from(value: Vec<PrimitiveType>) -> Self {
Self::EitherOf(value)
}
}
impl<P> FromIterator<P> for Type
where
P: Into<PrimitiveType>,
{
fn from_iter<T: IntoIterator<Item = P>>(iter: T) -> Self {
Self::EitherOf(iter.into_iter().map(|x| x.into()).collect())
}
}
impl<T> From<T> for PrimitiveType
where
T: Into<Name>,
{
#[inline(always)]
fn from(value: T) -> Self {
PrimitiveType::new(value.into())
}
}
impl AsRef<str> for PrimitiveType {
fn as_ref(&self) -> &str {
&self.0
}
}
impl Deref for PrimitiveType {
type Target = Name;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl IntoIterator for Type {
type Item = PrimitiveType;
type IntoIter = FlatteningIntoIterator<Self::Item>;
fn into_iter(self) -> Self::IntoIter {
match self {
Type::Exactly(item) => FlatteningIntoIterator::new(item),
Type::EitherOf(vec) => FlatteningIntoIterator::new_vec(vec),
}
}
}
impl Display for PrimitiveType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl Display for Type {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Type::Exactly(x) => write!(f, "{}", x),
Type::EitherOf(xs) => {
let xs: Vec<_> = xs.iter().map(|p| p.to_string()).collect();
write!(f, "(either {})", xs.join(" "))
}
}
}
}
#[cfg(all(test, feature = "parser"))]
mod tests {
use super::*;
use crate::parsers::Span;
use crate::Parser;
#[test]
fn simple_works() {
let t = Type::exactly("location");
assert_eq!(format!("{t}"), "location");
}
#[test]
fn flatten_with_single_element_works() {
let (_, t) = Type::parse(Span::new("object")).unwrap();
let mut iter = t.into_iter();
assert!(iter.next().is_some());
assert!(iter.next().is_none());
}
#[test]
fn flatten_with_many_elements_works() {
let (_, t) = Type::parse(Span::new("(either object number)")).unwrap();
let mut iter = t.into_iter();
assert!(iter.next().is_some());
assert!(iter.next().is_some());
assert!(iter.next().is_none());
}
#[test]
fn either_works() {
let t = Type::either(["location", "memory"]);
assert_eq!(format!("{t}"), "(either location memory)");
}
}