# orx-pseudo-default

[![orx-pseudo-default crate](https://img.shields.io/crates/v/orx-pseudo-default.svg)](https://crates.io/crates/orx-pseudo-default)
[![orx-pseudo-default crate](https://img.shields.io/crates/d/orx-pseudo-default.svg)](https://crates.io/crates/orx-pseudo-default)
[![orx-pseudo-default documentation](https://docs.rs/orx-pseudo-default/badge.svg)](https://docs.rs/orx-pseudo-default)

`PseudoDefault` trait allows to create a cheap default instance of a type, which **does not claim to be useful**.

The difference of `PseudoDefault` from `Default` is the relaxed expectation of the created instance to be useful.

The main use case of the trait is when we need to create a cheap instance of a type without any arguments, only to throw away afterwards. Therefore, created instance does not need to be a decent one.

This trait allows to avoid unsafe code in certain use cases. For instance:
* We can avoid tricks such as uninit, manually-drop, etc. that requires to be extremely careful, when we could've actually created a valid instance much more easily.
* We can use pseudo-default to fill the gaps when we need to take out an element from a collection of types that cannot implement Default.

Note that pseudo-default requirement is more relaxed than that of default, and hence,
* types implementing Default can implement PseudoDefault,
* additionally, types that cannot implement Default can manually implement PseudoDefault, provided that it is safe and cheap to create a pseudo instance of the type without any arguments.

> **no-std**: This crate supports **no-std**; however, *std* is added as a default feature together with *derive*. Please include with **no-default-features** for no-std use cases: `cargo add orx-pseudo-default --no-default-features`.

# Example

Consider the following fictional type `Share` which divides a whole into pieces. Without providing the `number_of_shares`, this type does not have a meaning.

**Therefore, we cannot justify implementing `Default`, it would be misleading.**

If we still need to be able to create Share's for some reason, we can simply use `pseudo_default`. We would know that the created type does not promise to make sense behaviorally; however, it is still a cheap and valid instance that can be safely dropped.

```rust
use orx_pseudo_default::PseudoDefault;

struct Share {
    number_of_shares: std::num::NonZeroUsize,
}

impl Share {
    fn share_size(&self, whole_amount: usize) -> usize {
        whole_amount / self.number_of_shares
    }
}

impl PseudoDefault for Share {
    fn pseudo_default() -> Self {
        Self {
            number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
        }
    }
}
```

A more advanced use case could be the following. Assume that we are trying to create a vec wrapper called `TakeVec` with the following features;
* it allows to take out elements by index by a method called `take`
* we should be able to wrap an allocated vec without any additional allocation
* we need to be able to give back the originally allocated vec
* we want to achieve this without unsafe code

It is trivial to implement this with `Default` but we want to be less restrictive on the constraint so that it works for non-default types as well. We can use PseudoDefault for this.

```rust
use orx_pseudo_default::PseudoDefault;

struct TakeVec<T>(Vec<T>);

impl<T> From<Vec<T>> for TakeVec<T> {
    fn from(inner: Vec<T>) -> Self {
        Self(inner)
    }
}

impl<T> From<TakeVec<T>> for Vec<T> {
    fn from(value: TakeVec<T>) -> Self {
        value.0
    }
}

impl<T: PseudoDefault> TakeVec<T> {
    fn take(&mut self, index: usize) -> Option<T> {
        self.0.get_mut(index).map(|element| {
            let mut value = T::pseudo_default();
            std::mem::swap(&mut value, element);
            value
        })
    }
}

// implemented default types

let mut vec: TakeVec<_> = vec![0, 1, 2, 3].into();
assert_eq!(vec.take(2), Some(2));

let mut vec: TakeVec<_> = vec![0.to_string(), 1.to_string()].into();
assert_eq!(vec.take(0), Some(String::from("0")));

// non-default types

struct Share {
    number_of_shares: std::num::NonZeroUsize,
}

impl PseudoDefault for Share {
    fn pseudo_default() -> Self {
        Self {
            number_of_shares: std::num::NonZeroUsize::new(1).unwrap(),
        }
    }
}

let mut vec: TakeVec<_> = vec![
    Share {
        number_of_shares: std::num::NonZeroUsize::new(42).unwrap(),
    },
    Share {
        number_of_shares: std::num::NonZeroUsize::new(7).unwrap(),
    },
]
.into();
assert_eq!(vec.take(0).map(|x| x.number_of_shares.into()), Some(42));
```

### Derive

Similar to `Default`, it is possible to derive `PseudoDefault` provided that all members also implement `PseudoDefault`.

```rust
use orx_pseudo_default::*;

#[derive(PseudoDefault)]
struct ChildStruct {
    a: String,
    b: char,
    c: Vec<u32>,
}

#[derive(PseudoDefault)]
struct MyStruct {
    x: ChildStruct,
    y: bool,
    z: Option<usize>,
}

assert_eq!(String::pseudo_default(), MyStruct::pseudo_default().x.a);
assert_eq!(char::pseudo_default(), MyStruct::pseudo_default().x.b);
assert_eq!(Vec::<u32>::pseudo_default(), MyStruct::pseudo_default().x.c);
assert_eq!(bool::pseudo_default(), MyStruct::pseudo_default().y);
assert_eq!(
    Option::<usize>::pseudo_default(),
    MyStruct::pseudo_default().z
);
```

## Contributing

Contributions are welcome! If you notice an error, have a question or think something could be improved, please open an [issue](https://github.com/orxfun/orx-pseudo-default/issues/new) or create a PR.

## License

Dual-licensed under [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT).
