0

I have my types defined and then I keep them in something like ArrayVec<[MyType, 16]> (from arrayvec crate) variables (members of a structure). Restson has the RestPath trait, allow us to define a path used to form a URI when performing a REST query.

However, due to the restriction that only local traits can be implemented for arbitrary types (AKA the orphan rule) I can't use it straightforwardly for ArrayVec<[MyType, 16]>.

I somehow overcame the problem by implementing the trait for ~specialization~ instantiation of the following enum:

enum ModelArray<T> {
    Array(T)
}

and then decorticate the instance of T using:

type MyArray = ModelArray<ArrayVec<[MyType; 16]>>;

let encapsulated_array: MyArray = client.get(()).unwrap();

let ModelArray::<ArrayVec<[MyType; 16]>>::Array(myarray) = encapsulated_array;

This works as minimal example, but I suffer from the fact I cannot call client.get(()).unwrap() directly to the member of other structure.

I'm surprised full specialization of a generic type isn't treated by Rust as local type and orphan rule still applies. Why?

Are there other nice ways to overcome the limitation and would let me nicely assign result of Restson's get() into members of a structure?


Working code:

extern crate restson;
extern crate arrayvec;
extern crate serde_derive;

use restson::RestPath;
use arrayvec::ArrayVec;

#[derive(Deserialize, Debug)]
struct MyType {
    id: u16,
    data: u32,
}

struct DataModel {
    my_data: ArrayVec<[MyType; 16]>
}

#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum ModelArray<T> {
    Array(T)
}

impl RestPath<u16> for MyType {
    fn get_path(id: u16) -> Result<String, Error> {
        Ok(format!("data/MyType/{}", id))
    }
}

impl RestPath<()> for ModelArray<ArrayVec<[MyType; 16]>> {
    fn get_path(_: ()) -> Result<String, Error> {
        Ok(String::from("data/MyType"))
    }
}

use restson::RestClient;

pub fn load_data() {
    let mut client = RestClient::new(&format!("http://{}", "localhost:8080")).unwrap();

    let element: Type = client.get(24).unwrap();
    println!("Room: {:?}", elementh);

    type ModelArray = ModelArray<ArrayVec<[MyType; 16]>>;
    let encapsulated: ModelArray = client.get(()).unwrap();
    let ModelArray::<ArrayVec<[MyType; 16]>>::Array(elements) = encapsulated;
    println!("Room: {:?}", elements[0]);
}

On Rust Playground (lack of restson crate wouldn't allow you to build)

Respective complete code: on GitHubGist

Michał Fita
  • 1,183
  • 1
  • 7
  • 24
  • Some parts of the question are unclear: do you mean the `ArrayVec` type from the `arrayvec` crate? And do you mean "decorate" rather than "decorticate"? A [mcve] might still help, so as to be clear what `client` is. – E_net4 Apr 02 '19 at 21:58
  • You probably want a [tuple struct](https://doc.rust-lang.org/book/ch05-01-defining-structs.html?highlight=tuple,stru#using-tuple-structs-without-named-fields-to-create-different-types) instead of an enum. So the access becomes `encapsulated_array.0.do_whatever()`. – Michail Apr 03 '19 at 21:05
  • @E_net4 Edited. https://www.thefreedictionary.com/decorticate @Michail The tuple struct works, cuts down one line... two actually as `#[serde(untagged)]` goes away from enum type. – Michał Fita Apr 03 '19 at 21:41
  • I'm still astonished the `ArrayVec<[MyLocalType;16]>` isn't treated as local type and orphan rule still fires. I'm unhappy with lack of C++'s `decltype()` equivalent as well, but that's another story. – Michał Fita Apr 03 '19 at 21:43
  • I think the question is answered by https://stackoverflow.com/q/43989065/1233251 . It doesn't matter that local types as type parameters or local traits are involved, since these crates could still think about providing their own implementations and lead to a bunch of conflicts. The solution: use an actual newtype and implement the trait for it (roughly as you did, but a tuple struct is preferred over a single-variant enum). – E_net4 Apr 04 '19 at 10:34
  • "This works as minimal example, but I suffer from the fact I cannot call client.get(()).unwrap() directly to the member of other structure.", this is uncrear – Stargateur Apr 04 '19 at 11:08
  • Possible duplicate of [How do I implement a trait I don't own for a type I don't own?](https://stackoverflow.com/questions/25413201/how-do-i-implement-a-trait-i-dont-own-for-a-type-i-dont-own) – Stargateur Apr 04 '19 at 11:11
  • "I'm still astonished the `ArrayVec<[MyLocalType;16]>` isn't treated as local type and orphan rule still fires. " because `RestPast` could implement its trait for `ArrayVec` – Stargateur Apr 04 '19 at 11:12
  • I don't understand why you use word "specialization" because you don't use it, see https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md – Stargateur Apr 04 '19 at 11:15
  • @Stargateur Ups... Maybe I use C++ terminology that applies to templates. Is instantiation a correct term here? BTW _thank you_ for correcting my British English into American... – Michał Fita Apr 04 '19 at 12:37
  • @Stargateur "because RestPast could implement its trait for ArrayVec" - could it be detected by compiler and then rejected as error? – Michał Fita Apr 04 '19 at 12:40
  • 1
    "BTW thank you for correcting my British English into American..." well thanks to my spell checking to do it for me and fix my english mistake, I'm french and I don't speak english very well. I don't really care about your war with US english feel free to reverse it, it's your question – Stargateur Apr 04 '19 at 12:47
  • Hmm... https://github.com/rust-lang/rust/issues/24745 – Michał Fita Apr 04 '19 at 13:23

0 Answers0