Generic traits not visible in external module - rust

I have next code:
pub trait Osm<T> {
fn get_points(&self) -> Vec<Point<T>>;
}
#[deriving(Show, PartialEq, Clone)]
pub struct Point<T> {
pub lat: T,
pub lon: T,
}
#[deriving(Show, PartialEq, Clone)]
pub struct Node<T> {
pub point: Point<T>,
}
impl<T: Clone> Osm<T> for Node<T> {
fn get_points(&self) -> Vec<Point<T>> {
return vec![self.point.clone()];
}
}
When I put this code to main and call:
let b = Node { point: Point { lat: 10i64, lon: 12i64 }};
println!("{}", b.get_points());
all work fine.
But when I put it to another module get next error:
/prj/src/main.rs:64:22: 64:34 error: type `osm::test::Node<i64>` does not implement any method in scope named `get_points`
/prj/src/main.rs:64 println!("{}", b.get_points());
^~~~~~~~~~~~
error: aborting due to previous error
I little bit confused why it not work, probably it's make private method because for main all work fine, but when I try use pub keywords it show unnecessary visibility qualifier build error. So can I use generic traits for external module?

To use a trait method in a different module, you need to use the trait first.
So use osm::test::Osm; should work. This is the only case where a use statement imports functionality instead of just making an identifier available.
Also, methods don't need explicit pubs for pub traits since exporting the trait exports the methods.

Related

Retrieve constants from inner in Newtype pattern

Is there a way to retrieve public constants from the inner struct in the Newtype pattern?
Say I am using a struct from another crate like this
#[derive(PartialEq)]
pub struct Version(u32);
impl Version {
pub const v0: Self = Self(0);
pub const v1: Self = Self(1);
}
Now, in my code I need to wrap it with a newtype pattern. So far so good.
#[derive(PartialEq)]
pub struct MyVersion(Version);
I want to get the inner constant using the wrapper type along the lines of MyVersion::v0. Is this doable?
Rust Playground link
Thanks to #Sven for suggesting a solution that works with stable Rust.
A way out of this is to implement a trait with an associated type. The end usage is awkward (due to E0223), but at least re-defining constants and associated methods is unnecessary.
// original crate
#[derive(Debug, PartialEq)]
pub struct Version(u32);
impl Version {
pub const V0: Self = Self(0);
pub const V1: Self = Self(1);
}
// another crate
use std::ops::Deref;
#[derive(Debug, PartialEq)]
pub struct MyVersion(Version);
impl Deref for MyVersion {
type Target = Version;
fn deref(&self) -> &Self::Target {
&self.0
}
}
trait Versioning {
type V;
}
impl Versioning for MyVersion {
type V = Version;
}
fn main() {
let myv0 = MyVersion(Version::V0);
assert_eq!(*myv0, <MyVersion as Versioning>::V::V0);
}
The custom trait will probably not be needed when inherent associated type lands in the stable channel.

Serialize a remote struct with private String

