specify specific types in where clause? - rust

Is it possible to specify the data types a generic can take as opposed to traits?
Like this:
// Purely an example for demonstrative purposes
fn has_a<T>(text: T) -> bool
where T: String + str {
text.contains('a')
}
If not is there a way to group types into a collection or trait so the possible type of a generic parameter can only take on the listed types? E.g:
trait Text { String, str}

Generics do not have this functionality. If you want to group a couple types together, you can use an enum or split your function into separate versions for each type.
/// This is just an example. Don't use this.
pub enum StringTypes<'a> {
Owned(String),
Borrowed(&'a str),
}
However, it is generally better to look for (or create) a trait that provides the functionality you want. For example, that might look something like this:
pub trait ContainsA {
fn contains_a(&self) -> bool;
}
impl ContainsA for String {
fn contains_a(&self) -> bool {
self.contains('a')
}
}
impl ContainsA for str {
fn contains_a(&self) -> bool {
self.contains('a')
}
}
Here are some of the most common traits that you may want to consider:
AsRef<T>: Generally if you want to accept an owned type or a reference, you probably want to use the trait bound AsRef<T>. When you need to use it you can simply call x.as_ref() and you know you will get a &T back without consuming the initial value. Some of the most common ways you will see this used are with AsRef<str> to accept any string-like type and AsRef<Path> to accept file path-like types.
ToOwned: This is a helpful trait which which turns some type into an owned value. You can generally think of this as a smarter version of Clone that can handle turning reference types into their owned counterparts (Ex: str to String).
So in your case, it could be rewritten as follows:
fn has_a<S: AsRef<str>>(text: S) -> bool {
text.as_ref().contains('a')
}
However, it may be easier to just always accept a &str and call it a day.
If your actual use case is related to contains and string pattern matching, you may want to look into std::str::pattern on nightly.

Related

Associated type for ndarray arguments in rust

