Skip to content
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

feat: allow encoding of borrowed data #9

Merged
merged 3 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic
Versioning](https://semver.org/spec/v2.0.0.html).

## [0.7.0]

### Changed

- Use GATs for `Encoder` trait to allow encoding of borrowed data.
See [PR 9](https://github.com/mxinden/asynchronous-codec/pull/9).
Comment on lines +13 to +14
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think of including the diff to the LengthCodec below here to help folks upgrade to the new version?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The diff is in the linked PR, isn't that equivalent?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It reduces one step for users.I think it might safe them some time. Not a strong preference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would prefer to just merge this to be honest :)

The compiler will also guide people to add the lifetime.


## [0.6.2]

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "asynchronous-codec"
edition = "2018"
version = "0.6.2"
version = "0.7.0"
authors = ["Max Inden <mail@max-inden.de>"]
description = "Utilities for encoding and decoding frames using `async/await`"
license = "MIT"
Expand Down
4 changes: 2 additions & 2 deletions src/codec/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@ use std::io::Error;
pub struct BytesCodec;

impl Encoder for BytesCodec {
type Item = Bytes;
type Item<'a> = Bytes;
type Error = Error;

fn encode(&mut self, src: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.extend_from_slice(&src);
Ok(())
}
Expand Down
4 changes: 2 additions & 2 deletions src/codec/cbor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ where
for<'de> Dec: Deserialize<'de> + 'static,
for<'de> Enc: Serialize + 'static,
{
type Item = Enc;
type Item<'a> = Enc;
type Error = CborCodecError;

fn encode(&mut self, data: Self::Item, buf: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, data: Self::Item<'_>, buf: &mut BytesMut) -> Result<(), Self::Error> {
// Encode cbor
let j = serde_cbor::to_vec(&data)?;

Expand Down
4 changes: 2 additions & 2 deletions src/codec/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ where
for<'de> Dec: Deserialize<'de> + 'static,
for<'de> Enc: Serialize + 'static,
{
type Item = Enc;
type Item<'a> = Enc;
type Error = JsonCodecError;

fn encode(&mut self, data: Self::Item, buf: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, data: Self::Item<'_>, buf: &mut BytesMut) -> Result<(), Self::Error> {
// Encode json
let j = serde_json::to_string(&data)?;

Expand Down
8 changes: 4 additions & 4 deletions src/codec/length.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ const U64_LENGTH: usize = std::mem::size_of::<u64>();
/// pub struct MyStringCodec(LengthCodec);
///
/// impl Encoder for MyStringCodec {
/// type Item = String;
/// type Item<'a> = String;
/// type Error = Error;
///
/// fn encode(&mut self, src: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
/// fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
/// let bytes = Bytes::from(src);
/// self.0.encode(bytes, dst)
/// }
Expand All @@ -47,10 +47,10 @@ const U64_LENGTH: usize = std::mem::size_of::<u64>();
pub struct LengthCodec;

impl Encoder for LengthCodec {
type Item = Bytes;
type Item<'a> = Bytes;
type Error = Error;

fn encode(&mut self, src: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, src: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.reserve(U64_LENGTH + src.len());
dst.put_u64(src.len() as u64);
dst.extend_from_slice(&src);
Expand Down
4 changes: 2 additions & 2 deletions src/codec/lines.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ use std::io::{Error, ErrorKind};
pub struct LinesCodec;

impl Encoder for LinesCodec {
type Item = String;
type Item<'a> = String;
type Error = Error;

fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.reserve(item.len());
dst.put(item.as_bytes());
Ok(())
Expand Down
39 changes: 35 additions & 4 deletions src/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,50 @@ use std::io::Error;
/// Encoding of messages as bytes, for use with `FramedWrite`.
pub trait Encoder {
/// The type of items consumed by `encode`
type Item;
type Item<'a>;
/// The type of encoding errors.
type Error: From<Error>;

/// Encodes an item into the `BytesMut` provided by dst.
fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error>;
fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error>;
}

impl<T, U: Encoder> Encoder for Fuse<T, U> {
type Item = U::Item;
type Item<'a> = U::Item<'a>;
type Error = U::Error;

fn encode(&mut self, item: Self::Item, dst: &mut BytesMut) -> Result<(), Self::Error> {
fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
self.u.encode(item, dst)
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::FramedWrite;
use futures::executor::block_on;
use futures_util::SinkExt;

#[test]
fn can_use_borrowed_data() {
let mut buf = Vec::new();

let mut write = FramedWrite::new(&mut buf, BorrowedCodec);
block_on(write.send(&[1, 2, 3, 4])).unwrap();

assert_eq!(buf, vec![1, 2, 3, 4])
}

struct BorrowedCodec;

impl Encoder for BorrowedCodec {
type Item<'a> = &'a [u8];
type Error = Error;

fn encode(&mut self, item: Self::Item<'_>, dst: &mut BytesMut) -> Result<(), Self::Error> {
dst.extend_from_slice(item);

Ok(())
}
}
}
4 changes: 2 additions & 2 deletions src/framed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
}
}

impl<T, U> Sink<U::Item> for Framed<T, U>
impl<T, U> Sink<U::Item<'_>> for Framed<T, U>
where
T: AsyncWrite + Unpin,
U: Encoder,
Expand All @@ -173,7 +173,7 @@
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.project().inner.poll_ready(cx)
}
fn start_send(self: Pin<&mut Self>, item: U::Item) -> Result<(), Self::Error> {
fn start_send(self: Pin<&mut Self>, item: U::Item<'_>) -> Result<(), Self::Error> {
self.project().inner.start_send(item)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Expand All @@ -185,7 +185,7 @@
}

/// The parts obtained from [`Framed::into_parts`].
pub struct FramedParts<T, U> {

Check failure on line 188 in src/framed.rs

View workflow job for this annotation

GitHub Actions / Clippy

this seems like a manual implementation of the non-exhaustive pattern

Check failure on line 188 in src/framed.rs

View workflow job for this annotation

GitHub Actions / Clippy

this seems like a manual implementation of the non-exhaustive pattern
/// The underlying I/O stream.
pub io: T,
/// The codec used for encoding and decoding frames.
Expand Down
8 changes: 4 additions & 4 deletions src/framed_write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@
}
}

impl<T, E> Sink<E::Item> for FramedWrite<T, E>
impl<T, E> Sink<E::Item<'_>> for FramedWrite<T, E>
where
T: AsyncWrite + Unpin,
E: Encoder,
Expand All @@ -150,7 +150,7 @@
fn poll_ready(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.project().inner.poll_ready(cx)
}
fn start_send(self: Pin<&mut Self>, item: E::Item) -> Result<(), Self::Error> {
fn start_send(self: Pin<&mut Self>, item: E::Item<'_>) -> Result<(), Self::Error> {
self.project().inner.start_send(item)
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
Expand Down Expand Up @@ -221,7 +221,7 @@
}
}

impl<T> Sink<T::Item> for FramedWrite2<T>
impl<T> Sink<T::Item<'_>> for FramedWrite2<T>
where
T: AsyncWrite + Encoder + Unpin,
{
Expand All @@ -241,7 +241,7 @@

Poll::Ready(Ok(()))
}
fn start_send(mut self: Pin<&mut Self>, item: T::Item) -> Result<(), Self::Error> {
fn start_send(mut self: Pin<&mut Self>, item: T::Item<'_>) -> Result<(), Self::Error> {
let this = &mut *self;
this.inner.encode(item, &mut this.buffer)
}
Expand All @@ -249,7 +249,7 @@
let mut this = self.project();

while !this.buffer.is_empty() {
let num_write = ready!(Pin::new(&mut this.inner).poll_write(cx, &this.buffer))?;

Check failure on line 252 in src/framed_write.rs

View workflow job for this annotation

GitHub Actions / Clippy

this expression creates a reference which is immediately dereferenced by the compiler

Check failure on line 252 in src/framed_write.rs

View workflow job for this annotation

GitHub Actions / Clippy

this expression creates a reference which is immediately dereferenced by the compiler

if num_write == 0 {
return Poll::Ready(Err(err_eof().into()));
Expand Down Expand Up @@ -277,7 +277,7 @@
}

/// The parts obtained from [`FramedWrite::into_parts`].
pub struct FramedWriteParts<T, E> {

Check failure on line 280 in src/framed_write.rs

View workflow job for this annotation

GitHub Actions / Clippy

this seems like a manual implementation of the non-exhaustive pattern

Check failure on line 280 in src/framed_write.rs

View workflow job for this annotation

GitHub Actions / Clippy

this seems like a manual implementation of the non-exhaustive pattern
/// The underlying I/O stream.
pub io: T,
/// The frame encoder.
Expand Down