I want to use function pointers to point to either of these 2 functions below.
Both functions work as expected, when called directly.
When I want to use pointers, their types are not compatible, even though they have the same parameters a: &'a [T], b: &'a [T] and both return f64.
use ndarray::linalg::Dot;
use ndarray::{ArrayView, ArrayBase, RawData};
#[inline]
pub fn euclidean_distance<'a, T>(a: &'a [T], b: &'a [T]) -> f64
where
f64: From<T>,
T: Copy,
{
a.iter()
.zip(b.iter())
.fold(0f64, |acc, (&x, &y)| {
acc + (f64::from(x) - f64::from(y)).powi(2)
})
.sqrt()
}
#[inline]
pub fn cosine<'a, T>(a: &'a [T], b: &'a [T]) -> f64
where
T: Copy,
ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
let x = ArrayView::from(a);
let y = ArrayView::from(b);
x.dot(&y) / (x.dot(&x) * y.dot(&y)).sqrt()
}
When, I want to use pointers to these function
pub struct Model<'a, T>
where
T: Copy,
f64: From<T>,
{
/// Epsilon value - maximum distance between points in a cluster
pub eps: f64,
/// Minimum number of points in a cluster
pub mpt: usize,
distance: fn(a: &'a [T], b: &'a [T]) -> f64,
c: Vec<Classification>,
v: Vec<bool>,
}
impl<'a, T> Model<'a, T>
where
T: Copy,
f64: From<T>,
{
/// Create a new `Model` with a set of parameters
///
/// # Arguments
/// * `eps` - maximum distance between datapoints within a cluster
/// * `min_points` - minimum number of datapoints to make a cluster
pub fn new(eps: f64, min_points: usize, mode: &str) -> Model<T> {
Model {
eps,
mpt: min_points,
c: Vec::new(),
v: Vec::new(),
distance: match mode {
"euclidean" => euclidean_distance,
"cosine" => cosine,
_ => panic!("Unknown Mode {:?}", mode),
},
}
}
}
I get the following error: "expected fn pointer, found fn item". I don't understand why the functions have different incompatible types.
error[E0308]: `match` arms have incompatible types
--> src/dbscan.rs:115:29
|
113 | distance: match mode {
| _______________________-
114 | | "euclidean" => euclidean_distance,
| | ------------------ this is found to be of type `fn(&[T], &[T]) -> f64`
115 | | "cosine" => cosine,
| | ^^^^^^ expected fn pointer, found fn item
116 | | _ => panic!("Unknown Mode {:?}", mode),
117 | | },
| |_____________- `match` arms have incompatible types
|
= note: expected fn pointer `fn(&[T], &[T]) -> _`
found fn item `fn(&[f64], &[f64]) -> _ {dbscan::cosine::<'_, f64>}`
It just required a couple of minor lifetime tweaks and there was a where clause missing in impl Model:
use ndarray::linalg::Dot;
use ndarray::{ArrayView, Ix1};
struct Classification;
#[inline]
pub fn euclidean_distance<T>(a: &[T], b: &[T]) -> f64
where
f64: From<T>,
T: Copy,
{
a.iter()
.zip(b.iter())
.fold(0f64, |acc, (&x, &y)| {
acc + (f64::from(x) - f64::from(y)).powi(2)
})
.sqrt()
}
#[inline]
pub fn cosine<T>(a: &[T], b: &[T]) -> f64
where
T: Copy,
for<'a> ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
let x = ArrayView::from(a);
let y = ArrayView::from(b);
x.dot(&y) / (x.dot(&x) * y.dot(&y)).sqrt()
}
pub struct Model<T>
where
T: Copy,
f64: From<T>,
{
/// Epsilon value - maximum distance between points in a cluster
pub eps: f64,
/// Minimum number of points in a cluster
pub mpt: usize,
distance: fn(a: &[T], b: &[T]) -> f64,
c: Vec<Classification>,
v: Vec<bool>,
}
impl<T> Model<T>
where
T: Copy,
f64: From<T>,
for<'a> ArrayView<'a, T, Ix1>: Dot<ArrayView<'a, T, Ix1>, Output = f64>,
{
/// Create a new `Model` with a set of parameters
///
/// # Arguments
/// * `eps` - maximum distance between datapoints within a cluster
/// * `min_points` - minimum number of datapoints to make a cluster
pub fn new(eps: f64, min_points: usize, mode: &str) -> Model<T> {
Model {
eps,
mpt: min_points,
c: Vec::new(),
v: Vec::new(),
distance: match mode {
"euclidean" => euclidean_distance,
"cosine" => cosine,
_ => panic!("Unknown Mode {:?}", mode),
},
}
}
}
Related
I'm working on a library implementing allocators (https://github.com/JonathanWoollett-Light/array-allocators) which can be used in shared memory.
I have a type which currently implements Deref and DerefMut on T: Sized and need it to implement on T: ?Sized to support slices.
This type is TypedLinkedListArrayWrapper:
pub struct TypedLinkedListArrayWrapper<'a, const N: usize, T: ?Sized> {
pub wrapper: LinkedListArrayWrapper<'a, N>,
__marker: PhantomData<T>,
}
which implements Deref and DerefMut:
impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*(self.wrapper.deref() as *const [LinkedListArrayBlock]).cast() }
}
}
impl<'a, const N: usize, T> DerefMut for TypedLinkedListArrayWrapper<'a, N, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *(self.wrapper.deref_mut() as *mut [LinkedListArrayBlock]).cast() }
}
}
If I change T to be T:?Sized here I get the errors
error[E0277]: the size for values of type `T` cannot be known at compilation time
--> src/linked_list.rs:166:54
|
162 | impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
| - this type parameter needs to be `std::marker::Sized`
...
166 | unsafe { &*std::ptr::addr_of!(*self.wrapper).cast() }
| ^^^^ doesn't have a size known at compile-time
|
note: required by a bound in `ptr::const_ptr::<impl *const T>::cast`
--> /home/jonathan/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/ptr/const_ptr.rs:60:23
|
60 | pub const fn cast<U>(self) -> *const U {
| ^ required by this bound in `ptr::const_ptr::<impl *const T>::cast`
help: consider removing the `?Sized` bound to make the type parameter `Sized`
|
162 - impl<'a, const N: usize, T: ?Sized> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
162 + impl<'a, const N: usize, T> Deref for TypedLinkedListArrayWrapper<'a, N, T> {
|
For more information about this error, try `rustc --explain E0277`.
error: could not compile `array-allocators` due to previous error
This is on top of LinkedListArrayWrapper:
pub struct LinkedListArrayWrapper<'a, const N: usize> {
allocator: &'a LinkedListArrayAllocator<N>,
index: usize,
size: usize,
}
which implements Deref and DerefMut:
impl<'a, const N: usize> Deref for LinkedListArrayWrapper<'a, N> {
type Target = [LinkedListArrayBlock];
fn deref(&self) -> &Self::Target {
let allocator = unsafe { &*self.allocator.0.get() };
&allocator.data[self.index..self.index + self.size]
}
}
impl<'a, const N: usize> DerefMut for LinkedListArrayWrapper<'a, N> {
fn deref_mut(&mut self) -> &mut Self::Target {
let allocator = unsafe { &mut *self.allocator.0.get() };
&mut allocator.data[self.index..self.index + self.size]
}
}
where LinkedListArrayBlock is:
pub struct LinkedListArrayBlock {
size: usize,
next: Option<usize>,
}
How can I do this?
So I found a solution.
An important topic here relates to https://doc.rust-lang.org/std/ptr/trait.Pointee.html. Unfortunately this is nightly and requires #![feature(ptr_metadata)].
A solution is to use a custom type for slices to embed the meta data needed for a slice:
pub struct SliceLinkedListArrayWrapper<'a, const N: usize, T> {
pub wrapper: LinkedListArrayWrapper<'a, N>,
pub len: usize,
__marker: PhantomData<T>,
}
impl<'a, const N: usize, T> Deref for SliceLinkedListArrayWrapper<'a, N, T> {
type Target = [T];
fn deref(&self) -> &Self::Target {
unsafe { &*std::ptr::from_raw_parts(std::ptr::addr_of!(*self.wrapper).cast(), self.len) }
}
}
impl<'a, const N: usize, T> DerefMut for SliceLinkedListArrayWrapper<'a, N, T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe {
&mut *std::ptr::from_raw_parts_mut(
std::ptr::addr_of_mut!(*self.wrapper).cast(),
self.len,
)
}
}
}
A more generalized solution is likely possible although may be awkward.
The specific problem here is that .cast() requires the target type to be Sized. The reason can be found in the issue introducing the method:
Like with NonNull::cast, the input pointed type does not need to be Sized but the output pointed type does, because we wouldn’t know what appropriate pointer metadata (slice length, trait object vtable, …) to insert.
With that out of the way, I don't understand what you're trying to accomplish. At all. It seems like you're trying to use a slice of LinkedListArrayBlock as backing storage for T? That seems very dubious and wildly unsound. And even if it weren't you can't cast between fat pointers arbitrarily and have it make sense.
On the code below, you can see that I forced the implementation of A for everything that implements AsRef<[T]> and Index[T], so B should implement it, because it implements both of these. However this is not the case. Why?
use std::convert::{AsMut, AsRef};
use std::ops::{Index, IndexMut};
use std::slice::SliceIndex;
pub trait A<T, I: SliceIndex<[T], Output = T>>:
AsRef<[T]> + Index<I, Output = T>
{
fn len(&self) -> usize;
}
impl<
T: AsRef<[T]> + Index<I, Output = T>,
I: SliceIndex<[T], Output = T>,
> A<T, I> for T
{
fn len(&self) -> usize {
self.as_ref().len()
}
}
struct B<'a, T>{
data: &'a mut [T]
}
impl<'a, T> AsRef<[T]> for B<'a, T> {
fn as_ref(&self) -> &[T] {
self.data
}
}
impl<'a, T, I: SliceIndex<[T], Output = T>> Index<I> for B<'a, T> {
type Output = T;
fn index(
&self,
v: I,
) -> &Self::Output {
&self.as_ref()[v]
}
}
fn something<'a, T>(r: &'a mut[T]) -> Box<dyn A<T, usize>> {
let a = B{data: r};
Box::new(a)
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=aa2353139f3d097e2497ed700d678ed3
Error:
error[E0277]: the trait bound `B<'_, T>: A<T, usize>` is not satisfied
--> src/lib.rs:46:5
|
46 | Box::new(a)
| ^^^^^^^^^^^ the trait `A<T, usize>` is not implemented for `B<'_, T>`
|
= note: required for the cast to the object type `dyn A<T, usize, Output = T>`
You need to introduce an additional type parameter on the blanket impl for A:
impl<T, I, V> A<T, I> for V
where
V: AsRef<[T]> + Index<I, Output = T>,
I: SliceIndex<[T], Output = T>,
{
fn len(&self) -> usize {
self.as_ref().len()
}
}
After fixing that, you'll get a lifetime error since the trait object returned in the box infers a 'static lifetime, so you'll need to bind it to the input slice's 'a lifetime.
fn something<'a, T>(r: &'a mut [T]) -> Box<dyn A<T, usize> + 'a> {
let a = B { data: r };
Box::new(a)
}
I've been trying to get this code to compile
pub trait Packet: PacketSerializer + ProtocolToID + Default {
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf>;
fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self>;
}
impl<T: PacketSerializer + ProtocolToID + PacketHandler + Default> Packet for T
{
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf> {
let mut buf = Box::new(ByteBuf::new());
buf.write_var_int(self.resolve_id(ver));
self.serialize(&mut buf, &ver);
buf
}
fn deserialize_gen(buf: &mut ByteBuf) -> Box<T> {
let mut p: T = Default::default();
p.deserialize(buf);
Box::new(p)
}
}
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
specifically invoke_packet_handler is supposed to return a Box<dyn Packet>
According to the docs, this should work https://doc.rust-lang.org/rust-by-example/trait/dyn.html if you "statically" define the trait so the compiler can see it.
I get the following error at runtime
error[E0038]: the trait `Packet` cannot be made into an object
--> src/serialize/packet.rs:43:61
|
43 | pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
| ^^^^^^^^^^^^^^^ `Packet` cannot be made into an object
I'm assuming this is because of the implementation for Packet? It's generic on every type that implements PacketSerializer, ProtocolToID, PacketHandler and Default
However,
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn PacketHandler> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
does compile if I specify a single trait
I'm trying to wrap a HashMap, as defined below, to return a mutable reference from a HashMap:
use std::{collections::HashMap, marker::PhantomData};
struct Id<T>(usize, PhantomData<T>);
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
type Output = &'a mut T;
fn index(&mut self, id: &'a Id<T>) -> Self::Output {
self.0.get_mut(id).unwrap()
}
}
And the resulting error:
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 54:5...
--> src/id_container.rs:54:5
|
54 | / fn index(&mut self, id: &'a Id<T>) -> Self::Output {
55 | | self.0.get_mut(id).unwrap()
56 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/id_container.rs:55:9
|
55 | self.0.get_mut(id).unwrap()
| ^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 52:6...
--> src/id_container.rs:52:6
|
52 | impl<'a, T> std::ops::Index<Id<T>> for &'a mut IdCollection<T> {
| ^^
= note: ...so that the types are compatible:
expected std::ops::Index<id_container::Id<T>>
found std::ops::Index<id_container::Id<T>>
Why can't the compiler extend the lifetime of the get_mut? The IdCollection would then be borrowed mutably.
Note that I tried using a std::collections::HashSet<IdWrapper<T>> instead of a HashMap:
struct IdWrapper<T> {
id: Id<T>,
t: T,
}
Implementing the proper borrow etc. so I can use the Id<T> as a key.
However, HashSet doesn't offer a mutable getter (which makes sense since you don't want to mutate what's used for your hash). However in my case only part of the object should be immutable. Casting a const type to a non-const is UB so this is out of the question.
Can I achieve what I want? Do I have to use some wrapper such as a Box? Although I'd rather avoid any indirection...
EDIT
Ok I'm an idiot. First I missed the IndexMut instead of the Index, and I forgot the & when specifying the Self::Output in the signature.
Here's my full code below:
pub struct Id<T>(usize, PhantomData<T>);
impl<T> std::fmt::Display for Id<T> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> Hash for Id<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> PartialEq for Id<T> {
fn eq(&self, o: &Self) -> bool {
self.0 == o.0
}
}
impl<T> Eq for Id<T> {}
pub struct IdCollection<T>(HashMap<Id<T>, T>);
impl<'a, T> IntoIterator for &'a IdCollection<T> {
type Item = (&'a Id<T>, &'a T);
type IntoIter = std::collections::hash_map::Iter<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter()
}
}
impl<'a, T> IntoIterator for &'a mut IdCollection<T> {
type Item = (&'a Id<T>, &'a mut T);
type IntoIter = std::collections::hash_map::IterMut<'a, Id<T>, T>;
fn into_iter(self) -> Self::IntoIter {
self.0.iter_mut()
}
}
impl<T> std::ops::Index<Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output {
self.0.get(&id).unwrap()
}
}
impl<T> std::ops::IndexMut<Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output {
self.0.get_mut(&id).unwrap()
}
}
impl<T> std::ops::Index<&Id<T>> for IdCollection<T> {
type Output = T;
fn index(&self, id: &Id<T>) -> &Self::Output {
self.0.get(id).unwrap()
}
}
impl<T> std::ops::IndexMut<&Id<T>> for IdCollection<T> {
fn index_mut(&mut self, id: &Id<T>) -> &mut Self::Output {
self.0.get_mut(id).unwrap()
}
}
If I understand correctly what you try to achieve, then I have to tell you, that it is a bit more complex than you originally thought it would be.
First of all, you have to realise, that if you like to use a HashMap then the type of the key required to be hashable and comparable. Therefore the generic type parameter T in Id<T> has to be bound to those traits in order to make Id hashable and comparable.
The second thing you need to understand is that there are two different traits to deal with the indexing operator: Index for immutable data access, and IndexMut for mutable one.
use std::{
marker::PhantomData,
collections::HashMap,
cmp::{
Eq,
PartialEq,
},
ops::{
Index,
IndexMut,
},
hash::Hash,
};
#[derive(PartialEq, Hash)]
struct Id<T>(usize, PhantomData<T>)
where T: PartialEq + Hash;
impl<T> Eq for Id<T>
where T: PartialEq + Hash
{}
struct IdCollection<T>(HashMap<Id<T>, T>)
where T: PartialEq + Hash;
impl<T> Index<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
type Output = T;
fn index(&self, id: Id<T>) -> &Self::Output
{
self.0.get(&id).unwrap()
}
}
impl<T> IndexMut<Id<T>> for IdCollection<T>
where T: PartialEq + Hash
{
fn index_mut(&mut self, id: Id<T>) -> &mut Self::Output
{
self.0.get_mut(&id).unwrap()
}
}
fn main()
{
let mut i = IdCollection(HashMap::new());
i.0.insert(Id(12, PhantomData), 99i32);
println!("{:?}", i[Id(12, PhantomData)]);
i[Id(12, PhantomData)] = 54i32;
println!("{:?}", i[Id(12, PhantomData)]);
}
It may seem a bit surprising, but IndexMut is not designed to insert an element into the collection but to actually modify an existing one. That's the main reason why HashMap does not implement IndexMut -- and that's also the reason why the above example uses the HashMap::insert method to initially place the data. As you can see, later on, when the value is already available we can modify it via the IdCollection::index_mut.
I'm not sure that I understand why this code won't compile. It seems like the new "vector" Mul specialization is more specific than the default one, and I don't think that I'm relying on the Vectorizable trait not having been defined for a type external to my crate.
#![feature(cfg_target_feature)]
#![feature(specialization)]
use std::marker::PhantomData;
use std::ops::{Mul, Add};
type Dimension = (usize, usize);
type Coordinate = (usize, usize);
pub trait Ordering {
// omitted
}
pub struct RowMajor {}
impl Ordering for RowMajor {}
pub struct ColumnMajor {}
impl Ordering for ColumnMajor {}
// NxM matrix
pub struct Matrix<T, O: Ordering> {
dim: Dimension,
values: Vec<T>,
// needed so that we can add type bound to struct
ordering: PhantomData<O>,
}
trait VectorSize {}
struct V4x {}
impl VectorSize for V4x {}
// others defined for other sizes
trait Vectorizable {
type SimdType; /*: simd::Simd */
type VectorSize: VectorSize;
}
#[cfg(target_feature = "sse")]
impl Vectorizable for f32 {
type SimdType = f32; /* simd::f32x4 */
type VectorSize = V4x;
}
impl<'a, 'b, T1, T2, O1: Ordering, O2: Ordering>
Mul<&'b Matrix<T2, O2>> for &'a Matrix<T1, O1>
where
T1: Mul<T2> + Clone,
T2: Clone,
<T1 as Mul<T2>>::Output: Add<Output = <T1 as Mul<T2>>::Output> + Clone + Default,
{
// always output row major because we compute in row major order
type Output = Matrix<
<T1 as Mul<T2>>::Output
, RowMajor>;
// self is a &'a
default fn mul(self, rhs: &'b Matrix<T2, O2>) -> Self::Output
{
unimplemented!();
}
}
impl<'a, 'b, T: Vectorizable> Mul<&'b Matrix<T, ColumnMajor>> for &'a Matrix<T, RowMajor> {
fn mul(self, rhs: &'b Matrix<T, ColumnMajor>) -> Self::Output {
unimplemented!();
}
}
(playground)
error[E0119]: conflicting implementations of trait `std::ops::Mul<&Matrix<_, ColumnMajor>>` for type `&Matrix<_, RowMajor>`:
--> src/main.rs:65:1
|
46 | / impl<'a, 'b, T1, T2, O1: Ordering, O2: Ordering>
47 | | Mul<&'b Matrix<T2, O2>> for &'a Matrix<T1, O1>
48 | | where
49 | | T1: Mul<T2> + Clone,
... |
62 | | }
63 | | }
| |_- first implementation here
64 |
65 | / impl<'a, 'b, T: Vectorizable> Mul<&'b Matrix<T, ColumnMajor>> for &'a Matrix<T, RowMajor> {
66 | | fn mul(self, rhs: &'b Matrix<T, ColumnMajor>) -> Self::Output {
67 | | unimplemented!();
68 | | }
69 | | }
| |_^ conflicting implementation for `&Matrix<_, RowMajor>`
The Vectorizable implementation is not more specific, for instance it does not mention anything about T * T being a valid operation, required by the general one.
You need to add more bounds to the Vectorizable impl to match the general one:
impl<'a, 'b, T> Mul<&'b Matrix<T, ColumnMajor>> for &'a Matrix<T, RowMajor>
where
T: Vectorizable + Mul + Clone,
T::Output: Add<Output = T::Output> + Clone + Default,
{
Alternatively, you could add those bounds as the supertrait of Vectorizable:
trait Vectorizable: Mul<Output=Self> + Add<Output = Self> + Clone + Default {
// ...
}
impl<'a, 'b, T: Vectorizable> Mul<&'b Matrix<T, ColumnMajor>> for &'a Matrix<T, RowMajor> {
// ...
}