Rust not finding method of trait struct because of lifetime parameters [duplicate] - rust

This question already has an answer here:
Why do I need to import a trait to use the methods it defines for a type?
(1 answer)
Closed 4 months ago.
I was trying to do simple struct with few traits following examples on the internet an came across the following problem.
//My struct in framebuffer.rs
pub struct HighLevelFrameBuffer<'a> {
pub fbinfo: FrameBufferInfo,
pub fbdata: &'a mut [u8],
pub pixel_bytesize: u8,
pub color: FrameBufferColor,
}
//Trait and implementation
trait WriteLine {
fn write_line(&self, line: usize, color: FrameBufferColor);
}
impl<'a> WriteLine for HighLevelFrameBuffer<'a> {
fn write_line(&self, line: usize, color: FrameBufferColor) {
//Do stuff
}
}
When I try to call this from my main function as follows from main.rs:
mod framebuffer;
pub use framebuffer::HighLevelFrameBuffer;
pub use framebuffer::FrameBufferColor;
let hlfb = HighLevelFrameBuffer{
fbinfo: something,
fbdata: data_location,
pixel_bytesize: 0,
color: FrameBufferColor {r: 0, g: 0, b: 0}
};
hlfb.write_line(100, FrameBufferColor{r: 0xFF, g: 0xFF, b: 0xFF});
Compiler tells me that there is no implementation of write_line for HighLevelFrameBuffer struct:
hlfb.write_line(100, FrameBufferColor{r: 0xFF, g: 0xFF, b: 0xFF});
| ^^^^^^^^^^ method not found in `HighLevelFrameBuffer<'_>`
pub struct HighLevelFrameBuffer<'a> {
| ----------------------------------- method `write_line` not found for this struct
What I am doing wrong here?

There could be a couple reasons for this:
Did you make a typo when typing write_line?
Is WriteLine defined in a different file from where you're calling hlfb.write_line? If it is, then have you added a use statement to import WriteLine?
It's hard to be more specific without more details.

Related

Serialize complicated data structure

I'm having trouble serializing the following struct. I have narrowed it down to, that the problem lies within the variable objects, containing trait structs within a HashMap. I'll try to explain my circumstances:
I have the following main struct, which i'm interested in obtaining data from:
#[derive(Serialize)]
pub struct System {
pub objects: HashMap<(u32, u32), Box<dyn CommonObjects>>,
pub paths: Vec<Path>,
pub loops: Vec<Loop>,
pub physics: Physics,
pub run_limit_loops: u32,
pub run_limit_paths: u32,
pub error_tol_loops: f64,
pub error_tol_paths: f64,
pub unknown_flow_outlets: u32,
pub unknown_pumps_id: u32,
pub system: u32,
}
The kind of structs which are contained within objects are as the following:
pub struct Outlet {
// Variables found in all structs contained within 'objects'
pub Q: f64,
pub hL: f64,
pub ob: u32,
pub id: u32,
pub active: bool,
pub system: u32,
pub con_Q: HashMap<u32, f64>,
// Variables found only in this struct.
pub p_dyn: f64,
pub flow_specified: String,
pub submerged: bool,
}
pub struct Pipe {
// Variables found in all structs contained within 'objects'
pub Q: f64,
pub hL: f64,
pub ob: u32,
pub id: u32,
pub active: bool,
pub system: u32,
pub con_Q: HashMap<u32, f64>,
// Variables found only in this struct.
pub Re: f64,
pub f: f64,
}
These struct has some variables which are only used within themselves, and some variables which are common for all structs contained within objects (p_dyn is only used within Outlet, while Q is used for all structs contained within objects) To get these variables, get-function are defined, both within the local struct, and by the trait CommonObject. All i am interested in, is serializing objects in order to get all the variables in a string format, both the common ones, and the ones only appearing locally within a struct, so that i can send the variables to other programs to further visualization.
In this following code the error occurs:
// Where the system struct originates from.
let systems: Vec<System> = system_analyse::analyse_system(data);
// I try to only serialize the objects contained within one of the system structs.
let jsonstringresult = serde_json::to_string(&systems[0].objects);
match jsonstringresult {
Ok(v) => {
println!("{:?}", &v);
v
},
Err(e) => {
// The error message originates from here.
println!("An error occured at serializing: {}", e);
String::new()
}
}
I get the following error:
An error occured at serializing: key must be a string
I have found this thread discussing the issue of serializing dynamic traits, and i've followed the instructions and added the following to the trait:
pub trait CommonObjects: erased_serde::Serialize {
...
}
serialize_trait_object!(CommonObjects);
Which makes the code compile in the first place. I've also found this site getting the same error, but the issue there seems to be with enums. Maybe the problem in this site is related to my problem, but i cant figure out how if so.
I'm open to all sort of feedback and even fundamentally change the structure of the code if so necessary.
A quick way to serialize a HashMap with non-string keys to Json is to use the serde_as macro from the serde_with crate.
use serde_with::serde_as;
#[serde_as]
#[derive(Serialize)]
pub struct System {
#[serde_as(as = "Vec<(_, _)>")]
pub objects: HashMap<(u32, u32), Box<dyn CommonObjects>>,
//...
}
The #[serde_as(as = "Vec<(_, _)>")] encodes the map as a sequence of tuples, representing pairs of keys and values. In Json, this will become an array of 2-element arrays.

