use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use proc_macro2::TokenStream;
use quote::{ToTokens, quote};
use ustr::Ustr;
pub trait Quine {
fn ctor_tokens(&self) -> TokenStream;
}
impl Quine for Ustr {
fn ctor_tokens(&self) -> TokenStream {
let s = self.as_str();
quote! {Ustr::from(#s)}
}
}
impl<T: Quine> Quine for &T {
fn ctor_tokens(&self) -> TokenStream {
(**self).ctor_tokens()
}
}
impl<T: Quine> Quine for Box<T> {
fn ctor_tokens(&self) -> TokenStream {
let inner = self.as_ref().ctor_tokens();
quote! {Box::new(#inner)}
}
}
impl<T: Quine> Quine for Option<T> {
fn ctor_tokens(&self) -> TokenStream {
match self {
Some(value) => {
let inner = value.ctor_tokens();
quote! {Some(#inner)}
}
None => quote! {None},
}
}
}
impl<T: Quine, const N: usize> Quine for [T; N] {
fn ctor_tokens(&self) -> TokenStream {
let elements = self.iter().map(|elem| elem.ctor_tokens());
quote! {[#(#elements),*]}
}
}
derive_primitive!(
i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64, bool, char, &str
);
derive_trivial!(String);
derive_tuple_all!(A B C D E F G H I J K);
derive_iterable!(Vec<T>);
derive_iterable!(VecDeque<T>);
derive_iterable!(HashSet<T>);
derive_iterable!(HashMap<K, V>);
derive_iterable!(BTreeMap<K, V>);
mod test {
use super::*;
#[allow(unused)]
use crate::Quine;
#[allow(unused)]
use std::fmt::Display;
#[allow(unused)]
use std::fmt::Formatter;
mod custom_module {
use super::*;
#[allow(dead_code)]
#[derive(Quine)]
#[path_prefix(some_module)]
pub struct Custom {
pub value: i32,
}
}
#[allow(unused)]
fn assert_ts_eq(left: &TokenStream, right: &TokenStream) {
assert_eq!(left.to_string(), right.to_string());
}
#[test]
fn test_vec() {
let vec = Vec::from([1i32, 2i32, 3i32]);
assert_ts_eq(&vec.ctor_tokens(), "e! {Vec::from([1i32, 2i32, 3i32])});
}
#[test]
fn test_tuple() {
let tuple = (1i32, true);
assert_ts_eq(&tuple.ctor_tokens(), "e! {(1i32, true)});
}
#[test]
fn test_hashmap() {
let map = HashMap::from([(1i32, "one")]);
assert_ts_eq(&map.ctor_tokens(), "e! {HashMap::from([(1i32, "one")])});
}
#[test]
fn test_box() {
let boxed = Box::new(String::from("hello, world!"));
assert_ts_eq(
&boxed.ctor_tokens(),
"e! {Box::new(String::from("hello, world!"))},
);
}
#[test]
fn test_slice() {
let slice = [1i32, 2i32, 3i32];
assert_ts_eq(&slice.ctor_tokens(), "e! {[1i32, 2i32, 3i32]});
}
#[test]
fn test_custom_module_prefix() {
let value = custom_module::Custom { value: 42i32 };
assert_ts_eq(
&value.ctor_tokens(),
"e! {some_module::Custom { value: 42i32 }},
);
}
#[test]
fn test_struct() {
#[derive(Quine)]
struct TestStruct {
a: i32,
b: bool,
}
let test_struct = TestStruct { a: 1i32, b: true };
assert_ts_eq(
&test_struct.ctor_tokens(),
"e! {polyquine::quine::test::TestStruct { a: 1i32, b: true }},
);
}
#[test]
fn test_tuple_struct() {
#[derive(Quine)]
struct TestTupleStruct(i32, bool);
let test_tuple_struct = TestTupleStruct(1i32, true);
assert_ts_eq(
&test_tuple_struct.ctor_tokens(),
"e! {polyquine::quine::test::TestTupleStruct(1i32, true)},
);
}
#[test]
fn test_unit_struct() {
#[derive(Quine)]
struct TestUnitStruct;
let test_unit_struct = TestUnitStruct {};
assert_ts_eq(
&test_unit_struct.ctor_tokens(),
"e! {polyquine::quine::test::TestUnitStruct {}},
);
}
#[test]
fn test_nested_struct() {
#[derive(Quine)]
struct Node {
value: i32,
next: Option<Box<Node>>,
}
let node = Node {
value: 1i32,
next: Some(Box::new(Node {
value: 2i32,
next: None,
})),
};
assert_ts_eq(
&node.ctor_tokens(),
"e! {polyquine::quine::test::Node { value: 1i32, next: Some(Box::new(polyquine::quine::test::Node { value: 2i32, next: None })) }},
);
}
#[test]
fn test_enum() {
#[derive(Quine)]
enum TestEnum {
A,
B(i32),
C { name: String },
}
let a = TestEnum::A;
let b = TestEnum::B(1i32);
let c = TestEnum::C {
name: String::from("John"),
};
assert_ts_eq(
&a.ctor_tokens(),
"e! {polyquine::quine::test::TestEnum::A},
);
assert_ts_eq(
&b.ctor_tokens(),
"e! {polyquine::quine::test::TestEnum::B(1i32)},
);
assert_ts_eq(
&c.ctor_tokens(),
"e! {polyquine::quine::test::TestEnum::C { name: String::from("John") }},
);
}
#[test]
fn test_ast() {
#[derive(Quine)]
struct Metadata {
src: String,
}
#[derive(Quine)]
enum Ast {
Num(Box<Metadata>, isize),
Mul(Box<Metadata>, Box<Ast>, Box<Ast>),
Sum(Box<Metadata>, Vec<Ast>),
}
let ast = Ast::Sum(
Box::new(Metadata {
src: String::from("1 + (2 * 3)"),
}),
vec![
Ast::Num(
Box::new(Metadata {
src: String::from("1"),
}),
1,
),
Ast::Mul(
Box::new(Metadata {
src: String::from("2 * 3"),
}),
Box::new(Ast::Num(
Box::new(Metadata {
src: String::from("2"),
}),
2,
)),
Box::new(Ast::Num(
Box::new(Metadata {
src: String::from("3"),
}),
3,
)),
),
],
);
assert_ts_eq(
&ast.ctor_tokens(),
"e! {
polyquine::quine::test::Ast::Sum(
Box::new(polyquine::quine::test::Metadata {
src: String::from("1 + (2 * 3)")
}),
Vec::from([
polyquine::quine::test::Ast::Num(
Box::new(polyquine::quine::test::Metadata {
src: String::from("1")
}),
1isize
),
polyquine::quine::test::Ast::Mul(
Box::new(polyquine::quine::test::Metadata {
src: String::from("2 * 3")
}),
Box::new(polyquine::quine::test::Ast::Num(
Box::new(polyquine::quine::test::Metadata {
src: String::from("2")
}),
2isize
)),
Box::new(polyquine::quine::test::Ast::Num(
Box::new(polyquine::quine::test::Metadata {
src: String::from("3")
}),
3isize
))
)
])
)
},
);
}
#[test]
fn test_ustr() {
let u1 = Ustr::from("the quick brown fox");
assert_ts_eq(
&u1.ctor_tokens(),
"e! {Ustr::from("the quick brown fox")},
);
}
#[test]
fn test_struct_with_generic() {
#[derive(Quine)]
struct Test<T: Display> {
value: T,
}
let good: Test<String> = Test {
value: String::from("Hello World"),
};
assert_ts_eq(
&good.ctor_tokens(),
"e! {
polyquine::quine::test::Test {
value: String::from("Hello World")
}
},
);
}
#[test]
fn test_enum_with_generic() {
#[derive(Quine)]
enum TestEnum<T> {
A(T),
}
let a = TestEnum::A(String::from("Hello World"));
assert_ts_eq(
&a.ctor_tokens(),
"e! {
polyquine::quine::test::TestEnum::A(String::from("Hello World"))
},
);
}
#[test]
#[should_panic(
expected = "Attempted to call ctor_tokens() on skipped enum variant TestEnum::B"
)]
fn test_skipped_variant() {
#[derive(Quine)]
enum TestEnum {
A,
#[polyquine_skip]
B,
}
let a = TestEnum::A;
assert_ts_eq(
&a.ctor_tokens(),
"e! {polyquine::quine::test::TestEnum::A},
);
let b = TestEnum::B;
let _ = b.ctor_tokens(); }
}