optionable 0.1.13

Derive macro (and associated marker trait) to derive nested structs/enums with all subfields being optional (e.g. for patches or Kubernetes server side apply).
Documentation
# optionable
 
A rust library to derive `optioned` structs/enums versions of existing types where all fields have been recursively replaced
with versions that support setting just a subset of the relevant fields (or none at all).

One motivation for this concept is the common problem when expressing patches e.g. for [Kubernetes apply configurations](https://pkg.go.dev/k8s.io/client-go/applyconfigurations)
that for a given rust struct `T` a corresponding struct `T::Optioned` would be required where all fields are recursively optional
to specify.

While trivial to write for plain structures this quickly becomes tedious for nested structs/enums.

#### Links
- [crates.io]https://crates.io/crates/optionable
- [rust documentation]https://docs.rs/optionable/

## Deriving optional structs/enums

The core utility of this library is to provide an `Optionable`-derive macro that derives such an optioned type
and implements the corresponding `Optionable`-trait (see below for details).
It supports nested structures, enums as well as various container types.

For detailed configuration options via helper attributes, see the [`Optionable`-derive macro docs](https://docs.rs/optionable/latest/optionable/derive.Optionable.html).

The general logic is the same as for other rust derives. If you want to use the derive `Optionable` for a struct/enum
every type used for a field needs to also have implemented the corresponding `Optionable` trait:
```rust
#[derive(Optionable)]
#[optionable(derive(Default,Serialize,Deserialize))]
struct Address {
    street_name: String,
    number: u8,
}

fn example(){
    let _ = AddressOpt{
        street_name: Some("a".to_owned()),
        // fill the other fields with `None`
        ..Default::default()
    };
}
```

The generated optioned type is (shown here with resolved associated types) as follows:
```rust
#[derive(Default,Serialize,Deserialize)]
struct AddressOpt {
    street_name: Option<String>,
    number: Option<u8>,
}
```

### Enum support
Deriving optioned versions also works with enums:
```rust
#[derive(Optionable)]
enum AddressEnum {
     Plain(String),
     AddressExplicit { street: String, number: u32 },
     AddressNested(Address)
}

fn example(){
    let _ = AddressEnumOpt::AddressExplicit{
        street: Some("a".to_owned()),
        number: None 
    };
}
```

## Core concept
The main `Optionable` trait is quite simple:
```rust
pub trait Optionable {
    type Optioned;
}
```
It is a marker trait that allows to express for a given type `T` which type should be considered its `T::Optioned` type
such that `Option<T::Optioned>` would represent all variants of partial completeness.
For types without inner structure this means that the `Optioned` type will just resolve to the type itself, e.g.
```rust
impl Optionable for String {
    type Optioned = String;
}
```
For many primitive types as well as common wrapper or collection types the `Optionable`-trait is already implemented.

### Conversion
Per default also conversion traits for struct/enums with sized fields will be generated.
The relevant traits are (shown here without comments and `where` clauses):
```rust
pub trait OptionableConvert: Sized + Optionable {
    fn into_optioned(self) -> Self::Optioned;
    fn try_from_optioned(value: Self::Optioned) -> Result<Self, Error>;
    fn merge(&mut self, other: Self::Optioned) -> Result<(), Error>;
}

// auto-implemented from `OptionableConvert`
pub trait OptionedConvert<T>: Sized + Sealed<T>
{
    fn from_optionable(value: T) -> Self;
    fn try_into_optionable(self) -> Result<T, Error>;
}
```

## Crate features
- `derive`: Default-feature, re-exports the `Optionable` derive macro.
- `chrono`: Derive `Optionable` for types from [chrono]https://docs.rs/chrono/latest/chrono/
- `serde_json`: Derive `Optionable` for [serde_json]https://docs.rs/serde_json/latest/serde_json/::Value

## Limitations

### External types
Due to the orphan rule the usage of the library becomes cumbersome if one has a use case which heavily relies on crate-external types.
For well-established libraries adding corresponding `impl` to this crate (feature-gated) would be a worthwhile approach.

### IDE: Resolving associated types
Due to the use of associated types some IDE-hints do not fully resolve the associated types leaving you with
`<i32 as Optionable>::Optioned` instead of `i32`. Luckily, for checking type correctness and also for error messages
when using wrong types the associated types are resolved.

## Similar crates
One crate with similar scope is [optional_struct](https://crates.io/crates/optional_struct).
It focuses specifically on structs (not enums) and offers a more manual approach, especially in respect to nested sub-struct,
providing many fine-grained configuration options.

Another crate is [struct-patch](https://github.com/yanganto/struct-patch/).
It focuses on patching structs (not enums), especially from serde inputs. Nesting is supported with manual helper annotations.

### License
You can use this under the conditions of the [MIT license](LICENSE-MIT) or the [Apache License, Version 2.0](LICENSE-APACHE) at your option.

#### Contributing
Any contributor has to agree to have their contribution also dual-licensed under the MIT as well as Apache-2.0 license as
specified above in the `License` subsection.