| Crates.io | polyquine |
| lib.rs | polyquine |
| version | 0.0.8 |
| created_at | 2025-06-07 20:15:36.363746+00 |
| updated_at | 2025-11-10 20:27:41.927257+00 |
| description | Teach Rust types to codegen their own constructors |
| homepage | |
| repository | https://github.com/gskorokhod/polyquine |
| max_upload_size | |
| id | 1704394 |
| size | 41,867 |
Polyquine: Teach Rust types to codegen their own constructor!
crates.io: polyquine
cargo add polyquine
This crate contains:
Quine trait. Types that implement Quine have a method ctor_tokens(&self) -> TokenStream;
The tokens returned by it are valid Rust expression that, when evaluated, produces the original value.i32, bool, etc.)String[T; N]std::collections types (Vec, HashMap, HashSet, etc.)Box<T>, Option<T>Quine for:
derive_iterable).
The given iterable must:
.iter() method that returns an iterator over its elements.From<[T; N]>#[derive(Quine)] macro to derive the trait for enums and structs.
All fields thereof must implement Quine.For example:
#[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(),
// Evaluate this and you get the value of `node` back!
"e! {Node { value: 1i32, next: Some(Box::new(Node { value: 2i32, next: None })) }},
);
You can supply a custom implementation for a specific variant only - handy when this variant contains a foreign type that does not implement Quine, or when you want some custom logic in its .ctor_tokens().
This is done using the attribute #[polyquine_with(arm = (val) => {...})].
#[derive(Quine)]
enum TestEnum {
A,
#[polyquine_with(arm = (val) => {
let new_val = val + 1;
quote! { TestEnum::B(#new_val) }
})]
B(i32),
}
let b = TestEnum::B(42i32);
assert_ts_eq(&b.ctor_tokens(), "e! { TestEnum::B(43i32) }); // <- the value got incremented!
You can also skip variants using #[polyquine_skip].
By doing so, you pinky promise to never call .ctor_tokens() on an instance of that variant.
If you do, it will panic!():
#[derive(Quine)]
enum TestEnum {
A,
#[polyquine_skip]
B,
}
let a = TestEnum::A;
assert_ts_eq(
&a.ctor_tokens(),
"e! {polyquine::quine::test::TestEnum::A},
); // All good for A
let b = TestEnum::B;
let _ = b.ctor_tokens(); // <- This should panic
Contributions are always welcome!
Quine to work with a specific type from std or a third-party crate,
or have any other feature suggestions, open an issue tagged "feature request".cargo fmt
cargo clippy --workspace --fix
cargo test --workspace
See the issues for planned feature tracking and known bugs
0.0.2 is a complete rewrite.
We now use our own trait instead of deriving quote::ToTokens.
All field attributes from version 0.0.1 are no longer supported.&T is the same as for T.
This may cause issues - please open an issue if you encounter any.std type is not supported and you need it.Rc, Arc and friends are unlikely to ever be supported.
This is due to their shared ownership semantics:
We can have multiple Rc's pointing to the same memory.
When implementing Quine, the best we can do is re-construct their values separately.
When evaluated, we will now have multiple independent copies of the original value - not a single value behind a shared reference.Partially inspired by the parsel crate.
This is intended for cases where you need to construct a value and do some non-trivial logic on it at compile time (probably in a procedural macro), then take the result out of the macro as valid Rust code.
For example, when you are parsing a DSL at compile time and outputting the constructed (and possibly simplified / transformed) AST as the result of your macro call.
See this PR as proof that this use case is not completely made up.
still no.
A quine is a program that outputs its own source code. This crate teaches an arbitrary enum / struct to generate a Rust program that constructs it, thereby making it a quine. So, polyquine! This is only slightly pretentious.
also, trans rights! 🏳️⚧️