I believe these transmutes are currently UB, but it would be nice if tuple slicing (or at least prefixing) were legal. So, is there any concrete reason not to allow this?
use std::mem::transmute;
fn main() {
let tuple = ("str", 1u32, 2u64);
unsafe {
let prefix1: &(&str,) = transmute(&tuple);
let prefix2: &(&str, u32) = transmute(&tuple);
let suffix: &(u32, u64) = transmute(&tuple.1);
println!("{:?}", prefix1);
println!("{:?}", prefix2);
println!("{:?}", suffix);
}
}
But… lisp! Really, I wanted to be able to query BTreeSets/BTreeMaps by tuple prefix (and needed a way to borrow tuple prefix’s from tuples) but, after thinking about it, I’ve come to the conclusion that there are definitely better ways to go about this…
After thinking about it, it’s probably best to just write (((A, B), C), D) when one needs to be able to do things like this.
This seems like a good option. Also, do you really need to borrow? I'm not sure what you're storing in your tuples, but if like in your example it's immutable references and integers, you'll get the same or better performance when just copying those values in your prefixes. You can easily implement a newtype and prefix-newtypes for your BTrees that have the right Ord implementations.
I was trying to work around some limitations of BTreeSet and the Ord trait. Basically,
Ord only allows comparing T to T.
BTreeSet::<T>::range allows querying by any type Q such that T: Borrow<Q>, Q: Ord (i.e., Q can be borrowed from T and Q implements Ord).
Given BTreeSet<(A, B, C)> I wanted to query for all (a, b, *). Ord can’t be used to compare (A, B) to (A, B, C) (not the same type) so I needed to be able to “borrow” my query type from (A, B, C).
However, the better way to do this would be to change the range method to take a some type implementing a RangeQuery trait:
Enums work (that’s what I tried first) but force me to store an extra word for the tag. Really, I had (A, B) and needed to “borrow” A so I just did the following:
#[derive(Ord, PartialOrd, Eq, PartialEq)]
struct Pair<A, B>(A, B);
#[derive(Ord, PartialOrd, Eq, PartialEq)]
struct Left<A>(A);
impl Borrow<Left<A>> for Pair<A, B> {
fn borrow(&self) -> &Left<A> {
unsafe {
// UB? The standard library does it...
mem::transmute(&self.0)
}
}
}