# Possible Rust library providing a three state enum for differentiating between an explicit null value and the absense of a value. This is intended to be used with `serde` serialization and deserialization to address an ambiguity between null values and the absense of a value where `Option` comflates the two. `Possible` is an enumerator over three possibilities `Some(T)`, `None`, and `Void`. The intended use is that `Some(T)` is used for storing some data like with an `Option`; `None` represents explicitly null values; and `Void` represents the absense of any value. `Possible` implements most of the same functionality as `Option`, and can often be used as a direct replacement. Even though there is disambiguation between `None` and `Void`, they will tend to be treated in the same way for most `Option` functionality to behave in an expected way. ## Installation With [cargo-edit](https://crates.io/crates/cargo-edit), run the following to add this library to your project. ```sh cargo add possible ``` Otherwise add the following to the `Cargo.toml` file of your project under the `[dependencies]` table section. ```toml # Under [dependencies] possible = "0.1.0" ``` ## Usage In it's most simple case, `Possible` can be used in similar ways to `Option`. ```rust use possible::Possible; let possible_value: Possible = Possible::Some(42); assert_eq!(possible_value, Possible::Some(42)); if let Possible::Some(value) = possible_value { assert_eq!(value, 42); } let halved_possible_value = possible_value.map(|value| value / 2); assert_eq!(halved_possible_value, Possible::Some(21)); let unwrapped_value = possible_value.unwrap(); assert_eq!(unwrapped_value, 42); ``` Matching can be done similarly to `Option` type variants. ```rust use possible::Possible; let possible_value: Possible = Default::default(); // defaults to Possible::Void if let Possible::Void = possible_value { // semantically means there is an absense of any value stored } match possible_value { Possible::Void => { /* the default variant implying no value */ } Possible::None => { /* like Option::None, a null or empty value */ } Possible::Some(value) => { /* like Option::Some, a value of some type */ } } assert_eq!(possible_value.is_void(), true); assert_eq!(possible_value.is_none(), false); assert_eq!(possible_value.is_some(), false); ``` The primary use case for this library is paired with `serde` serialization and deserialization from formats like JSON. This is useful when the a null value (or `None`) is a valid value yet the absence of a value is still significant to capture. ```rust use serde::Serialize; use serde_json::json; use possible::Possible; // serde(skip_serializing_if = "Possible::is_void") is required to implicitly // omit values that are set as Possible::Void from being serialized #[derive(Debug, Serialize, PartialEq)] pub struct OutputJsonData { id: i64, #[serde(skip_serializing_if = "Possible::is_void")] name: Possible, #[serde(skip_serializing_if = "Possible::is_void")] enabled: Possible, } let intended_output = OutputJsonData { id: 1324, name: Possible::Void, enabled: Possible::Some(true), }; let serialized = serde_json::to_string(&intended_output).unwrap(); assert_eq!(serialized, r#"{"id":1324,"enabled":true}"#); ``` ```rust use serde::Deserialize; use possible::Possible; let input = r#"{ "id": 1324, "name": "Ferris" }"#; // serde(default) is required to implicitly parse // missing values as Possible::Void instead of Possible::None #[derive(Debug, Deserialize, PartialEq)] pub struct InputJsonData { id: i64, #[serde(default)] name: Possible, #[serde(default)] enabled: Possible, } let parsed_input: InputJsonData = serde_json::from_str(input).unwrap(); assert_eq!(parsed_input, InputJsonData { id: 1324, name: Possible::Some( String::from("Ferris") ), enabled: Possible::Void, }); ``` ## Contributing Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate. ## License [MIT](https://choosealicense.com/licenses/mit/) or [Apache 2](https://choosealicense.com/licenses/apache-2.0/)