Expand description
RentToOwn<T>: A wrapper type for optionally giving up ownership of the
underlying value.
RentToOwn<T> is useful in situations where
-
a function might want to conditionally take ownership of some
Tvalue, and -
that function cannot take the
Tby value and return anOption<T>to maybe give theTvalue back if it doesn’t want ownership.
RentToOwn<T> dereferences (immutably and mutably) to its inner T value, and
additionally provides a take method that gives up ownership of the inner value
to the caller.
Under the covers, RentToOwn<T> is essentially an Option<T> that gets
unwrapped when dereferenced and calls Option::take if we need to take
ownership of the inner value. The key advantage over using Option<T> directly,
other than the Deref sugar, is some lifetime trickery to statically prevent
all unwrapping panics that would arise from using the RentToOwn<T> wrapper
again after the inner value has been taken. Once the inner value is taken, the
borrow checker will ensure that the original RentToOwn<T> cannot be used
anymore. See the take method’s documentation for details.
§Example
In this example, if the configure function encounters any errors, we do not
wish to drop the BigExpensiveResource, but instead allow the caller to handle
the error and then reuse the resource. In effect, the configure function is
conditionally taking ownership of the BigExpensiveResource depending on if
there are IO errors or not.
use rent_to_own::RentToOwn;
use std::io::{self, Read};
use std::fs;
/// This is a big, expensive to create (or maybe even unique) resource, and we
/// want to reuse it even if `configure` returns an error.
struct BigExpensiveResource {
// ...
}
#[derive(Default)]
struct Config {
// ...
}
/// A big, expensive resource that has been properly configured.
struct ConfiguredResource {
resource: BigExpensiveResource,
config: Config,
}
fn read_and_parse_config_file() -> io::Result<Config> {
// ...
}
fn configure<'a>(
resource: &'a mut RentToOwn<'a, BigExpensiveResource>
) -> io::Result<ConfiguredResource> {
// We use normal error propagation with `?`. Because we haven't `take`n the
// resource out of the `RentToOwn`, if we early return here the caller still
// controls the `BigExpensiveResource` and it isn't dropped.
let config = read_and_parse_config_file()?;
// Now we `take` ownership of the resource and return the configured
// resource.
let resource = resource.take();
Ok(ConfiguredResource { resource, config })
}What does configure’s caller look like? It calls RentToOwn::with to
construct the RentToOwn<BigExpensiveResource> and invoke a closure with
it. Then it inspects the results of the closure and whether the
BigExpensiveResource was taken or not.
In this example, the caller can recover from any IO error when reading or
parsing the configuration file and use a default configuration with the
BigExpensiveResource instead.
fn use_custom_configuration_or_default(resource: BigExpensiveResource) -> ConfiguredResource {
// We pass the resource into `with` and it constructs the `RentToOwn`
// wrapper around it and then gives the wrapper to the closure. Finally, it
// returns a pair of an `Option<BigExpensiveResource>` which is `Some` if
// the closure took ownership and `None` if it did not, and the closure's
// return value.
let (resource, result) = RentToOwn::with(resource, |resource| {
configure(resource)
});
if let Ok(configured) = result {
return configured;
}
// Reuse the resource if the closure did not take ownership or else
// reconstruct it if the closure did take ownership. (In this particular
// example, we know that `configure` took ownership if and only if the
// result was `Ok`, but that doesn't hold for all possible examples.)
// Finally, return the configured resource with the default configuration.
let resource = resource.unwrap_or_else(|| BigExpensiveResource::reconstruct());
let config = Config::default();
ConfiguredResource { resource, config }
}Structs§
- Rent
ToOwn - A wrapper around a
Tthat allows users to conditionally take ownership of the innerTvalue, or simply use it like a&mut Treference.

