Here's an odd little challenge: can you implement the squeeze function so that it passes the tests below?
I'm pretty sure this can't be implemented in stable Rust. I've implemented it using #[feature(optin_builtin_traits)]. It feels like it ought to be implementable using specialization, but I can't figure out how.
#[cfg(test)]
mod test {
use super::squeeze;
#[test]
fn test_squeeze() {
// The idea here is that any non-() type would work.
assert_eq!(squeeze(1i32, 2i32), (1, 2));
assert_eq!(squeeze(true, false), (true, false));
assert_eq!(squeeze("foo", Some("bar")), ("foo", Some("bar")));
assert_eq!(squeeze(1i32, ()), 1);
assert_eq!(squeeze("foo", ()), "foo");
assert_eq!(squeeze(Some(1.3), ()), Some(1.3));
assert_eq!(squeeze((), 2i32), 2);
assert_eq!(squeeze((), "foo"), "foo");
assert_eq!(squeeze((), Some(1.3)), Some(1.3));
assert_eq!(squeeze((), ()), ());
}
}
Here's my solution. [edit] Unfortunately, it's not correct; see Cerberuser's comment.
Phew, that was a nightmare! I solved it with an Fn* impl on a mutable static variable. This code is a mess, yet I still find it to be beautiful given its complexity and what it achieves.
Here's my solution.
There were some necessary changes to be able to make it work:
#[cfg(test)]
mod test {
use super::squeeze;
#[test]
fn test_squeeze() {
unsafe {
// The idea here is that any non-() type would work.
assert_eq!(squeeze(1i32, 2i32), (1, 2).into());
assert_eq!(squeeze(true, false), (true, false).into());
assert_eq!(squeeze("foo", Some("bar")), ("foo", Some("bar")).into());
assert_eq!(squeeze(1i32, ()), 1.into());
assert_eq!(squeeze("foo", ()), "foo".into());
assert_eq!(squeeze(Some(1.3), ()), Some(1.3).into());
assert_eq!(squeeze((), 2i32), 2.into());
assert_eq!(squeeze((), "foo"), "foo".into());
assert_eq!(squeeze((), Some(1.3)), Some(1.3).into());
assert_eq!(squeeze((), ()), ().into());
}
}
}
The changes were, that because we're operating on a static mutable object we need to use an unsafe block, and we also need to call .into() to cast the right hand expression of the assert_eq! to a Return<L, R>. There is some of unstable code in here though, so be careful with it.
Edit: Here's a better documented version of the code.
Troll solution : it does make the test succeed, with no unstable features whatsoever, but just because it is exploiting the finite sample size of the test batteries. It is still an interesting solution for those needing such functionality for a finite set of types.
Remark regarding @jimb 's challenge and solution:
for all T != (), T, () should give (T, ) instead of T (and same for the mirror).
To see that, it should be noted that with the current constraints, one can write:
impl<Y> Squeeze<Y> for () {
type Output = Y;
fn squeeze(self, other: Y) -> Y {
other
}
}
instead of
impl<Y: NonTrivial> Squeeze<Y> for () {
type Output = Y;
fn squeeze(self, other: Y) -> Y {
other
}
}
impl Squeeze<()> for () {
type Output = ();
fn squeeze(self, _other: ()) -> () {
()
}
}
I was looking more into this challenge and I broke the compiler.
thread 'rustc' panicked at 'internal error: entered unreachable code', src/libsyntax/parse/parser.rs:648:22
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
error: internal compiler error: unexpected panic
note: the compiler unexpectedly panicked. this is a bug.
note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports