Folks!
long time I don't hang out here
Anyhow I got a small problem and I would like your input on it and on the pattern.
In Rust code I create a structure that hold sender of a channel, this structure is then managed by C code via FFI. Eventually I get back the raw pointer from the C code and I need to send to the channel.
This code works (or at least seems to work).
#[repr(C)]
pub struct RedisKey {
pub key: *mut rm::ffi::RedisModuleKey, // this is the raw pointer
}
impl RedisKey {
// this is how we create the structure
pub fn new(key_name: &str, ctx: &Context) -> Self {
let key_name = rm::RMString::new(ctx, key_name);
let key =
rm::OpenKey(ctx, &key_name, rm::ffi::REDISMODULE_WRITE);
RedisKey { key }
}
// this is how we access the sender
pub fn get_channel(
&self,
) -> Result<&Sender<Command>, RediSQLError> {
match self.key_type() {
KeyTypes::RediSQL => unsafe {
// we get the raw pointer
let dbkey = rm::ffi::RedisModule_ModuleTypeGetValue
.unwrap()(self.key)
as *mut DBKey;
Ok(&(*dbkey).tx) // just return the sender here
},
// business logic here
KeyTypes::Empty => Err(RediSQLError::empty_key()),
_ => Err(RediSQLError::no_redisql_key()),
}
}
}
The problem of this code is that eventually I need to remember to don't drop anything
So I moved into this other code:
#[repr(C)]
pub struct RedisKey {
pub key: *mut rm::ffi::RedisModuleKey,
}
// let's use this structure that `Deref` to DBKey,
// so I don't have to remember anything anymore!
pub struct UndroppableDBKey {
dbkey: std::mem::ManuallyDrop<DBKey>,
}
impl std::ops::Deref for UndroppableDBKey {
type Target = DBKey;
fn deref(&self) -> &Self::Target {
&self.dbkey
}
}
impl RedisKey {
pub fn new(key_name: &str, ctx: &Context) -> Self {
.... as before ....
}
pub fn get_channel(
&self,
) -> Result<Sender<Command>, RediSQLError> {
// use the method below to get the undroppable version
let dbkey = self.get_dbkey()?;
// the second time I use this Sender the channel is closed.
Ok(dbkey.tx.clone())
}
pub fn get_dbkey(
&self,
) -> Result<UndroppableDBKey, RediSQLError> {
match self.key_type() {
// similar to above, we get the raw pointer here
KeyTypes::RediSQL => {
let dbkey = unsafe {
rm::ffi::RedisModule_ModuleTypeGetValue.unwrap()(
self.key,
) as *mut DBKey
};
// eventually we read the pointer, get the structure and
// push the new structure in ManuallyDrop
Ok(UndroppableDBKey {
dbkey: std::mem::ManuallyDrop::new(unsafe {
dbkey.read()
}),
})
}
KeyTypes::Empty => Err(RediSQLError::empty_key()),
_ => Err(RediSQLError::no_redisql_key()),
}
}
}
The second version does not work, it works once and then the Sender is closed, the error is something like: sending on a closed channel
.
Unfortunately I don't understand what I am doing wrong and why?
Do you guys have ideas?