Default::default() and statics

I've been working on slowly converting an existing C project into rust code. It's been going well for the most part, until I ran into some global statics I have to export for the old C code temporarily until I can remove the need for them.

Declaring and exporting the statics for FFI use was straightforward, but providing them with the required default value has been painful. Initially I thought all I had to do was "impl Default" for the various types found within the static struct. However, that led me to errors like this one:

error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
  --> project\src\main.rs:60:20
   |
60 |         somefield: Default::default(),
   |                    ^^^^^^^^^^^^^^^^^^

My understanding is that this is because trait functions currently can't be const in stable rust, so I can't make my fn default() const.

How do others work around this? Is there a workaround or do I just have to live with manually specifying the values of every field in every static struct?

You can make a const inherent method, and if you like also have your Default call that.

1 Like

Ah, I hadn't even considered that. I'm guessing this is what you meant:

#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct Vec3T([c_float; 3]);

impl Vec3T {
    pub const fn default() -> Self {
        Vec3T([0.0, 0.0, 0.0])
    }
}

impl Default for Vec3T {
    fn default() -> Self {
        Self::default()
    }
}

I'm hoping that this is equivalent (ffi-wise) to the below given the rust repr and that it's a tuple struct if I'm reading the docs correctly:

typedef float vec3_t[3];

If you want to guarantee ffi-compatibility with C, then use #[repr(C)], not #[repr(transparent)].

#[repr(C)]
pub struct Vec3T([c_float; 3]);

Although, technically, this would be the same in this case.

That's what I thought originally, but the rfc for repr(transparent) seems to insist that repr(transparent) is what you should use with any tuple struct case especially with ffi? Have I misread it?

Yes, #[repr(transparent)] struct Foo([c_float; 3]) is what you should pass to a C function that takes an array.

#[repr(C)] struct Foo([c_float; 3]) is what you should pass to a C function that takes a struct that contains an array.

4 Likes

Yes, sorry, I apologize; I was missing the important distinction that @mbrubeck made.

Aside from your issue, did you try C2Rust, yet?

I'm purposefully avoiding any automated translation to take the opportunity to internalize how to express certain concepts in rust and to delete or improve code.

2 Likes

That being said, in the case of arrays, C does not have the concept of directly taking an array by value that Rust does (it needs to be struct wrapped for it to happen):

1 Like