I need to serialize a struct from a remote crate and all of the fields in the struct are private. There are getter's implemented in the remote struct to get those values. I am following this guidance and got it to work just fine for primitive types. However, I'm struggling with how to implement this for non-primitive types (ie: String) that the remote struct contains.
Below is a small piece of what I've implemented to frame the issue. The DataWrapper struct simply wraps Data, where Data is the remote struct.
#[derive(Serialize)]
pub struct DataWrapper {
#[serde(with = "DataDef")]
pub data: Data,
}
#[derive(Serialize)]
#[serde(remote = "remote_crate::data::Data")]
pub struct DataDef {
#[serde(getter = "Data::image_id")] // This works
image_id: u16,
#[serde(getter = "Data::description")] // This does not work
description: String,
}
The error I get when compiling this is
#[derive(Serialize)]
^^^^^^^^^ expected struct `std::string::String`, found `&str`
This makes sense, since the getter Data::description returns &str rather than a String. But, I'm not seeing a way in my code to coerce this so the compiler is happy.
If I change DataDef::description to be &str instead of String, then I have to implement lifetimes. But, when I do that, the compiler then says the remote "struct takes 0 lifetime arguments".
Appreciate any tips on how I can serialize this and other non-primitive types.
One approach you could do, so that you have full control of the serialization. Is to have the data wrapper be a copy of the struct fields you need, instead of the entire remote struct. Then you can implement From<remote_crate::data::Data> for DataWrapper and use serde without trying to coerce types.
#[derive(Serialize)]
pub struct Data {
image_id: u16,
description: String,
}
impl From<remote_crate::data::Data> for Data {
fn from(val: remote_crate::data::Data) -> Self {
Self {
image_id: val.image_id,
description: val.description.to_string(),
}
}
}
// Then you could use it like this:
// let my_data: Data = data.into();
I couldn't get it to work with an &str, but if you're OK with an allocation, you can write a custom getter:
mod local {
use super::remote::RemoteData;
use serde::{Deserialize, Serialize};
fn get_owned_description(rd: &RemoteData) -> String {
rd.description().into()
}
#[derive(Serialize)]
#[serde(remote = "RemoteData")]
pub struct DataDef {
#[serde(getter = "get_owned_description")]
description: String,
}
}
mod remote {
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
pub struct RemoteData {
description: String,
}
impl RemoteData {
pub fn description(&self) -> &str {
&self.description
}
}
}
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e9c7c0b069d7e16b6faac2fa2b840c72

Generic APIs with traits

I'm attempting to generalize/decouple an API, so that alternative structs that satisfy a Trait can be used. Struggling on Syntax regarding nested traits. This is a stripped down example of what I'm attempting to do. Note that in the real one, there are multiple sub-traits, which potentially makes a follow-on question of "how to reduce verbosity, if I'm on the right track".
pub mod general {
/// A trait to make the API generic
pub trait MyTrait<A: PartialEq> {
// type A: Partial
fn val(self) -> A;
}
/// Part of the generic API
pub struct Data<A: PartialEq, T: MyTrait<A>> {
mys: T
}
/// Another part of the generic API
fn doit<A: PartialEq>(s: impl MyTrait<A>) -> impl MyTrait {
s
}
}
pub mod specific {
/// Api-specific substruct
#[derive(PartialEq)]
pub struct Aval {
val: u32
}
/// My top-level custom struct
pub struct MyS {
val: Aval
}
}
impl<A: PartialEq> crate::general::MyTrait<A> for crate::specific::MyS {
fn val(self) -> crate::specific::Aval {
self.val
}
}
/// Example of how we'd use this
fn main() {
let mys = crate::specific::MyS{ val: crate::specific::Aval{ val: 0 } };
let S = crate::general::Data{mys};
crate::general::doit(mys); // Eg pretend we cloned or didn't create S.
}
Playground
In this specific example, we have a chicken+egg: Error on the Data struct of error[E0392]: parameter `A` is never used. Where if we remove A: error[E0412]: cannot find type `A` in this scope
I suspect this is a syntax problem related to associated types.
Just remove the trait bound from your struct.
struct Data<T> {
mys: T
}
You can still add methods and trait implementations for Data<T> requiring more specific bounds on T, but you don’t need them to define the layout of Data<T>, so you shouldn’t specify them there (and in this case, you can’t, unless you add a PhantomData member referring to A).
Your code has a number of other errors, but I trust you’ll figure them out. Feel free to comment if you get stuck again.

How do I use a BorrowMut supertrait to access struct fields in a trait default method?

