Skip to content
/ ov-rs Public

a collection of traits that allow you to chain off of anything

Notifications You must be signed in to change notification settings

brigand/ov-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 

Repository files navigation

ov

The 'ov' crate provides a collection of traits that allow you to chain off of anything. Each trait has a single method with the same name as the trait (but in snake case).

Over, OverRef, and OverMut are each of self, &self, and &mut self, and the callback receives that same value. They are implemented for all types.

OverDeref and OverDerefMut are implemented for types which have Deref and DerefMut implementations. They both borrow the receiver, and pass a reference of the Deref::target to the callback.

Usage

You may either wildcard import it, or import specific traits. New items will not be added in semver compatible versions.

use ov::*;

or

use ov::Over;

Examples

A common use for this is with unary enum or struct constructors. These would otherwise be multiple statements with variables, or nested parenthesis.

use ov::*;
use std::error::Error;
use std::io::{Error as IoError, ErrorKind};

fn maybe_string() -> Option<String> {
    "foo".to_owned().over(Some)
}
assert_eq!(maybe_string(), Some("foo".to_owned()));

// A helper is needed as `.over(Box::new)` always creates a Box<IoError>
fn to_err_object(error: impl Error + Send + 'static) -> Box<dyn Error + Send> {
    Box::new(error)
}

fn try_io_thing() -> Result<(), Box<dyn Error + Send>> {
    IoError::new(ErrorKind::Other, "oh no!").over(to_err_object).over(Err)
}

The .over_mut method can be used to perform some mutations on an arbitrary value, including a field of a struct.

use ov::*;
struct S { field: i32 }
let mut s = S { field: 5 };

s.field.over_mut(|n| {
    // n is &mut i32
    *n *= 3;
    *n += 1;
});
assert_eq!(s.field, 16);

The over_deref and over_deref_mut methods can be useful if you want to use a function that takes e.g. &str and you have a String.

let s = String::from("Hello, world!");
// Note: this would fail if `my_str` were `String` or `&String`
let len = s.over_deref(|my_str| str::len(my_str));
// Can be shortened to this
let len = s.over_deref(str::len);
assert_eq!(len, 13);

Another case for this is extracting the value from a mutable reference. For this, we can use std::mem::take or std::mem::replace. In the following example we have to use replace because Command doesn't impl Default.

use std::process::Command;
fn assert_type<T>(_x: T) {}

let command = Command::new("ls")
    .arg("-a") // returns &mut Command
    .arg("-l") // returns &mut Command
    .over(|r| std::mem::replace(r, Command::new(""))); // returns Command

assert_type::<Command>(command);

License: MIT

About

a collection of traits that allow you to chain off of anything

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages