-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve mdb #96
base: main
Are you sure you want to change the base?
Improve mdb #96
Conversation
kjughx
commented
Oct 7, 2024
•
edited
Loading
edited
- It doesn't make much sense to bundle OwnedOrBorrowedError when they serve different use cases, better split them into separate types.
- Message borrows *const mdb_sys::mdb_message_t so should contain a marker with a lifetime bound.
- The callbacks used in mdb are hidden behind pointers to pointers to DSTs when they could just be generic pointers. This also simplifies the UX since a consumer doesn't have to wrap callbacks in Box::new().
|
||
pub struct BorrowedError<'a> { | ||
ptr: *const mdb_sys::mdb_error_t, | ||
_marker: PhantomData<&'a mdb_sys::mdb_error_t>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well spotted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I think more about this, I start doubting that BorrowedError
should have an associated lifetime; maybe it is better/correct that the API only gives out &'a BorrowedError
instead, where 'a
is the lifetime of the reference. This looks at least superficially similar to &'a CStr
.
I want to do some research on this as well; If you are impatient about getting the new callbacks merged, I would suggest scaling back the scope of the PR to only those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #116, there the API only exposes Error
and &Error
. The owned Error
as a return value and &Error
in the callback.
crates/mdb/src/error.rs
Outdated
value | ||
} | ||
|
||
pub trait MdbError<Ptr> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are some benefits of defining a trait for this?
In particular, do we really want new
and as_ref
to be available to users of the library?
write!(f, "Code: {}; Message: {:?};", self.code(), self.message()) | ||
} | ||
} | ||
pub trait Callback<T>: FnMut(T) + Send + 'static {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, I have not seen this pattern for handling callbacks before. What are some benefits of using our own trait instead of relying on only the Fn*
traits?
Have you seen any other crates or authors using it (i.e. is there anywhere I can learn more about it)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benefit of this is not having to repeat for<'a> FnMut(BorrowedError<'a>) + Send + 'static
et. al. and risk making mistakes. I am still weary of introducing a trait for this purpose, so I will experiment a bit to learn more and maybe see if there is another way to achieve this DRYness.
} | ||
(false, true) => { | ||
let on_message = config.on_message; | ||
config.on_message = std::ptr::null_mut(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't store the on_message
callback on the Subscriber
, will it not be dropped as soon as this try_new
returns?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Could Subscriber just own SubscriberConfig which then is dropped when Subscriber is dropped?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could. I actually wrote it like that at first to minimize the complexity, but then I changed my mind thinking that it is unnecessary to tie up the mdb_subscriber_config_t
for the lifetime of the connection. Are there reasons other than complexity for going back? Is there anything in particular that you think contributes to complexity with the current solution (assuming complexity is the reason you want to change this)?
The variants of this enum are always treated as separate types so they should just be separate types.
Message borrows *const mdb_sys::mdb_message_t and should have a marker to indicate that.
It's very clunky to have to pass a Box<> callback. The functions that accept callbacks should be generic over the callback. The ownership of the callbacks was also unclear. Also no reason to allocate pointers to pointers on the heap. pointers are pointers.
Consider splitting the PR, the parts that are purely a refactoring are an especially good candidate. That way we can get something merged faster by focusing our attention on a smaller change. It may also help us write a good commit message; I'm trying to get into the habit of following conventional commits, but since I'm inconsistent at best this is not a requirement. |
write!(f, "Code: {}; Message: {:?};", self.code(), self.message()) | ||
} | ||
} | ||
pub trait Callback<T>: FnMut(T) + Send + 'static {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The benefit of this is not having to repeat for<'a> FnMut(BorrowedError<'a>) + Send + 'static
et. al. and risk making mistakes. I am still weary of introducing a trait for this purpose, so I will experiment a bit to learn more and maybe see if there is another way to achieve this DRYness.
} | ||
(false, true) => { | ||
let on_message = config.on_message; | ||
config.on_message = std::ptr::null_mut(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could. I actually wrote it like that at first to minimize the complexity, but then I changed my mind thinking that it is unnecessary to tie up the mdb_subscriber_config_t
for the lifetime of the connection. Are there reasons other than complexity for going back? Is there anything in particular that you think contributes to complexity with the current solution (assuming complexity is the reason you want to change this)?
|
||
pub struct BorrowedError<'a> { | ||
ptr: *const mdb_sys::mdb_error_t, | ||
_marker: PhantomData<&'a mdb_sys::mdb_error_t>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I think more about this, I start doubting that BorrowedError
should have an associated lifetime; maybe it is better/correct that the API only gives out &'a BorrowedError
instead, where 'a
is the lifetime of the reference. This looks at least superficially similar to &'a CStr
.
I want to do some research on this as well; If you are impatient about getting the new callbacks merged, I would suggest scaling back the scope of the PR to only those.
} | ||
|
||
impl Connection { | ||
// TODO: Consider adopting a builder-like pattern. | ||
pub fn try_new(on_error: Option<Box<OnError>>) -> Result<Self, Error> { | ||
/// Passing `None` as the `@on_error` callback requires qualifying the generic like so: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I know it is convention in Rust to reference parameters without an @
prefix, see for instance Box::new
.