How can I define a generic struct in Rust without one of the fields being of the generic type? [duplicate]

This question already has answers here:
How can I have an unused type parameter in a struct?
(2 answers)
Closed 4 years ago.
I have the following problem (it is simplified a bit).
There is a trait which supplies a set of functions which do not use self:
pub trait ImageFormat {
fn write(data: Vec<[u8; 3]>, path: &str, ...) -> io::Result<()>;
...
}
with several implementations.
There also is a struct which uses functions from that trait:
pub struct Images<T: ImageFormat> {
path: String,
...
}
impl<T> Images<T> where T: ImageFormat {
pub fn setup(path: &str, ...) -> Images<T> {
Images {
path: String::from(path),
...
}
}
fn write(&mut self, data: Vec<[u8; 3]>, ...) -> io::Result<()> {
T::write(data, &self.path[..], ...)
}
...
}
This does not compile, because the struct does not have a field of type T.
It works if I do this, but it feels like a hack:
pub struct Images<T: ImageFormat> {
_image_format: Option<T>,
path: String,
...
}
impl<T> Images<T> where T: ImageFormat {
pub fn setup(path: &str, ...) -> Images<T> {
Images {
_image_format: None,
path: String::from(path),
...
}
}
...
}
Is there any idiomatic way of doing this?
PhantomData can be used "to mark things that "act like" they own a T".
So, you could write:
pub struct Images<T: ImageFormat> {
path: String,
phantom: PhantomData<T>, // mark that Image "acts like" it owns a T
}
In initialization, you simply provide a PhantomData for the respective field:
Images {
path: ...
phantom: PhantomData,
}
As mentioned by others, you may be better off without the type parameter in the first place, but I have had cases where they seem perfectly reasonable to me (e.g. if T provides functions that do not take a self).

What kind of lifetime parameter do I have to use here when declaring a struct field object type

This is what my code looks like. I'm trying to use a impled struct within my ShapeRenderer struct and use its methods.
shapes.rs:
use super::core::*;
pub struct ShapeRenderer<'a> {
core_renderer: &'a mut CanvasRenderer,
}
core.rs
pub struct Canvas {
pub width: usize,
pub height: usize,
pub array: Vec<char>,
}
pub struct Point {
pub x: usize,
pub y: usize,
}
pub struct CanvasRenderer<'a> {
canvas: &'a mut Canvas,
}
impl<'a> CanvasRenderer<'a> {
pub fn new(canvas: &'a mut Canvas) -> CanvasRenderer {
CanvasRenderer { canvas: canvas }
}
}
Error
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/shapes.rs:5:28
|
5 | core_renderer: &'a mut CanvasRenderer
| ^^^^^^^^^^^^^^ expected 1 lifetime parameter
I marked it with a lifetime parameter - why does it want another one? tried the object type with <'a> and appended it <'a> - neither of those attempts solved the problem.
CanvasRenderer is parameterized over a lifetime, so you need to state what that lifetime is:
pub struct ShapeRenderer<'a> {
core_renderer: &'a mut CanvasRenderer<'a>,
// ^^^^
}
However, this structure doesn't seem to have much purpose, it only adds indirection. Why have a reference to a thing that only has a reference? Skip the middleman:
pub struct ShapeRenderer<'a> {
core_renderer: CanvasRenderer<'a>,
}

