Documentation
use core::ops::Deref;

/// A wrapper that provides read-only access to a value
///
/// <div class="warning">
///
/// This type is meant to prevent accidental modifications of values after construction.
/// It can not however, prevent *replacement* of the value itself. For example:
///
/// ```
/// use cut::Immutable;
///
/// let mut val = Immutable::new(10);
///
/// // later...
/// val = Immutable::new(11);
///
/// assert_eq!(*val, 11);
/// ```
///
/// ```
/// use cut::Immutable;
///
/// struct Foo {
///   bar: Immutable<bool>,
/// }
///
/// impl Foo {
///   pub fn new(bar: bool) -> Self {
///     Self {
///       bar: Immutable::new(bar),
///     }
///   }
///
///   pub fn bar(&mut self) -> bool {
///     // ERROR
///     //self.bar = !*self.bar;
///
///     // if From<T> was implemented for Immutable<T>, you might accidently do this:
///     //self.bar = (!*self.bar).into();
///
///     // uh oh...
///     // atleast you can explictly see that a new Immutable<T> is being assigned
///     self.bar = Immutable::new(!*self.bar);
///
///     *self.bar
///   }
/// }
///
/// let mut foo = Foo::new(false);
///
/// assert_eq!(foo.bar(), true);
/// assert_eq!(foo.bar(), false);
/// assert_eq!(foo.bar(), true);
/// ```
///
/// </div>
///
/// <div class="warning">
///
/// Types with interior mutability such as [`Cell`][core::cell::Cell] can still be modified when
/// wrapped. This includes nesting such as the following:
///
/// ```
/// use core::cell::Cell;
///
/// use cut::Immutable;
///
/// struct Foo {
///   bar: Bar,
/// }
///
/// struct Bar {
///   baz: Cell<bool>,
/// }
///
/// let foo = Immutable::new(Foo {
///   bar: Bar {
///     baz: Cell::new(false),
///   },
/// });
///
/// foo.bar.baz.set(true);
///
/// assert_eq!(foo.bar.baz.get(), true);
/// ```
///
/// </div>
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct Immutable<T>(T);

impl<T> Immutable<T> {
  /// Wrap a value `v` to ensure read-only access going forward
  pub const fn new(v: T) -> Self {
    Self(v)
  }

  /// Get a reference to the wrapped read-only value
  pub fn get(&self) -> &T {
    &self.0
  }
}

impl<T> Deref for Immutable<T> {
  type Target = T;

  fn deref(&self) -> &Self::Target {
    self.get()
  }
}