Wrapping a private Cow

One thing I struggle with quite often is creating my own owned wrappers around various (near) zero-copy crates (essentially to hide impl details).

Something along the lines of:

// 3rd party crate with private fields
pub struct Foo<'a> {
    bar: Cow<'a, [u8]>, // non-pub
}
// my code
struct FooWrapper {
    foo: Foo, // <-- need to specify lifetime
}

Is there a way of somehow taking the ownership of Foo instance in FooWrapper?

Given that you don't control Foo, no. Your only option is to do the conversion by hand, at which point you don't have a Foo.

You could hold a Foo<'static>, but that limits you to data that's either owned or borrowed at compile time. The third-party crate might not give you much choice there though.

1 Like

You have not described exactly what library/type you're using so it's hard to say. But you can potentially do this with yoke if the library provides a compatible interface, e.g.

// your_library.rs
pub struct Foo<'a>;

impl<'a> Foo<'a>
{
  // you need a function which looks like this to use this type with yoke:
  // - 'a must be totally unconstrained;
  // - there must be some other type which owns its data from which you can borrow a `v'
  pub fn borrow_foo_from_somewhere(v : &'a [u8]) -> Self;
}

// main.rs
use yoke::*;
use yoke_derive::*;

// unfortunatly you need this due to orphan trait impl rules (you must implement Yokeable)
#[derive(Yokeable)]
struct MyFoo<'a>(Foo<'a>);

struct FooWrapper
{
  foo: Yoke<MyFoo<'static>, Vec<u8>>
}

impl FooWrapper
{
  fn new(v : Vec<u8>) -> Self
  {
    FooWrapper { foo: Yoke::attach_to_cart(v, |v| MyFoo(Foo::borrow_foo_from_somewhere(v)) ) }
  }

  fn get_foo_ref(&self) -> &Foo
  {
    &self.foo.get().0
  }
}
1 Like

Does this work?

struct FooWrapper<'a> {
    foo: Foo<'a>,
}
1 Like

You can't hide the fact that something is temporarily borrowed.

Making that a "clean" interface without lifetimes would be unsafe per Rust's rules. You will have virally spreading lifetime annotations infecting everything that tries to hold a temporary reference.

2 Likes

Thanks everyone!

I keep coming across the same problem every now and then, so it isn't really specific to a single library. Usually it's plain old self-referential structures (owned buffer and zero-copy parser stored in the same struct, either for caching or for encapsulating/hiding impl details) but in this case I wasn't sure if Cow changes anything.

I have been away from Rust for almost 2 years and I remember there wasn't any good approach for self-referential structs (I seem to remember transmuting lifetimes to 'static) and I was hoping that something acceptable would pop up in the meantime.

Yoke seems to have answered my question, it compiles and runs, although I can't claim I understand the side-effects and see potential problems it might've introduced. :sweat_smile:

My go-to solution for self-referential structs is the ouroboros crate.

1 Like

Totally off topic: Title reads funny out of context.

4 Likes

Thank you, looks good! I'll need to brush up my understanding of covariance but I re-wrote my struct from yoke to ouroboros as a test and it seems like a bit cleaner approach.

Both @yuriy0's yoke and @Michael-F-Bryan's ouroboros suggestions provide a good solution for creating self-referential structs.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.