Consider the following Rust code
trait Trait {
fn show_name(&self) {}
}
struct Foo {
name: String,
things_and_stuff: usize,
}
impl Trait for Foo {
fn show_name(&self) {
println!("{}", self.name);
}
}
struct Bar {
name: String,
other_field: i32,
}
impl Trait for Bar {
fn show_name(&self) {
println!("{}", self.name);
}
}
The two show_name functions have exactly the same code. It would be convenient if I could put that method as a default method on Trait, but that's not possible because traits cannot access struct fields.
We could declare a get_name(&self) -> &str method on Trait and implement it on Foo and Bar, but that doesn't fix the problem of having duplicated code because both implementations of get_name will be the same.
It would be nice to avoid the code duplication. Another question has already asked if field access is possible in traits, and the answer was basically "no".
However, I found a comment in the rust-internals forum suggesting that it's already possible. Here's the code:
struct Fields {
name: String,
}
trait Trait: BorrowMut<Fields> {
// methods go here
}
impl<T> Trait for T where T: BorrowMut<Fields> {}
Presumably there's a way to make a type T be BorrowMut<Fields> and use that to allow Trait to access Fields's fields, but so far I'm not sure how that would work.
How is the code snippet shown above supposed to solve the problem of getting field access in traits?
I know there are discussions of adding field access in traits to the language (rust-internals, RFC, another RFC), but I'd like to know what's possible now.
the answer was basically "no"
The answer actually says (emphasis mine):
A default implementation can only use methods that are defined on the trait or in a super trait.
That's what your snippet does:
trait Trait: BorrowMut<Fields>
To make it work, follow the advice from the post you are referencing:
all types which choose to implement BorrowMut<Foo>
Thus, you need to implement the trait for each of your types. I switched to Borrow because you don't need mutability here:
use std::borrow::Borrow;
struct Fields {
name: String,
}
trait Trait: Borrow<Fields> {
fn show_name(&self) {
let fields: &Fields = self.borrow();
println!("{}", fields.name);
}
}
struct Foo {
fields: Fields,
things_and_stuff: usize,
}
impl Borrow<Fields> for Foo {
fn borrow(&self) -> &Fields {
&self.fields
}
}
struct Bar {
fields: Fields,
other_field: i32,
}
impl Borrow<Fields> for Bar {
fn borrow(&self) -> &Fields {
&self.fields
}
}
impl<T> Trait for T where T: Borrow<Fields> {}
I'm almost certain you won't like this solution because it
doesn't fix the problem of having duplicated code because both implementations [...] will be the same
You may prefer to write a macro if your goal is to reduce the number of duplicate characters in your code.
See also:
I implemented a trait for another trait but cannot call methods from both traits
Is it possible to access struct fields from within a trait?

Source trait is inaccessible

The situation is (severely simplified) this (playpen):
mod tokentree {
pub struct TokenTree;
mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
I get the following error (both on nightly and beta):
<anon>:20:22: 20:47 error: source trait is inaccessible
<anon>:20 println!("{:?}", [TokenTree].intern_strs());
^~~~~~~~~~~~~~~~~~~~~~~~~
My problem is that I don't even know what this is supposed to mean.
It needs a pub declaration. Also your declarations are all over the place. Recommended form is to stick your pub mod declarations first, then, use.
Here is the working example.
mod tokentree {
pub struct TokenTree;
pub mod serialize {
use std::collections::BTreeMap;
use super::TokenTree;
#[derive(Debug)]
pub struct InternStr;
pub trait InternStrsExt {
fn intern_strs(&self) -> BTreeMap<&str, InternStr>;
}
impl InternStrsExt for [TokenTree] {
fn intern_strs(&self) -> BTreeMap<&str, InternStr> { BTreeMap::new() }
}
}
pub use self::serialize::{InternStrsExt, InternStr};
}
pub use tokentree::*;
fn main() {
println!("{:?}", [TokenTree].intern_strs());
}
(playpen)
What happened here is that you stumbled upon following glitches:
https://github.com/rust-lang/rust/issues/18241
https://github.com/rust-lang/rust/issues/16264
You can't export your traits from a private module. That's why you need to change mod serialize into pub mod serialize. For example this playpen example demonstrates that exporting struct Export works, but un-commenting the println! will make it stop compiling, because we used a trait.
Tip: One thing that helps me with the visibility rules is to generate doc files and see which doc files are visible.

Resources