These are chat archives for rust-lang/rust

26th
Feb 2017
Tomer Margalit
@matomer
Feb 26 2017 14:33
hi, I'm stuck trying to implement a global function pointer in rust. I have a global graphics context that can alloc/dealloc buffers and I'd like to use it everywhere without passing it around the program. However nothing I've tried (e.g. references, options, raw pointers) will let me store and use a global function pointer (such as alloc) that I will set at runtime. How should this be done in rust?
Aleksey Kladov
@matklad
Feb 26 2017 14:37
You can store global data in static,
but it requires that the data you store is thread safe. That is, you can have a static B: AtomicBool, but not static B: Cell<bool>.
Tomer Margalit
@matomer
Feb 26 2017 14:39
@matklad I tried using a static mut variable but then I need a Box for a trait and then rust complains about destructors in static being experimental
Aleksey Kladov
@matklad
Feb 26 2017 14:40
A common solution to "I want global data initlalized at runtime" is https://crates.io/crates/lazy_static
Aleksey Kladov
@matklad
Feb 26 2017 14:49
Yeah, looks like statics with destructors have not been stabilized yet. Another option (which I believe is what lazy static does internaly), is to leak the Box, converting it into const *: https://github.com/rust-lang-nursery/lazy-static.rs/blob/master/src/lazy.rs#L15
Tomer Margalit
@matomer
Feb 26 2017 14:49
but I need a mut variable
Aleksey Kladov
@matklad
Feb 26 2017 14:50
Because you want to initialize it lately, or because you really want to change it sometimes?
Tomer Margalit
@matomer
Feb 26 2017 14:51
basically it doesn't matter to me - I really just want to implement a function somewhere with runtime arguments and then pass it
however those args will have to be mutable
basically I need a way to opt out of the compiler guards completely for a type. Is that possible?
Aleksey Kladov
@matklad
Feb 26 2017 14:57
This is usually achieved with raw pointers or UnsafeCell.
Tomer Margalit
@matomer
Feb 26 2017 14:57
I tried that but rust won't let me initialize a *mut TRAIT
I tried = (0 as *mut TRAIT)
and rust complains that it can't be converted
"casting usize as ... is invalid"
Aleksey Kladov
@matklad
Feb 26 2017 15:03
Huh, there's not ATOMIC_PTR_INIT which you can use to initialize AtomicPtr...
Hm, I think that you can use AtomicUsize and cast it to AtomicPtr with transmute in the get operation, but this does not feel right
Especially because you need two words to store a pointer to a trait object.
Tomer Margalit
@matomer
Feb 26 2017 15:06
I tried using &mut 0 and that seems to work
but now it complains about using 0
Aleksey Kladov
@matklad
Feb 26 2017 15:10
Still, I don't undestand why something like this is not enough:
#[macro_use]
extern crate lazy_static;

struct CtxImpl;

impl CtxImpl {
    fn new() -> Self {
        CtxImpl
    }
}

trait Ctx: Sync {
    // note: it **have** to take `self` by shared reference, because
    // the context is globally accessible
    fn foo(&self) {}
}

impl Ctx for CtxImpl {}

lazy_static! {
    static ref CTX: Box<Ctx> = Box::new(CtxImpl::new());
}
Tomer Margalit
@matomer
Feb 26 2017 15:14
I get macro undefined when trying to use lazy_static
but also - it's incredibly complicated for something as simple as a global callback/function pointer
Aleksey Kladov
@matklad
Feb 26 2017 15:15
have you added lazy_static to Cargo.toml? And is #[macro_use] present before extern crate?
Tomer Margalit
@matomer
Feb 26 2017 15:16
yes
Aleksey Kladov
@matklad
Feb 26 2017 15:16

it's incredibly complicated for something as simple as a global callback/function pointer

Indeed it is. But in multithreaded programs global data is incredibly complicated. This solution guarantees correct synchronization.

Tomer Margalit
@matomer
Feb 26 2017 15:16
it isn't complicated. It's a mutex around a global callback. You lock when allocating data and that's it.

You lock when allocating data and that's it.

You also need some synchronization (atomic read) when reading the value afterwards. And you need to make sure that the value itself is threadsafe.

Tomer Margalit
@matomer
Feb 26 2017 15:19
No need for atomic read... It's just a lock around the callback (for the allocator state) once you get the data you can use it without locking
or buffer
Aleksey Kladov
@matklad
Feb 26 2017 15:20
Yep, you are correct, I've misunderstood your original statement!
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:00
Hello guys
Do you know how to represent something like: int const * const variable_name in Rust?
My guess would be:
int const *const variable <==> variable: *const libc::c_int
int *const variable <==> variable: *mut libc::c_int
Is there a way for me to say that the address is immutable?
Aleksey Kladov
@matklad
Feb 26 2017 16:05
let mut prt: *const libc::c_int vs let ptr: *const libc::c_int.
But the second const does not affect ffi in any way, so you should not worry about it.
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:08
Ok, thanks @matklad !
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:18
So, this seems correct to you?
C: int dlt_env_extract_ll_set(char ** const env, dlt_env_ll_set * const ll_set);
Rust: fn dlt_env_extract_ll_set(env: *mut *mut c_char, ll_set: *mut dlt_env_ll_set) -> c_int;
char ** const env -> env: *mut *mut c_char
_set *const ll_set -> ll_set: *mut _set
Aleksey Kladov
@matklad
Feb 26 2017 16:22
That seems correct, yes. Perhaps it's worth trying to use bindgen: https://github.com/servo/rust-bindgen.
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:23
Thanks for the suggestion. I was thinking about it but for some reason I don't trust it to understand some thing in the code
Aleksey Kladov
@matklad
Feb 26 2017 16:24
I don't trust myself when reading C code :)
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:25
The code has things like:
#if !defined (PACKED)
#define PACKED __attribute__((aligned(1),packed))
#endif

