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

impl Decode, Encode and Type for smart pointer types like Cow #3100

Open
JoHaHu opened this issue Mar 7, 2024 · 0 comments · May be fixed by #3102
Open

impl Decode, Encode and Type for smart pointer types like Cow #3100

JoHaHu opened this issue Mar 7, 2024 · 0 comments · May be fixed by #3102
Labels
enhancement New feature or request

Comments

@JoHaHu
Copy link

JoHaHu commented Mar 7, 2024

Currently this code doesn't work since Decode isn't implemented for Cow<T> but for Cow<str>.

This leads to the problem that I have to implement two different structs for the types if I don't want to clone the fields for every query (one using owned types to retrieve data and one using references to bind in query).
Cow<T> can be used in this case to allow treating a field like a pointer or like a owned value as needed.
The same is true for other smart pointer types like Arc and Rc.

#[derive(sqlx::FromRow, Clone)]
pub(super) struct A<'a> {
  pub(super) content: Cow<'a, MaybeBig>, 
  ...
}

Describe the solution you'd like

impl<DB, T> Type<DB> for Cow<'_, T>
where
  T: Type<DB>,
  DB: Database,
{
  fn type_info() -> DB::TypeInfo {
    T::type_info()
  }

  fn compatible(ty: &DB::TypeInfo) -> bool {
    T::compatible(ty)
  }
}

// Maybe this is unnecessary since smart pointers implement Deref for T
impl<'q, DB, T> Encode<'q, DB> for Cow<'q, T>
where
  T: Encode<'q, DB>,
  DB: Database,
{
 //  encode() omitted since it requires an additional ToOwned<Owned=T> bound on T 

  fn encode_by_ref(&self, buf: &mut <DB as HasArguments<'q>>::ArgumentBuffer) -> IsNull {
    T::encode_by_ref(self, buf)
  }

  fn produces(&self) -> Option<DB::TypeInfo> {
    T::produces(self)
  }

  fn size_hint(&self) -> usize {
    T::size_hint(self)
  }
}

impl<'r, DB, T> Decode<'r, DB> for Cow<'static, T>
where
  T: Decode<'r, DB> + ToOwned<Owned = T>,
  DB: Database,
{
  fn decode(value: <DB as HasValueRef<'r>>::ValueRef) -> Result<Self, BoxDynError> {
    T::decode(value).map(|t| t.to_owned()).map(Cow::Owned)
  }
}

Describe alternatives you've considered
I've considered using a extension trait for a short time, but couldn't get it done, because of dyn object safety.
And i believe this should be part of the library.

Another alternative is to have two different structs. One for querying (uses references) and one for retrieving (uses owned Types)

Create a wrapper around Cow from standard library that delegates to the inner and implement the trait on this wrapper.

If this seems useful to you I would like to start working on a PR for this.


This is related to #1904

@JoHaHu JoHaHu added the enhancement New feature or request label Mar 7, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant