-
-
Notifications
You must be signed in to change notification settings - Fork 509
Support for serialization using abomonation #279
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
Conversation
Hello! Yes, I think the slice use in
For example, here is the #[inline]
unsafe fn exhume<'a,'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
// extract memory from bytes to back our vector
let binary_len = self.len() * mem::size_of::<T>();
if binary_len > bytes.len() { None }
else {
let (mine, mut rest) = bytes.split_at_mut(binary_len);
let slice = std::slice::from_raw_parts_mut(mine.as_mut_ptr() as *mut T, self.len());
std::ptr::write(self, Vec::from_raw_parts(slice.as_mut_ptr(), self.len(), self.len()));
for element in self.iter_mut() {
let temp = rest; // temp variable explains lifetimes (mysterious!)
rest = try_option!(element.exhume(temp));
}
Some(rest)
}
} I think this almost directly applies, except that (edit: see next comment):
If you think that Also, the tests seem sane but I would mention that it is super hard to test Abomonation without round-tripping things through different address spaces. It is not uncommon to have a bug, but the pointer still points at legitimately interpreted memory and so passes the test. Not sure about how best to test this, though (perhaps re-rigging the tests to forcibly drop the input used for serialization?). |
Actually, I think the abomonation methods should be much simpler for My guess is that the implementation should look roughly like the tuple implementation (based on my understanding of impl<T: Abomonation> Abomonation for GenericArray<T,N> {
#[inline]
unsafe fn embalm(&mut self) {
// provide each element the opportunity to embalm (clean up representation).
for element in self.as_mut_slice().iter_mut() {
element.embalm();
}
}
#[inline]
unsafe fn entomb(&self, bytes: &mut Vec<u8>) {
// provide each element the opportunity to entomb data.
for element in self.as_slice().iter() { element.entomb(bytes); }
}
#[inline]
unsafe fn exhume<'a,'b>(&'a mut self, but bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
// provide each element the opportunity to exhume data.
for element in self.as_mut_slice().iter_mut() {
let temp = bytes; // temp variable explains lifetimes (mysterious!)
bytes = try_option!(element.exhume(temp));
}
Some(bytes)
}
} I think you should be able to slot this in to |
This is more robust than delegating to a slice, which has been removed upstream due to unsafety. Since we can rely on there being no pointer indirection in a GenericArray, we just iterate over the array.
The new changes look totally sane to me. Hard to know without being the one testing it, but it looks right. :) |
@frankmcsherry Thank you very much for the very thorough review. I adopted your suggested implementation for cc @fizyk20 if you are interested ^^ I'll have another look at the tests. Adding a drop is easy enough to do. |
No worries. :) I'd be happy to move some of these impls to Abomonation, but just a little worried about the back-compat issues (since I can't track if any are actually used). Perhaps they could land there with feature flags? This must have come up before as a pattern, coherence-be-damned. |
If I were in your position, I would not take in impls for other crates' types, unless you depend on them anyway. It is much more natural for a type provider to maintain the implementation than for the trait provider. Most importantly, you may need access to private fields in order to implement the trait, which can't be done out-of-crate. Also, the implementation tends to change more frequently with the type, as traits are usually more stable as they are contracts by design. I guess that issue is part of the reason why the community tends to gravitate to common abstractions (like serde) to keep the boilerplate of optional features to a minimum So yeah, coherence has its ups and downs. There have been heated debates around the issue, see rust-lang/rfcs#493 for example. I don't think anybody felt comfortable bringing modular typeclasses (from ML) or instance arguments (from Agda) to Rust, mostly because safety and semantics of common abstractions like |
@sebcrozet from my point of view, this is done. feel free to merge. |
Thanks! This will be released on the version 0.13 of nalgebra. |
Resolves #277.
I ended up implementing the trait by hand after all. This is basically, because
abomonation_derive
is not quite as flexible for our types, as it needs to be.I intend to change that upstream (see TimelyDataflow/abomonation#4), but for now the manual implementation should suffice.
cc @frankmcsherry
I would be very glad, if you could provide some feedback on whether these implementations look sane to you. Almost all of them are pure delegations. I am somewhat uncertain about the usage of slices in
src/core/matrix_array.rs
though. The test cases seem to work out, but I want to make sure I am not overlooking a critical issue here.