Is it possible to derive(RustcEncodable) for part of struct?

I have a struct like:
struct S {
data: i32,
fun: Box<Fn()>,
}
and would like to serialize the data part using an encoder. To do that I use rustc_serialize and derive its traits like
#[derive(RustcEncodable, RustcDecodable)]
struct S {
data: i32,
fun: Box<Fn()>,
}
The problem is that fun can't be serialized as it's a function. This is fine as I only want to serialize the plain data field. Is there a way to do that?
The data field in my real use case is also a struct which can also have a Fn so I can't simply split the struct into two.
The short answer is "no". The rustc-serialize crate 1 does not provide that level of control on the automated implementations of traits like Decodable or Encodable.
To do this, you would need to implement them yourself:
extern crate rustc_serialize;
use rustc_serialize::{Encodable, Encoder};
use rustc_serialize::json;
struct S {
data: i32,
fun: Box<Fn()>,
}
impl Encodable for S {
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_struct("S", 1, |s| {
s.emit_struct_field("data", 0, |s| {
s.emit_i32(self.data)
})
})
}
}
fn main() {
let thing = S { data: 42, fun: Box::new(|| println!("I am a function")) };
let json = json::encode(&thing).expect("Couldn't encode");
println!("{}", json);
(thing.fun)();
}
If you aren't tied to rustc-serialize, you may be interested in serde which offers the #[serde(skip_serializing)] and #[serde(skip_deserializing)] annotations.
1: Technically, #[derive(RustcEncodable, RustcDecodable)] is provided by the compiler. This is why it has the Rustc prefix. It's also an ugly wart that wants to be removed but is waiting for stable support of compiler plugins.
Shepmaster's answer gives the RustcEncodable solution. For completeness, here is the equivalent Serde code:
#![feature(custom_derive, plugin)]
#![plugin(serde_macros)]
extern crate serde_json;
#[derive(Serialize, Deserialize)]
struct S {
data: i32,
#[serde(skip_serializing, skip_deserializing, default="empty_fun")]
fun: Box<Fn()>,
}
fn empty_fun() -> Box<Fn()> {
Box::new(|| {})
}
fn main() {
let s = S { data: 42, fun: Box::new(|| println!("I am a function")) };
// prints {"data":42}
println!("{}", serde_json::to_string(&s).unwrap());
}
The skip_serializing attribute means ignore the field when serializing the struct. Similarly, the skip_deserializing attribute means ignore the field when deserializing.
The default attribute gives the value to use for the field when deserializing. Fields that implement std::default::Default do not need this as Serde is able to use the value of Default::default().

Creating default function parameters [duplicate]

This question already has answers here:
Default function arguments in Rust
(7 answers)
Closed 7 years ago.
Is there a way to create pseudo default function parameters in rust? I'd like to do something like
pub struct Circular<T> {
raw: Vec<T>,
current: u64
}
impl<T> Circular<T> {
pub fn new(t_raw: Vec<T>, t_current=0: u64) -> Circular<T> {
return Circular { raw: t_raw, current: t_current };
}
I'd like to have the option of settings the current variable, but it won't always be needed to be set. Is this a possible thing to do in Rust?
No, Rust doesn't support default function arguments. You have to define different methods, or in case of struct initialization (your example) you can use the struct update syntax like this:
use std::default::Default;
#[derive(Debug)]
pub struct Sample {
a: u32,
b: u32,
c: u32,
}
impl Default for Sample {
fn default() -> Self {
Sample { a: 2, b: 4, c: 6}
}
}
fn main() {
let s = Sample { c: 23, .. Sample::default() };
println!("{:?}", s);
}

Resources