Closed najamelan closed 5 years ago
I forgot to mention. Sometimes you have to explicitly set structs to be not Send
or Sync
if they are not threadsafe. Especially when working with C code it's good to think about this for every structure.
This one is trickier.
I've been using #derive[]
sparingly on an "as-needed" basis. For example, NngError
has Clone/Copy/Debug/PartialEq.
Most of the other structs are wrappers around C FFI bindings and not safe for Copy/Clone. Pretty much all of them have a function that needs to be called on Drop
(nng_msg_free
, nng_close
, etc.). As much as possible I'd like to use Rust to enforce "correct" usage, but I haven't really settled on the best way to deal with this:
Arc
(code)For example, once you've called create_async_context() I don't think it's safe to use the socket (because nng_aio will be using it), so the socket should probably get "consumed" (i.e. create_async_context(self)
instead of create_async_context(&self)
). But I need to ask the nng author to be sure.
Pipes complicate this because they can be obtained from a message, but closing them will make the associated nng_ctx/nng_aio fail...
But I think you're right that there could be some improvements:
impl Clone for NngMsg
(which just calls nng_msg_dup
)Debug
is safe everywhere so I'll look at sprinkling it aroundThanks for looking into this. This makes me wonder, in async code it is common to use closures and thus often one needs to "clone" things. In the little test app I posted, I thus end up cloning a protocol::pair1::Pair1
even though it's not in polyamorous mode. Is that a problem?
It's ok to clone it, it won't get closed until the last reference goes away. The Arc
provides Send/Sync.
At the moment there's only impl Send for NngAio
because I tend to write:
let a = factory.pair_open()?.listen(&url)?;
let b = factory.pair_open()?.dial(&url)?;
let a_thread = thread::spawn(move || -> NngReturn {
let mut ctx = a.create_async_context()?;
//...
});
I don't plan to use the synchronous functions like SendMsg::send()
so I've not thought about that part of the API much. If you do plan to use that part, feel free to make suggestions or a PR. Come to think of it, I'm not even sure its got tests.
Right now if a struct contains for example a
protocol::pair1::Pair1
it can't deriveDebug
becausePair1
doesn't implement it. It is generally accepted to more or less always derive or implement at leastDebug
for allpub struct
s.Others that might be useful can be found in the rust book.
Eq
might also make sense for a socket. For the difference betweenEq
andPartialEq
, see here.Some traits are handy if it makes sense, like
Copy
, but they have implications for the future. If you later add a non-Copy
property to your struct, you will have to break the API by removingCopy
and instances will be implicitly copied on the stack which might not always be a good idea. HoweverClone
is explicit and might be a good idea.