If I have the following struct
#[derive(Clone, Debug, Deserialize)]
struct Foo<'a> {
#[serde(borrow)]
pub bar: Cow<'a, str>,
}
I can read it from a file like this:
let file = File::open("some.json").unwrap();
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer).unwrap();
let foo: Foo = serde_json::from_slice(&buffer).unwrap();
assert!(matches!(foo.bar, Cow::Borrowed(_)));
println!("from file {:?}", foo);
In this case bar
will be borrowed. However, if I want to move all that code into a dedicated function it no longer works:
fn from_file<'a>() -> Foo<'a> {
let file = File::open("some.json").unwrap();
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer).unwrap();
let foo: Foo = serde_json::from_slice(&buffer).unwrap();
assert!(matches!(foo.bar, Cow::Borrowed(_)));
foo
}
This won't compile, because of course it won't, data in bar
is not owned by foo
, but by buffer
. In these cases I won't mind if bar
is actually owned, so doing this works:
fn from_file<'a>() -> Foo<'a> {
let file = File::open("some.json").unwrap();
let mut reader = BufReader::new(file);
let mut buffer = Vec::new();
reader.read_to_end(&mut buffer).unwrap();
let foo: Foo = serde_json::from_slice(&buffer).unwrap();
assert!(matches!(foo.bar, Cow::Borrowed(_)));
let foo = Foo { bar: foo.bar.to_string().into() };
assert!(matches!(foo.bar, Cow::Owned(_)));
foo
}
However, if I want to have a function to do this it no longer works:
impl Foo<'_> {
pub fn to_owned(self) -> Self {
let foo = Self { bar: self.bar.to_string().into() };
assert!(matches!(foo.bar, Cow::Owned(_)));
foo
}
}
The problem being:
30 | let foo: Foo = serde_json::from_slice(&buffer).unwrap();
| ------- `buffer` is borrowed here
...
36 | foo.to_owned()
| ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function
What am I missing here? How can I tell the compiler that I'm no longer referencing buffer
?