rent_to_own 0.1.0

A wrapper type for optionally giving up ownership of the underlying value.
Documentation
# rent_to_own

[![](https://docs.rs/rent_to_own/badge.svg)](https://docs.rs/rent_to_own/) [![](https://img.shields.io/crates/v/rent_to_own.svg)](https://crates.io/crates/rent_to_own) [![](https://img.shields.io/crates/d/rent_to_own.png)](https://crates.io/crates/rent_to_own) [![Build Status](https://travis-ci.org/fitzgen/rent_to_own.png?branch=master)](https://travis-ci.org/fitzgen/rent_to_own)

`RentToOwn<T>`: A wrapper type for optionally giving up ownership of the
underlying value.

`RentToOwn<T>` is useful in situations where

1. a function might want to *conditionally take ownership* of some `T`
value, and

2. that function cannot take the `T` by value and return an `Option<T>` to maybe
give the `T` value 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.

```rust
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.

```rust
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 }
}
```


License: Apache-2.0/MIT