My problem is I want to have a transparent wrapper and implemented Into<underlying> for it. Unfortunately, rust's orphan rules forbid it. Here is a simple example:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> Into<T> for MyWrapper<T> {
fn into(self) -> T {
self.0
}
}
The question is is there any way I can implement it? I'm using macro to generate impl for all types I'm currently using but it looks very awkward and dirty.
You can implement the Deref trait instead. The Deref docs contain the following example which is almost identical to your code:
use std::ops::Deref;
struct DerefExample<T> {
value: T
}
impl<T> Deref for DerefExample<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
fn main() {
let x = DerefExample { value: 'a' };
assert_eq!('a', *x);
}
You can implement it in a regular impl block:
#[repr(transparent)]
pub struct MyWrapper<T>(pub T);
impl<T> MyWrapper<T> {
pub fn into(self) -> T {
self.0
}
}
fn main() {
let wrapped : MyWrapper<f32> = MyWrapper::<f32>(3.4f32);
let unwrapped : f32 = wrapped.into();
println!("{}", unwrapped);
}
Suppose I have a group of related non-scalar structs with a commutative arithmetic operation defined on them. For example,
struct Foo {
a: f64,
b: f64
}
impl Add<f64> for Foo {
type Output = Foo;
fn add(self, v: f64) -> Self::Output {
Foo {
a: self.a + v,
b: self.b + v
}
}
}
impl Add<Foo> for f64 {
type Output = Foo;
fn add(self, foo: Foo) -> Self::Output {
Foo {
a: foo.a + self,
b: foo.b + self
}
}
}
I want to implement a trait on this group of structs, taking advantage of this operation. That is, I want something like the following:
trait Bar: Add<f64, Output = Self> + Sized {
fn right_add(self, f: f64) -> Self {
self + f
}
// Doesn't compile!
fn left_add(self, f: f64) -> Self {
f + self
}
}
However, this currently doesn't compile, since the super-trait bound doesn't include the left addition of f64 to Self. My question is: How can I state this commutative trait bound?
(Playground link.)
Edit: To be clear, I'm aware that right_add and left_add have the same output. I'm mainly interested in the ergonomics of not having to remember which is "correct" according to the compiler. In addition, I'm curious to learn how to do this, even if it's not strictly necessary.
Inverted trait bounds like this are the exact usecase for where syntax:
trait Bar
where
f64: Add<Self, Output = Self>,
Self: Add<f64, Output = Self> + Sized,
{
fn right_add(self, f: f64) -> Self {
self + f
}
fn left_add(self, f: f64) -> Self {
f + self
}
}
Playground link
I am using typenum in Rust to add compile-time dimension checking to some types I am working with. I would like to combine it with a dynamic type so that an expression with mismatched dimensions would fail at compile time if given two incompatible typenum types, but compile fine and fail at runtime if one or more of the types is Dynamic. Is this possible in Rust? If so, how would I combine Unsigned and Dynamic?
extern crate typenum;
use typenum::Unsigned;
use std::marker::PhantomData;
struct Dynamic {}
// N needs to be some kind of union type of Unsigned and Dynamic, but don't know how
struct Vector<E, N: Unsigned> {
vec: Vec<E>,
_marker: PhantomData<(N)>,
}
impl<E, N: Unsigned> Vector<E, N> {
fn new(vec: Vec<E>) -> Self {
assert!(N::to_usize() == vec.len());
Vector {
vec: vec,
_marker: PhantomData,
}
}
}
fn add<E, N: Unsigned>(vector1: &Vector<E, N>, vector2: &Vector<E, N>) {
print!("Implement addition here")
}
fn main() {
use typenum::{U3, U4};
let vector3 = Vector::<usize, U3>::new(vec![1, 2, 3]);
let vector4 = Vector::<usize, U4>::new(vec![1, 2, 3, 4]);
// Can I make the default be Dynamic here?
let vector4_dynamic = Vector::new(vec![1, 2, 3, 4]);
add(&vector3, &vector4); // should fail to compile
add(&vector3, &vector4_dynamic); // should fail at runtime
}
Specifying a default for type parameters has, sadly, still not been stabilized, so you'll need to use a nightly compiler in order for the following to work.
If you're playing with defaulted type parameters, be aware that the compiler will first try to infer the types based on usage, and only fall back to the default when there's not enough information. For example, if you were to pass a vector declared with an explicit N and a vector declared without N to add, the compiler would infer that the second vector's N must be the same as the first vector's N, instead of selecting Dynamic for the second vector's N. Therefore, if the sizes don't match, the runtime error would happen when constructing the second vector, not when adding them together.
It's possible to define multiple impl blocks for different sets of type parameters. For example, we can have an implementation of new when N: Unsigned and another when N is Dynamic.
extern crate typenum;
use std::marker::PhantomData;
use typenum::Unsigned;
struct Dynamic;
struct Vector<E, N> {
vec: Vec<E>,
_marker: PhantomData<N>,
}
impl<E, N: Unsigned> Vector<E, N> {
fn new(vec: Vec<E>) -> Self {
assert!(N::to_usize() == vec.len());
Vector {
vec: vec,
_marker: PhantomData,
}
}
}
impl<E> Vector<E, Dynamic> {
fn new(vec: Vec<E>) -> Self {
Vector {
vec: vec,
_marker: PhantomData,
}
}
}
However, this approach with two impls providing a new method doesn't work well with defaulted type parameters; the compiler will complain about the ambiguity instead of inferring the default when calling new. So instead, we need to define a trait that unifies N: Unsigned and Dynamic. This trait will contain a method to help us perform the assert in new correctly depending on whether the size is fixed or dynamic.
#![feature(default_type_parameter_fallback)]
use std::marker::PhantomData;
use std::ops::Add;
use typenum::Unsigned;
struct Dynamic;
trait FixedOrDynamic {
fn is_valid_size(value: usize) -> bool;
}
impl<T: Unsigned> FixedOrDynamic for T {
fn is_valid_size(value: usize) -> bool {
Self::to_usize() == value
}
}
impl FixedOrDynamic for Dynamic {
fn is_valid_size(_value: usize) -> bool {
true
}
}
struct Vector<E, N: FixedOrDynamic = Dynamic> {
vec: Vec<E>,
_marker: PhantomData<N>,
}
impl<E, N: FixedOrDynamic> Vector<E, N> {
fn new(vec: Vec<E>) -> Self {
assert!(N::is_valid_size(vec.len()));
Vector {
vec: vec,
_marker: PhantomData,
}
}
}
In order to support add receiving a fixed and a dynamic vector, but not fixed vectors of different lengths, we need to introduce another trait. For each N: Unsigned, only N itself and Dynamic will implement the trait.
trait SameOrDynamic<N> {
type Output: FixedOrDynamic;
fn length_check(left_len: usize, right_len: usize) -> bool;
}
impl<N: Unsigned> SameOrDynamic<N> for N {
type Output = N;
fn length_check(_left_len: usize, _right_len: usize) -> bool {
true
}
}
impl<N: Unsigned> SameOrDynamic<Dynamic> for N {
type Output = N;
fn length_check(left_len: usize, right_len: usize) -> bool {
left_len == right_len
}
}
impl<N: Unsigned> SameOrDynamic<N> for Dynamic {
type Output = N;
fn length_check(left_len: usize, right_len: usize) -> bool {
left_len == right_len
}
}
impl SameOrDynamic<Dynamic> for Dynamic {
type Output = Dynamic;
fn length_check(left_len: usize, right_len: usize) -> bool {
left_len == right_len
}
}
fn add<E, N1, N2>(vector1: &Vector<E, N1>, vector2: &Vector<E, N2>) -> Vector<E, N2::Output>
where N1: FixedOrDynamic,
N2: FixedOrDynamic + SameOrDynamic<N1>,
{
assert!(N2::length_check(vector1.vec.len(), vector2.vec.len()));
unimplemented!()
}
If you don't actually need to support calling add with a fixed and a dynamic vector, then you can simplify this drastically:
fn add<E, N: FixedOrDynamic>(vector1: &Vector<E, N>, vector2: &Vector<E, N>) -> Vector<E, N> {
// TODO: perform length check when N is Dynamic
unimplemented!()
}
You could just keep using Vec<T> for what it does best, and use your Vector<T, N> for checked length vectors. To accomplish that, you can define a trait for addition and implement it for different combinations of the two types of vector:
trait MyAdd<T> {
type Output;
fn add(&self, other: &T) -> Self::Output;
}
impl <T, N: Unsigned> MyAdd<Vector<T, N>> for Vector<T, N> {
type Output = Vector<T, N>;
fn add(&self, other: &Vector<T, N>) -> Self::Output {
Vector::new(/* implement addition here */)
}
}
impl <T, N: Unsigned> MyAdd<Vec<T>> for Vector<T, N> {
type Output = Vector<T, N>;
fn add(&self, other: &Vec<T>) -> Self::Output {
Vector::new(/* implement addition here */)
}
}
impl <T> MyAdd<Vec<T>> for Vec<T> {
type Output = Vec<T>;
fn add(&self, other: &Vec<T>) -> Self::Output {
Vec::new(/* implement addition here */)
}
}
impl <T, N: Unsigned> MyAdd<Vector<T, N>> for Vec<T> {
type Output = Vector<T, N>;
fn add(&self, other: &Vector<T, N>) -> Self::Output {
Vector::new(/* implement addition here */)
}
}
Now you can use it almost in the same way as you were trying to:
fn main() {
use typenum::{U3, U4};
let vector3 = Vector::<usize, U3>::new(vec![1, 2, 3]);
let vector4 = Vector::<usize, U4>::new(vec![1, 2, 3, 4]);
let vector4_dynamic = vec![1, 2, 3, 4];
vector3.add(&vector4); // Compile error!
vector3.add(&vector4_dynamic); // Runtime error on length assertion
}
You could avoid creating your own trait by using the built in std::ops::Add, but you wouldn't be able to implement it for Vec. The left side of the .add would always have to be Vector<E, N> with Vec limited to only being in the argument. You could get around that with another Vec "newtype" wrapper, similar to what you've done with Vector<E, T> but without the length check and phantom type.
I have a few traits with default implementations that require the same methods, which happen to be field getters.
trait AddPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn add(&self){
println!("{:}", self.x()+self.x());
}
}
trait SubPosition<T: Display>{
fn x(&self) -> T;
fn y(&self) -> T;
fn sub(&self){
println!("{:}", self.x()-self.y());
}
}
Instead of manually repeating the same code for each trait implementation, can I have something like this?
impl AddPosition<i32>, SubPosition<i32> for Point{
fn x(&self) -> i32{ self.x }
fn y(&self) -> i32{ self.y }
}
The best option is probably to factor out the fact that your objects can have a position:
trait Position<T: Display> {
fn x(&self) -> T;
fn y(&self) -> T;
}
// trait AAA: BBB --> means AAA must implement BBB
trait AddPosition<T: Add<Output=T> + Display>: Position<T> {
fn add(&self){
println!("{:}", self.x()+self.x()); // ?
}
}
trait SubPosition<T: Sub<Output=T> + Display>: Position<T> {
fn sub(&self){
println!("{:}", self.x()-self.y()); // ?
}
}
struct MyPosition {
x: i32,
y: i32,
}
impl Position<i32> for MyPosition {
fn x(&self) -> i32 { self.x }
fn y(&self) -> i32 { self.y }
}
impl SubPosition<i32> for MyPosition {}
impl AddPosition<i32> for MyPosition {}
(Playground)
However, I fail to understand how your code really makes sense (? annotated lines). If this is just for the sake of the minimal example, this is totally fine; however, if this is meant for any serious code, you may want to look into the Add and Sub trait, which will allow you to benefit from operator overloading + and -. Even if you don't use those traits directly, they may inspire you for meaningful signatures of a potential add(&self, rhs: &P) -> P function (where P: Position<T>).
(Hi), I have tow questions concerning generics in rust:
1-I'm trying to port some C++ boost like concepts to rust (here an example with a 2D point):
#![feature(associated_types)]
pub trait Point2D {
type value_type;
fn x(&self) -> &<Self as Point2D>::value_type;
fn y(&self) -> &<Self as Point2D>::value_type;
}
#[deriving(Show)]
pub struct Point2<T> {
x : T,
y : T,
}
impl<T> Point2D for Point2<T> {
type value_type = T;
#[inline]
fn x(&self) -> &T {
&self.x
}
#[inline]
fn y(&self) -> &T {
&self.y
}
}
fn main(){
let mut p = Point2{x: 0i32, y : 0i32};
println!("p = {}", p);
//*p.x() = 1i32; //error: cannot assign to immutable dereference of `&`-pointer
}
Here what I want is that x() and y() return a reference to mutable T when T is mutable, and an immutable reference otherwise, is it possible ?
I saw some internals talks about parametric mutability but I didn't find any established RFC.
2- Is there any plans to add parametrization over numeric values (like template<size_t n>) to rust ?
thanks
Update: so I guest for now the only solution is something like that :
#![feature(associated_types)]
pub trait Point2D {
type value_type;
fn x_as_mut(&mut self) -> &mut <Self as Point2D>::value_type;
fn y_as_mut(&mut self) -> &mut <Self as Point2D>::value_type;
fn x_as_ref(&self) -> &<Self as Point2D>::value_type;
fn y_as_ref(&self) -> &<Self as Point2D>::value_type;
}
#[deriving(Show)]
pub struct Point2<T> {
x : T,
y : T,
}
impl<T> Point2D for Point2<T> {
type value_type = T;
#[inline]
fn x_as_mut(&mut self) -> &mut T {
&mut self.x
}
#[inline]
fn y_as_mut(&mut self) -> &mut T {
&mut self.y
}
#[inline]
fn x_as_ref(&self) -> &T {
&self.x
}
#[inline]
fn y_as_ref(&self) -> &T {
&self.y
}
}
trait Channel {
}
fn main(){
let mut p1 = Point2{x: 0i32, y : 0i32};
println!("p1 = {}", p1);
*p1.x_as_mut() = 1i32;
println!("p1 = {}", p1);
let p2 = Point2{x:0u8, y:10u8};
println!("p2 = {}", p2.y_as_ref());
}
Any cleaner way ?
There is no parametric mutability. I know that several people have expressed a strong desire for something along those lines, but I'm not aware of any actual plans as yet.
There is also no generic value parameters. I believe the core team definitely wants it, but it's not a priority right now.