I'm trying to implement a newtype wrapper around a borrowed value, in order to implement different behavior for a trait but can't get this to conform to the borrowing rules. I prepared a simplified example below.
Note: The actual code is more complex and also needs to work with values that need .as_any().downcast_ref()
first, which is why I'd like this to work with borrowed values.
use std::cmp::Ordering;
trait OrdVec {
fn cmp(&self, i: usize, j: usize) -> Ordering;
}
// note: actual trait bound is more complex and would lead to
// "conflicting implementations" when trying to implement `OrdSlice for &[f64]`
impl<T> OrdVec for Vec<T>
where
T: Ord,
{
fn cmp(&self, i: usize, j: usize) -> Ordering {
self[i].cmp(&self[j])
}
}
#[repr(transparent)]
struct F64VecAsOrdVec<'a>(&'a Vec<f64>);
impl OrdVec for F64VecAsOrdVec<'_> {
fn cmp(&self, i: usize, j: usize) -> Ordering {
let a: f64 = self.0[i];
let b: f64 = self.0[j];
if a < b {
return Ordering::Less;
}
if a > b {
return Ordering::Greater;
}
unimplemented!("convert NaN to canonical form and compare bitwise")
}
}
fn as_ord_vec<'a>(first: bool, int_vec: &'a Vec<i64>, float_vec: &'a Vec<f64>) -> &'a dyn OrdVec {
if first {
int_vec
} else {
// returns a reference to data owned by the current function
&F64VecAsOrdVec(float_vec)
// newtype should have same layout but this fails on calling `cmp`
// with "SIGSEGV: invalid memory reference"
// let ord: &F64VecAsOrdVec = unsafe { std::mem::transmute(float_vec) };
// ord
}
}
#[test]
fn test_int_as_ord() {
let int_vec = vec![1, 2, 3];
let float_vec = vec![3.0, 2.0, 1.0];
let int_ord = as_ord_vec(true, &int_vec, &float_vec);
assert_eq!(Ordering::Less, int_ord.cmp(0, 1));
}
#[test]
fn test_float_as_ord() {
let int_vec = vec![1, 2, 3];
let float_vec = vec![3.0, 2.0, 1.0];
let float_ord = as_ord_vec(false, &int_vec, &float_vec);
assert_eq!(Ordering::Greater, float_ord.cmp(0, 1));
}
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:43:5
|
43 | &F64VecAsOrdVec(vec)
| ^-------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function