#if defined (__MSDOS__) || defined (_MSC_VER)
#undef PACKED
#define PACKED
#endif

I know I can do things like(ignores MSDOS):

#[cfg_attr(not(target_env = "msvc"), repr(packed))]
#[repr(C)]

On every structure where the macro is used

I have not tried it but I don't think bindgen can handle this
Just an assumption
The thing I worry the most is that I am not a robot and copying is error prone for a human...
Aleksey Kladov
@matklad
Feb 26 2017 16:28
Perhaps you can use bindgen to generate some basic stuff (and make sure that you don't mess up number and types of arguments, etc), and then go through bindings by hand to add things it can't handle?
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:39
I mostly finished the port but I will run it because I am curious now how it handles it all
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:49
bindgen actually wrote better code than me... Maybe not elegantly aligned with the doxygen docs copied but it put derives that I didn't think of yet
Also, a lot of unnecessary constants copied from system headers but this is not a big issue... It's easy to delete them
Did not copy any of the Windows specific code...
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:55
It did use packed but for all systems... So this is incorrect code
I guess, on simple headers, it is preferable to run bindgen, on more complicated code, it's better to write it by hand(the code it generated for the more complicated version is hardly modifiable/understandable)
Aleksey Kladov
@matklad
Feb 26 2017 16:58
FYI,win-rs uses artisanal hand-crafted bindings.
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 16:58
1 header(the more complicated one):
  • The hand-written port with all the docs = 341 lines
  • Bindgen port without docs: 5660 lines
Peter Atashian
@retep998
Feb 26 2017 17:03
@lilianmoraru bindgen only handles the current target. It can't do cfgs based on preprocessor macros for other platforms
In winapi everything I do is manually by hand, because bindgen's output is so far from where I need it and missing so much stuff that it is easier to just hand write it than it is to fix up the bindgen output
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 17:05
Yes, observed that. I plan to add cfgs based on features that will be named the same as the macros(at least, that's the initial plan)
It did help me get my enums correct - I did not derive everything I should of
Peter Atashian
@retep998
Feb 26 2017 17:09
I actually have a bunch of fancy macros to make my code a lot simpler and handle all the boilerplate for me
as for enums, I don't use rust enums for several reasons, instead I have my enum macro just define them as integer constants
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 17:10
And if the function asks for "-> SomeEnum", you just return c_int/i32?
This is also an option
Peter Atashian
@retep998
Feb 26 2017 17:11
Nah, I still have SomeEnum, it is just an alias for u32
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 17:12
I do it like this(example from code):
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DltReturnValue {
    DLT_RETURN_LOGGING_DISABLED = -7,
    DLT_RETURN_USER_BUFFER_FULL = -6,
    DLT_RETURN_WRONG_PARAMETER  = -5,
    DLT_RETURN_BUFFER_FULL      = -4,
    DLT_RETURN_PIPE_FULL        = -3,
    DLT_RETURN_PIPE_ERROR       = -2,
    DLT_RETURN_ERROR            = -1,
    DLT_RETURN_OK               = 0,
    DLT_RETURN_TRUE             = 1,
}
I want the mapping to be more direct, if another user comes to add or modify something, it should be easy for them
As a rule for myself, everything has to be defined in the same order
Also, if this is in a specific header, than it has to be in a module named the same way(then exported from libs.rs)
I saw that openssl-sys puts everything in one file...
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 17:18
Big blocks of code that are under #ifdef I think to put in separate modules and then do:
#[cfg(feature = "SOME_DEFINE")]
pub use that_module::*;
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 18:01
Seems like I made a few more mistakes that bindgen helped me identify...
A few more derives and forgetting to use pub for the exported functions
Aravindh Sridharan
@hardvain
Feb 26 2017 18:09
I am writing a blog explaining certain features of rust. Is there any website that allows me to create representation of the following concepts online? 1. How variables are stored in memory and with some animations on what happens when a variable goes out of scope,
  1. Marking the scope of code blocks,
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 18:10
There are presentation on youtube with books burning and stuff like this
But there are also some pictures, if don't want to look through a video
sec
Aravindh Sridharan
@hardvain
Feb 26 2017 18:11
nah. not that much animation. Just a vertical tabular representation of memory, and some basic animations to add / remove few elements from that tabular representation
this looks nice even though it doesnt have any animation. Do you know the tool with which this was drawn?
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 18:12
The creator says Inkscape in the comments
Those are SVG images, so you can make them as big as you want
Aravindh Sridharan
@hardvain
Feb 26 2017 18:13
ya i saw that
thanks for the information
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 18:13
yw
Lilian Anatolie Moraru
@lilianmoraru
Feb 26 2017 22:18
@matklad The function I asked your opinion on if it is correctly written, bindgen generated a different code:
int dlt_env_extract_ll_set(char ** const env, dlt_env_ll_set * const ll_set); - bindgen -> pub fn dlt_env_extract_ll_set(env: *const *mut ::std::os::raw::c_char, ll_set: *const dlt_env_ll_set) -> ::std::os::raw::c_int
Will have to talk with the bindgen author to see his take on this. I think the generated code is wrong, but maybe there is something I don't know
Ok, seems to have an issue already: servo/rust-bindgen#511