-
Notifications
You must be signed in to change notification settings - Fork 134
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
Framing
refactor: framing.rs
api
#1033
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,7 +12,11 @@ type Slice = buffer_sv2::Slice; | |
/// A wrapper to be used in a context we need a generic reference to a frame | ||
/// but it doesn't matter which kind of frame it is (`Sv2Frame` or `HandShakeFrame`) | ||
#[derive(Debug)] | ||
pub enum Frame<T, B> { | ||
pub enum Frame<T, B> | ||
where | ||
T: Serialize + GetSize, | ||
B: AsMut<[u8]> + AsRef<[u8]>, | ||
{ | ||
HandShake(HandShakeFrame), | ||
Sv2(Sv2Frame<T, B>), | ||
} | ||
|
@@ -26,25 +30,23 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Frame<T, B> { | |
} | ||
} | ||
|
||
impl<T, B> From<HandShakeFrame> for Frame<T, B> { | ||
impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> From<HandShakeFrame> for Frame<T, B> { | ||
fn from(v: HandShakeFrame) -> Self { | ||
Self::HandShake(v) | ||
} | ||
} | ||
|
||
impl<T, B> From<Sv2Frame<T, B>> for Frame<T, B> { | ||
impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> From<Sv2Frame<T, B>> for Frame<T, B> { | ||
fn from(v: Sv2Frame<T, B>) -> Self { | ||
Self::Sv2(v) | ||
} | ||
} | ||
|
||
/// Abstraction for a SV2 Frame. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should expand this comment to make it clear what each maybe something like:
updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
#[derive(Debug, Clone)] | ||
pub struct Sv2Frame<T, B> { | ||
header: Header, | ||
payload: Option<T>, | ||
/// Serialized header + payload | ||
serialized: Option<B>, | ||
pub enum Sv2Frame<T, B> { | ||
Payload { header: Header, payload: T }, | ||
Raw { header: Header, serialized: B }, | ||
} | ||
|
||
impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | ||
|
@@ -53,23 +55,23 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | |
/// When called on a non serialized frame, it is not so cheap (because it serializes it). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should update these comments so that they are coherent with the new behavior of this function updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
#[inline] | ||
pub fn serialize(self, dst: &mut [u8]) -> Result<(), Error> { | ||
if let Some(mut serialized) = self.serialized { | ||
dst.swap_with_slice(serialized.as_mut()); | ||
Ok(()) | ||
} else if let Some(payload) = self.payload { | ||
#[cfg(not(feature = "with_serde"))] | ||
to_writer(self.header, dst).map_err(Error::BinarySv2Error)?; | ||
#[cfg(not(feature = "with_serde"))] | ||
to_writer(payload, &mut dst[Header::SIZE..]).map_err(Error::BinarySv2Error)?; | ||
#[cfg(feature = "with_serde")] | ||
to_writer(&self.header, dst.as_mut()).map_err(Error::BinarySv2Error)?; | ||
#[cfg(feature = "with_serde")] | ||
to_writer(&payload, &mut dst.as_mut()[Header::SIZE..]) | ||
.map_err(Error::BinarySv2Error)?; | ||
Ok(()) | ||
} else { | ||
// Sv2Frame always has a payload or a serialized payload | ||
panic!("Impossible state") | ||
match self { | ||
Sv2Frame::Raw { mut serialized, .. } => { | ||
dst.swap_with_slice(serialized.as_mut()); | ||
Ok(()) | ||
} | ||
Sv2Frame::Payload { header, payload } => { | ||
#[cfg(not(feature = "with_serde"))] | ||
to_writer(header, dst).map_err(Error::BinarySv2Error)?; | ||
#[cfg(not(feature = "with_serde"))] | ||
to_writer(payload, &mut dst[Header::SIZE..]).map_err(Error::BinarySv2Error)?; | ||
#[cfg(feature = "with_serde")] | ||
to_writer(&header, dst.as_mut()).map_err(Error::BinarySv2Error)?; | ||
#[cfg(feature = "with_serde")] | ||
to_writer(&payload, &mut dst.as_mut()[Header::SIZE..]) | ||
.map_err(Error::BinarySv2Error)?; | ||
Ok(()) | ||
} | ||
} | ||
} | ||
|
||
|
@@ -78,18 +80,19 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | |
/// This function is only intended as a fast way to get a reference to an | ||
/// already serialized payload. If the frame has not yet been | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should update these comments so that they are coherent with the new behavior of this function updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
/// serialized, this function should never be used (it will panic). | ||
pub fn payload(&mut self) -> &mut [u8] { | ||
if let Some(serialized) = self.serialized.as_mut() { | ||
&mut serialized.as_mut()[Header::SIZE..] | ||
} else { | ||
// panic here is the expected behaviour | ||
panic!("Sv2Frame is not yet serialized.") | ||
pub fn payload(&mut self) -> Option<&mut [u8]> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we rename this method? with the new so calling a method that is named I feel we would create a more sane user experience if this method was called |
||
match self { | ||
Sv2Frame::Raw { serialized, .. } => Some(&mut serialized.as_mut()[Header::SIZE..]), | ||
Sv2Frame::Payload { .. } => None, | ||
} | ||
} | ||
|
||
/// `Sv2Frame` always returns `Some(self.header)`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should update these comments so that they are coherent with the new behavior of this function updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
pub fn get_header(&self) -> Option<crate::header::Header> { | ||
Some(self.header) | ||
pub fn header(&self) -> crate::header::Header { | ||
match self { | ||
Self::Payload { header, .. } => *header, | ||
Self::Raw { header, .. } => *header, | ||
} | ||
} | ||
|
||
/// Tries to build a `Sv2Frame` from raw bytes, assuming they represent a serialized `Sv2Frame` frame (`Self.serialized`). | ||
|
@@ -110,10 +113,9 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | |
pub fn from_bytes_unchecked(mut bytes: B) -> Self { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Github doesn't allow me to add this comment on the lines above. Ideally this comment should be placed on line 98, but placing it here should be sufficient the comments on we should update these comments so that they are coherent with the new behavior of this function updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
// Unchecked function caller is supposed to already know that the passed bytes are valid | ||
let header = Header::from_bytes(bytes.as_mut()).expect("Invalid header"); | ||
Self { | ||
Self::Raw { | ||
header, | ||
payload: None, | ||
serialized: Some(bytes), | ||
serialized: bytes, | ||
} | ||
} | ||
|
||
|
@@ -147,13 +149,9 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | |
/// otherwise, returns the length of `self.payload`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should update these comments so that they are coherent with the new behavior of this function updating the comments is especially important given that these are used on the Rust Docs, so they need to follow these changes accordingly |
||
#[inline] | ||
pub fn encoded_length(&self) -> usize { | ||
if let Some(serialized) = self.serialized.as_ref() { | ||
serialized.as_ref().len() | ||
} else if let Some(payload) = self.payload.as_ref() { | ||
payload.get_size() + Header::SIZE | ||
} else { | ||
// Sv2Frame always has a payload or a serialized payload | ||
panic!("Impossible state") | ||
match self { | ||
Sv2Frame::Raw { serialized, .. } => serialized.as_ref().len(), | ||
Sv2Frame::Payload { payload, .. } => payload.get_size() + Header::SIZE, | ||
} | ||
} | ||
|
||
|
@@ -167,30 +165,31 @@ impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<T, B> { | |
) -> Option<Self> { | ||
let extension_type = update_extension_type(extension_type, channel_msg); | ||
let len = message.get_size() as u32; | ||
Header::from_len(len, message_type, extension_type).map(|header| Self { | ||
Header::from_len(len, message_type, extension_type).map(|header| Self::Payload { | ||
header, | ||
payload: Some(message), | ||
serialized: None, | ||
payload: message, | ||
}) | ||
} | ||
} | ||
|
||
impl<A, B> Sv2Frame<A, B> { | ||
impl<A: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> Sv2Frame<A, B> { | ||
/// Maps a `Sv2Frame<A, B>` to `Sv2Frame<C, B>` by applying `fun`, | ||
/// which is assumed to be a closure that converts `A` to `C` | ||
pub fn map<C>(self, fun: fn(A) -> C) -> Sv2Frame<C, B> { | ||
let serialized = self.serialized; | ||
let header = self.header; | ||
let payload = self.payload.map(fun); | ||
Sv2Frame { | ||
header, | ||
payload, | ||
serialized, | ||
pub fn map<C>(self, fun: fn(A) -> C) -> Sv2Frame<C, B> | ||
where | ||
C: Serialize + GetSize, | ||
{ | ||
match self { | ||
Sv2Frame::Raw { header, serialized } => Sv2Frame::Raw { header, serialized }, | ||
Sv2Frame::Payload { header, payload } => Sv2Frame::Payload { | ||
header, | ||
payload: fun(payload), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
impl<T, B> TryFrom<Frame<T, B>> for Sv2Frame<T, B> { | ||
impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> TryFrom<Frame<T, B>> for Sv2Frame<T, B> { | ||
type Error = Error; | ||
|
||
fn try_from(v: Frame<T, B>) -> Result<Self, Error> { | ||
|
@@ -232,7 +231,7 @@ impl HandShakeFrame { | |
} | ||
} | ||
|
||
impl<T, B> TryFrom<Frame<T, B>> for HandShakeFrame { | ||
impl<T: Serialize + GetSize, B: AsMut<[u8]> + AsRef<[u8]>> TryFrom<Frame<T, B>> for HandShakeFrame { | ||
type Error = Error; | ||
|
||
fn try_from(v: Frame<T, B>) -> Result<Self, Error> { | ||
|
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.
Best practice is to constrain generics only where you need 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.
In the impl block where you have function that need the generics to be constrained
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.
Having naked generics makes it really hard to read the enum
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.
I don't get it. Why is harder?
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.
Maybe you want to use InnerType and Buffer instead of T and B ?
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.
previously it was only
Frame<T,B>{ HandShake(HandShakeFrame), Sv2(Sv2Frame<T,B>)
without any info about T and BThere 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.
I dont feel very strongly about it, but I would appreciate reviewing the full PR (:
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.
I went trough the code everything look very good to me.
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 is the outcome here?
@Fi3 do you still feel need we shouldn't be constraining generics here? or looking at the rest of the PR change your mind?
should we drop this commit from the PR?
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.
constrain generics where not needed is bad, so my opinion is the same. If you are concerned about readability you can use Frame<InnerType,Buffer> instead of Frame<T,B>