I want to create an interface for a (numeric) algorithm for which I want to provide an implementation with ndarray and similar libraries (let's say pytorch bindings)
struct A<D> {
array: D
}
trait<D> T {
type ArgType;
fn foo(&mut self, other: &ArgType);
}
The type of the second argument other should depend on the selected generic type D. With ndarray, there are two types of arrays–those owning their data and views that share their data. The best way is to accept both types seems to be something like the following:
fn bar<S>(a: &ArrayBase<S, Ix2>)
where
S: Data<Elem = f64> {}
For the implementation of the trait T for A using ndarray, that would mean that I need something like this
use ndarray::{prelude::*, Data};
impl T<Array2<f64>> for A<Array2<f64>> {
type ArgType<S>=ArrayBase<S: Data<Elem=f64>, Ix2>;
fn foo(&mut self, other: &Self::ArgType){
///
}
}
Then, however, how would I add the new template parameter to foo. More importantly, generic associated types are not allowed in stable. I assume it would be simpler if there were a trait in ndarray that defined all methods, however, they are implemented directly for the ArrayBase type. I thought about writing a thin abstraction layer but that would be too complex (even if I only use a small subset of methods only). The asarray trait seemed to be a promising solution but it requires an lifetime parameter too (is there even a concept of associated traits?).
What would be the recommended way of handling this kind of situation; is there an easy way?
Maybe this approach is what you want:
use ndarray::{ArrayBase, Ix2};
trait TheAlgorithm<OtherArg> {
fn calculate(&self, other: &OtherArg) -> f64;
}
impl<ReprSelf, ReprOther> TheAlgorithm<ArrayBase<ReprOther, Ix2>>
for ArrayBase<ReprSelf, Ix2>
where
ReprSelf: ndarray::Data<Elem = f64>,
ReprOther: ndarray::Data<Elem = f64>,
{
fn calculate(&self, other: &ArrayBase<ReprOther, Ix2>) -> f64 {
// dummy calculation
self.view()[(0, 0)] + other.view()[(0, 0)]
}
}
This lets you call the calculate() method on either owned arrays or views, and the other argument can be owned or a view in either case.

Is it possible to assign the return value of different functions that return different structs (that implement a common trait) to a single variable?

Let's say I have something like this:
trait SomeTrait {}
struct One;
impl SomeTrait for One {}
struct Two;
impl SomeTrait for Two {}
fn return_one() -> One {
One
}
fn return_two() -> Two {
Two
}
Somewhere else, I want to essentially do:
fn do_stuff(op: Operation) {
let result = match op {
Operation::OpOne => return_one(),
Operation::OpTwo => return_two(),
};
}
That of course doesn't compile, as those two return_*() functions return distinct types. I've tried:
Declaring result as dyn SomeTrait (still error: mismatched types)
Casting the return values, e.g. return_one() as dyn SomeTrait (error: cast to unsized type: One as dyn SomeTrait)
Making Sized a supertrait of SomeTrait (this won't work for me in this particular case as I don't have control over the real-world version of SomeTrait, but it doesn't compile anyway: error: the trait SomeTrait cannot be made into an object
Things I think would work but don't want to or can't do:
Boxing values on return, e.g. Box::new(return_one()) as dyn Box<SomeTrait> (having to move the values into a box, and thus off the stack, seems excessive)
Having return_one() and return_two() instead return impl SomeTrait (this would allow me to accidentally return Two from return_one(), for example, and I want to use the type system to prevent that)
Wrapping with an enum: I don't want the functions to return a wrapper enum, because then we have the same problem as the previous bullet point. I could wrap the return values in an enum at the call site, and that could work, but let's say there's some function on SomeTrait that I want to call at the end; it seems like a lot of extra boilerplate to then unwrap the enum and call that function for each inner type. If I were to do that, I might as well just copy-paste the trait function call to each match arm.
I found a few crates on crates.io that claim to be able to do this, but AFAICT they all require implementing a trait on the types, which are foreign types for me, so I can't do that.
Is it possible to make this work?
A possible option is to do the following
fn do_stuff(op: Operation) {
let (one, two);
let _result: &dyn SomeTrait = match op {
Operation::OpOne => {one = return_one(); &one},
Operation::OpTwo => {two = return_two(); &two},
};
}
You can also use &mut dyn SomeTrait instead if you need to borrow it mutably.
This is somewhat verbose, but if you find yourself doing it a lot, a macro
that declares the anonymous variables, assigns them and returns a reference might help.
Another solution could be to use the auto_enums crate, which automaticaly creates the enum and implements the trait for it, the downside is that it only supports certain traits, (mostly in std, I believe) and that for this specific use case it requires nightly, or putting the match in a separate function.
I'm not sure I can link a specific part of the docs, but if you scroll down to "#Rust Nightly", you'll see your specific use of it, something like as follows
use auto_enums::auto_enum;
fn do_stuff(op: Operation) {
#[auto_enum(SomeTrait)]
let _result = match op {
Operation::OpOne => return_one(),
Operation::OpTwo => return_two(),
};
}
Although keep in mind this only works if auto_enums supports SomeTrait.

How to assign an impl trait in a struct?

Consider some struct (HiddenInaccessibleStruct) that is not accessible, but implements an API trait. The only way to obtain an object of this hidden type is by calling a function, that returns an opaque implementation of this type. Another struct owns some type, that makes use of this API trait. Right now, it seems not possible to assign this field in fn new(). The code below can also be found in rust playgrounds.
// -- public api
trait Bound {
fn call(&self) -> Self;
}
// this is not visible
#[derive(Default)]
struct HiddenInaccessibleStruct;
impl Bound for HiddenInaccessibleStruct {
fn call(&self) -> Self { }
}
// -- public api
pub fn load() -> impl Bound {
HiddenInaccessibleStruct::default()
}
struct Abc<T> where T : Bound {
field : T
}
impl<T> Abc<T> where T : Bound {
pub fn new() -> Self {
let field = load();
Abc {
field // this won't work, since `field` has an opaque type.
}
}
}
Update
The API trait Bound declares a function, that returns Self, hence it is not Sized.
There are two concepts in mid-air collision here: Universal types and existential types. An Abc<T> is a universal type and we, including Abc, can refer to whatever T actually is as T (simple as that). impl Trait-types are Rust's closest approach to existential types, where we only promise that such a type exists, but we can't refer to it (there is no T which holds the solution). This also means your constructor can't actually create a Abc<T>, because it can't decide what T is. Also see this article.
One solution is to kick the problem upstairs: Change the constructor to take a T from the outside, and pass the value into it:
impl<T> Abc<T>
where
T: Bound,
{
pub fn new(field: T) -> Self {
Abc { field }
}
}
fn main() {
let field = load();
let abc = Abc::new(field);
}
See this playground.
This works, but it only shifts the problem: The type of abc in main() is Abc<impl Bound>, which is (currently) impossible to write down. If you change the line to let abc: () = ..., the compiler will complain that you are trying to assign Abc<impl Bound> to (). If you try to comply with the advice and change the line to let abc: Abc<impl Bound> = ..., the compiler will complain that this type is invalid. So you have to leave the type of abc being implied. This brings some useability issues with Abc<impl Bound>, because you can't easily put values of that type into other structs etc.; basically, the existential type "infects" the outer type containing it.
impl Trait-types are mostly useful for immediate consumption, e.g. impl Iterator<Item=...>. In your case, with the aim apparently being to hide the type, you may get away with sealing Bound. In a more general case, it may be better to use dynamic dispatch (Box<dyn Bound>).

Is it possible to use a type to access a specific field of a Rust union?

As part of mapping a C interface to Rust, I want to handle a union that stored a few native types directly and have a pointer to an allocated type for all others.
How can I implement a parameterized wrapper type around the union that can select and use the appropriate field based on the wrapper type parameter?
In this case, I want to add a Rust wrapper that reads the data structure directly and not a solution that converts it to a Rust-native type first. Adding other support types to "trick" the compiler is fine though. The end goal is to be able to write code similar to this:
let the_list: List<i32> = get_a_list();
for i in the_list {
println!("value")
}
I am skipping the definitions of IntoIterator and friends since that boils down to accessing the correct field based on the type.
The code is highly unsafe, but we can assume that the user provides the correct type for the type parameter.
There are other solutions to this problem such as having explicit reader functions for each type, but this is focused on understanding if there are ways to make it work without those and without introducing an undue overhead.
Code that does not work, but illustrates what I want to accomplish:
#![feature(specialization)]
use std::convert::From;
union Data<T> {
int_value: i64,
ptr_value: *const T,
}
default impl<T> From<&Data<T>> for &T {
fn from(data: &Data<T>) -> &T {
&*data.ptr_value
}
}
impl From<&Data<i64>> for &i64 {
fn from(data: &Data<i64>) -> &i64 {
&*data.int_value
}
}
fn show<T>(value: &T) {
println!("value: {}", value);
}
fn main() {
let value = String::from("magic");
let data: Data<&str> = Data {
ptr_value: value.as_ptr(),
};
show(data.into());
}
I have minimized the example to avoid discussions about other aspects. This gives the following error:
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> examples/union_convert.rs:10:14
|
10 | default impl<T> From<&Data<T>> for &T {
| ^ type parameter `T` must be used as the type parameter for some local type
|
= note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local
= note: only traits defined in the current crate can be implemented for a type parameter
I have tried adding a wrapper around the union to handle the type-punning, but that seems to just push the error message around. Returning some other type than &T would also be possible, but I do not understand how to make it behave correctly. Using a different return type is also an option, but it still boils down to selecting the correct field based on a type.
Looking at the implementation of std::vec::Vec it does a similar thing, but in this case it always map the memory representation of the type to a real type. In this case, I want to select the correct union field based on the type that was used when writing the value.
Other similar questions that do not really answer this questions:
How to force a union to behave as if there is only one type? ask a similar question, but in this case there are explicit functions to retrieve each type and in this case I want to use the type to resolve what field to read.
Resolve union structure in Rust FFI just address the issue that you need to explicitly pick what field to read, which is what I intend to do.
How is there a conflicting implementation of From when using a generic type? This question discuss From as well, but it converting from a generic type (e.g., &T) to the implemented type (e.g., Data<T>). This question is about going in the other direction: converting from a new type (Data<T>) to a more generic type (&T).
Update: Provided a more distinct example of using into() to convert the union type one of the fields.
I would define my own trait instead of From to avoid conflicting with the standard library implementations. I'd also define a newtype wrapper / marker type. This removes the possibility of conflict when storing one of the specific types in the generic spot.
struct Other<T>(T);
union Data<T> {
bool_value: bool,
int_value: i64,
ptr_value: *const T,
}
trait Access<T> {
type Output;
unsafe fn access(&self) -> &Self::Output;
}
impl<T> Access<Other<T>> for Data<T> {
type Output = T;
unsafe fn access(&self) -> &Self::Output {
&*self.ptr_value
}
}
impl<T> Access<bool> for Data<T> {
type Output = bool;
unsafe fn access(&self) -> &Self::Output {
&self.bool_value
}
}
impl<T> Access<i64> for Data<T> {
type Output = i64;
unsafe fn access(&self) -> &Self::Output {
&self.int_value
}
}
fn main() {
let value = 123_f64;
let data: Data<f64> = Data { ptr_value: &value };
// This is safe because we just created this with
// a `f64` and nothing happened in-between.
unsafe {
println!("{}", Access::<Other<f64>>::access(&data));
}
}
See also:
How is there a conflicting implementation of `From` when using a generic type?

Should I return &Option<Foo> or Option<&Foo> from a getter?

I have a struct:
struct Foo {}
struct Boo {
foo: Option<Foo>,
}
I want to create getter for it, so user cannot modify it but can read it:
impl Boo {
pub fn get_foo(&self) -> ? { unimplemented!(); }
}
Should I return &Option<Foo> or Option<&Foo>? Are there any advantages between these two variants?
I use both variants in my program, and it became an inconvenience to mix them, so I want to choose one of them for the entire program.
Use Option<&T> instead of &Option<T>. Callers are interested in the wrapped value, not in Option.
Also, the common way to implement a getter like this is as follows:
impl Boo {
pub fn get_foo(&self) -> Option<&Foo> { self.foo.as_ref() }
}
This way you don't need to check the wrapped value in the getter. If you want to return a mutable value, use as_mut() instead.
When in doubt, pick the most flexible solution. This leaves you the most leeway in the future to change the internals of the struct without altering its API.
In this case, this means picking Option<&T>:
&Option<T> forces you to have a reference to an option,
Option<&T> only requires a reference to a T.
So, for example, in the latter case I could store a Vec<T> or a Result<T, Error> and still be able to hand out a Option<&T>. It is more flexible.
Note: this is why interfaces generally use &str instead of &String, &[T] instead of &Vec<T>, ... more flexibility!

Resources