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

Implement Decode, Encode and Type for Box, Arc, Cow and Rc #3674

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

joeydewaal
Copy link
Contributor

fixes #3100

Implements Decode, Encode and Type for Box<T>, Arc<T>, Cow<'_,T> and Rc<T>. I left out the Decode impl for Rc<T> because of the Send trait bounds in QueryAs and QueryScalar (which makes it impossible to use Rc).

@joeydewaal joeydewaal changed the title Encode decode Implement Decode, Encode and Type for Box, Arc, Cow and Rc Jan 9, 2025
@abonander
Copy link
Collaborator

I left out the Decode impl for Rc<T> because of the Send trait bounds in QueryAs and QueryScalar (which makes it impossible to use Rc).

@joeydewaal technically it's still possible to use by getting the Row and then calling get(). Someone's gonna end up asking why it doesn't exist, and justifying that would be more work than just carrying the impl.

We can relax the Send bound on QueryAs/QueryScalar in the future when we get rid of BoxStream in the fetch() method:

) -> BoxStream<'e, Result<Either<DB::QueryResult, O>, Error>>

Copy link
Collaborator

@abonander abonander left a comment

Choose a reason for hiding this comment

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

Previous comment.

@joeydewaal
Copy link
Contributor Author

Makes sense, I added the impl for Rc

@abonander
Copy link
Collaborator

CI should be fixed if you rebase.

@joeydewaal joeydewaal force-pushed the encode-decode branch 7 times, most recently from 0480f29 to ff041d6 Compare March 12, 2025 12:30
@joeydewaal joeydewaal requested a review from abonander March 19, 2025 13:02
Comment on lines +138 to +158
impl<'r, DB> Decode<'r, DB> for Cow<'r, str>
where
DB: Database,
&'r str: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let borrowed = <&str as Decode<DB>>::decode(value)?;
Ok(Cow::Borrowed(borrowed))
}
}

impl<'r, DB> Decode<'r, DB> for Cow<'r, [u8]>
where
DB: Database,
&'r [u8]: Decode<'r, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'r>) -> Result<Self, BoxDynError> {
let borrowed = <&[u8] as Decode<DB>>::decode(value)?;
Ok(Cow::Borrowed(borrowed))
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

These impls aren't really going to be practical to use. Consider the most common usage; there is basically never a row retained that can be borrowed from. query_as(), query_scalar() and all the macro variants throw away the row value after deserializing. #[derive(FromRow)] doesn't support borrowed values.

Manual calls to Row::get() would work, but that's about it. I think that's gonna confuse people more than anything. Arguably, we could get rid of the lifetime on FromRow entirely and only support deserializing from an owned row. It's more of an "it's there if you really wanna use it" kind of thing.

I think we could support both borrowed and owned data in the future with specialization, but it's not really feasible in the language currently.

I think for similar reasons, Serde only supports deserializing Cow::Owned despite having better support for deserializing from borrowed data overall.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At first I only implemented Decode for Cow::Owned but I switched to Cow::Borrowed because the current impls also use Cow::Borrowed and changing this would be a breaking change (I think?).

Comment on lines +177 to +178
T: Encode<'q, DB>,
T: ToOwned,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
T: Encode<'q, DB>,
T: ToOwned,
T: Encode<'q, DB> + ToOwned,

Copy link
Collaborator

Choose a reason for hiding this comment

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

This could possibly use a comment about how ToOwned is only required to satisfy Cow.

Comment on lines +175 to +177
impl<'q, T, DB: Database> Encode<'q, DB> for Cow<'_, T>
where
T: Encode<'q, DB>,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This might get weird with non-'static lifetimes. I would test that it's actually possible to bind with borrowed data.

Comment on lines +271 to +273
T: Type<DB>,
T: ToOwned,
T: ?Sized,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Weird way to style this. The requirements for a given type parameter should be grouped together.

Suggested change
T: Type<DB>,
T: ToOwned,
T: ?Sized,
T: Type<DB> + ToOwned + ?Sized,

Comment on lines +251 to +252
T: Type<DB>,
T: ?Sized,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
T: Type<DB>,
T: ?Sized,
T: Type<DB> + ?Sized,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

impl Decode, Encode and Type for smart pointer types like Cow
2 participants