Skip to content

Instantly share code, notes, and snippets.

@sunsided
Last active June 7, 2024 22:27
Show Gist options
  • Save sunsided/2af594c0348846c657ab0ae52a898731 to your computer and use it in GitHub Desktop.
Save sunsided/2af594c0348846c657ab0ae52a898731 to your computer and use it in GitHub Desktop.
Dynamically and iteratively combine arbitrary types in Rust. Makeshift variadic generics, anyone?
/// The base type acts as a stop token.
struct Base;
/// The wrapped type, defined in terms of the wrapped base `B` and the new value `T`.
/// You can stuff it with references and live without lifetime definitions on the type.
struct Wrapped<B, T>(B, T);
impl Base {
pub fn new(value: &str) -> Wrapped<Self, &str> {
Wrapped(Base, value)
}
}
impl<B, T> Wrapped<B, T> {
pub fn new(base: B, value: T) -> Wrapped<B, T> {
Wrapped(base, value)
}
pub fn wrap<X>(self, value: X) -> Wrapped<Self, X> {
Wrapped(self, value)
}
}
impl Debug for Base {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
impl Display for Base {
fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
Ok(())
}
}
impl<B, T> Debug for Wrapped<B, T>
where
B: Debug,
T: Debug,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&self.0, f)?;
Debug::fmt(&self.1, f)
}
}
impl<B, T> Display for Wrapped<B, T>
where
B: Display,
T: Display,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)?;
Display::fmt(&self.1, f)
}
}
#[test]
fn it_works() {
let from = String::from(" from ");
let value = Base::new("hello");
let value = value.wrap(' ');
let value = value.wrap("world");
let value = value.wrap(&from);
let value = value.wrap(2024);
assert_eq!(format!("{value}"), "hello world from 2024");
}
#[test]
fn goblinmode() {
let from = String::from(" from ");
let value: Wrapped<Base, &str> = Base::new("hello");
let value: Wrapped<Wrapped<Base, &str>, char> = value.wrap(' ');
let value: Wrapped<Wrapped<Wrapped<Base, &str>, char>, &str> = value.wrap("world");
let value: Wrapped<Wrapped<Wrapped<Wrapped<Base, &str>, char>, &str>, &String> = value.wrap(&from);
let value: Wrapped<Wrapped<Wrapped<Wrapped<Wrapped<Base, &str>, char>, &str>, &String>, i32> = value.wrap(2024);
assert_eq!(format!("{value}"), "hello world from 2024");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment