Interpretation(std::raw::TraitObject)

Dear Gurus, I need some help to understand when should i use std::raw::TraitObject, and the syntax to realize it. The code from the book does not work, that is why i'm asking for help. But as i understood it is used for callbacks (am i right?)

std::raw::TraitObject is almost never what you want. Could you please give an example of where you need it for?

2 Likes

Thanks for your time, sent on me.
I am currently working through rust and the only source of help when i have questions is forums.
According to the book we have following:

struct FooVtable {
destructor: fn(*mut ()),
size: usize,
align: usize,
method: fn(*const ()) -> String,
}
// u8:
fn call_method_on_u8(x: const ()) -> String {
let byte: &u8 = unsafe { &
(x as *const u8) };
byte.method() // ????????????????????????????
}

// String:
fn call_method_on_String(x: const ()) -> String {
let string: &String = unsafe { &
(x as *const String) };
string.method() // ?????????????????????????????
}

fn main()
{
static Foo_for_String_vtable: FooVtable = FooVtable {
destructor: /* Compiler magic */,
size: 24,
align: 8,
method: call_method_on_String as fn(*const ()) -> String,
};
static Foo_for_u8_vtable: FooVtable = FooVtable {
destructor: /Compiler magic/,
size: 1,
align: 1,
method: call_method_on_u8 as fn(*const ()) -> String,
};
let a: String = "foo".to_string();
let x: u8 = 1;
// let b: &Foo = &a;
let b = TraitObject {
// store the data
data: &a,
// store the methods
vtable: &Foo_for_String_vtable
};
// let y: &Foo = x;
let y = TraitObject {
// store the data
data: &x,
// store the methods
vtable: &Foo_for_u8_vtable
};
// b.method();
(b.vtable.method)(b.data);
// y.method();
(y.vtable.method)(y.data);
}

Questions are next:

  1. byte.method() // What method is being called?
  2. string.method() // What method is being called?
    I have marked it in the code as // ?????????????????????
  3. Why this code doesnt work?

What book are you reading?

documentation
Rust Programming Language

This one?
https://doc.rust-lang.org/book/second-edition/

No, Sir
http://rurust.github.io/rust_book_ru

That code in the book is trying to describe what the trait object (ie dynamic) dispatch sort of translates to - it’s not code you should try to run yourself.

The byte.method() just means it’s calling the method() implementation for u8. Similarly, string.method() is the impl for String. That book section is talking about a trait setup like this:

trait Foo {
   fn method(&self) -> String;
}

impl Foo for u8 {
    fn method(&self) -> String { 
      // some code here
    }
}

impl Foo for String {
   fn method(&self) -> String {
      // some other code here
   }
}

So byte.method() and string.method() are calling those two impls, respectively.

You don’t need to worry about this in normal code though - the compiler does this for you.

Thanks, Vitalyd.
But what if we need to use std::raw::TraitObject ?
What should i initialize its fields with?

If you're still learning Rust, there's a 99.99% chance that you don't need to use std::raw::TraitObject. This is likely what they call the XY problem: you're trying to achieve something and think raw trait objects are the solution, so you ask us how to work with those, when in fact you'd be better off asking us to help with solving your original problem.

But if you really really want to use that, here's the deal. You don't initialize its fields directly. Instead, you create some trait object and then transmute it to std::raw::TraitObject like this:

// create a trait object
let trait_object_42 = &42 as &Display;
// transmute it into a raw::TraitObject
let raw: raw::TraitObject = unsafe { transmute(trait_object_42) };
// inpect the raw::TraitObject
println!("data at {:p}, vtable at {:p}", raw.data, raw.vtable);
// constuct a new trait object with the same vtable,
// but different data
let raw2 = raw::TraitObject {
    data: &35 as *const _ as *mut (),
    vtable: raw.vtable,
};
let trait_object_35: &Display = unsafe { transmute(raw2) };
println!("new trait object: {}", trait_object_35);

(playground link)

But let me repeat again, this is very likely not what you need.

2 Likes

Thank you for help. I hope it will work out well in future.

Guys, need some help.

struct A{
string1:String,
string2:String,
}

fn func(x:&A)->String{
x.string1+&x.string2
}
fn main()
{
let x=A{string1:"Hello".to_string(),string2:" World".to_string());
println!("{}",func(&x));
}
//////////////////////////////////////////////////////////////////////////
x.string1+&x.string2
| ^^^^^^ cannot move out of borrowed content

Use format!() to create a new string:

fn func(x:&A)->String{
    format!("{} {}", x.string1, x.string2)
}

Thank you very much for solution.
But isnt a new string created in here x.string1+&x.string2 ???????

It does create a new string but it consumes/moves the string on the left of the + operator (it reuses its buffer to store the data). You can’t consume/move it here because it’s owned by the A instance that’s borrowed.

You could do x.string1.clone() + &x.string2 but generally string concatenation isn’t done with the + operator in Rust.

Thank you again. Your help is priceless.

Hello there. Here is another piece of information to think about:
macro_rules! My_mac2 {
(x=$x:expr)=>{
{
let mut ves: Vec = Vec::new();
for i in 0..$x{
ves.push(i);
}
ves
}
}
};
fn main()
{
let a=My_mac2!(x=3);
for i in a{
print!("{} ",i);}
println!();
}
// 0,1,2
While coding let mut ves: Vec = Vec::new();
it does not see the Vec namespace so it does not give hints on its static method new() in our case, typing Vec:: does not give anything, but the code works.

What exactly are you expecting to happen here? When I run this on the playground I get a compile error because a Vec is generic and thus requires you to mention a type between angle brackets (e.g. let mut ves: Vec<u32> = ...), yet you've just written Vec.

   |
3  |     let mut ves: Vec = Vec::new();
   |                  ^^^ expected 1 type argument

Pro tip: the forum will do proper code formatting and syntax highlighting if you put a ``` before and after a code snippet, or indent the snippet by 4 spaces.

Sorry my fault, it suppose to be Vec.
However it does not change the question. The code works but the question remains the same: Why when i type let mut ves: Vec= Vec:: No hints on static methods of Vec appears, like it does not see std::vec::Vec namespace.

When you type Vec:: where? In your editor or in this forum?