deltastruct 0.1.8

Allows defining deltas for tagged structs for later application.
Documentation
//! Create custom serializable changes to apply later
//!
//! Deltastruct is an attribute macro that generates definitions for
//! serializable changes (called deltas) over structs recursively.
//!
//! For techinical reasons, the attribute macro must be applied to a `mod`
//! definition containing a `struct` with the same name and an `impl` for
//! it's change definitions. Function names are converted to camel case to
//! appease the compiler.
//!
//! The generated deltas are always the type name followed by `Delta`. ie: `Foo` -> `FooDelta`, `i32` -> `i32Delta`.
//!
//! ```
//! # use deltastruct::*;
//! #[deltastruct]
//! mod Vector3 {
//!   #[derive(Clone, Copy)]
//!   pub struct Vector3 {
//!     pub x : f64,
//!     pub y : f64,
//!     pub z : f64,
//!   }
//!
//!   impl Vector3 {
//!     fn set(&mut self, other : Vector3) {
//!       // Copy the given vec's components into our own.
//!       self.x = other.x;
//!       self.y = other.y;
//!       self.z = other.z;
//!     }
//!
//!     fn multiply_scalar(&mut self, n : f64) {
//!       // Multiply each component by the given value
//!       self.x *= n;
//!       self.y *= n;
//!       self.z *= n;
//!     }
//!
//!     fn normalize(&mut self) {
//!       // divide each component by the vector's magnitude
//!       let magnitude = (
//!           self.x.powf(2f64)
//!         + self.y.powf(2f64)
//!         + self.z.powf(2f64)
//!       ).sqrt();
//!       
//!       self.x /= magnitude;
//!       self.y /= magnitude;
//!       self.z /= magnitude;
//!     }
//!   }
//! }
//!
//! fn main() {
//!   let mut v = Vector3 {
//!     x: 3f64,
//!     y: 6f64,
//!     z: 6f64
//!   };
//!
//!
//!   let v_delta = Vector3Delta::MultiplyScalar(4f64);
//!   v.apply(&v_delta);
//!   v.apply(&v_delta);
//!
//!   assert_eq!(v.x, 48f64);
//!
//!
//!   let v_delta = Vector3Delta::Normalize();
//!   v.apply(&v_delta);
//!
//!   assert_eq!(v.z, 2f64/3f64);
//!
//!
//!   let v_delta = Vector3Delta::X(f64Delta::Set(8f64));
//!   v.apply(&v_delta);
//!
//!   assert_eq!(v.x, 8f64);
//! }
//!
//! ```
//!
//!

mod primitive_impls;
pub use primitive_impls::*;

/// An attribute macro applied to `mod`s. Will generate a Delta and it's `DeltaStruct<_>` implementation.
///
/// Applied to a `mod`. Expects the `mod` to have a `struct` with the same name
/// and an implementation. Currently at least one field is expected in the `struct`
/// definition and at least one method is expected in the implementation. This macro
/// will generate an `enum` with the same name as the mod with `Delta` appended,
/// and an implementation `impl DeltaStruct<FooDelta> for Foo`.
///
/// The delta will have a tuple variant for each method defined for the struct
/// converted to camel case, and it's tuple will be of the same type as the
/// argument list of it's respective method (without `&mut self`). It will also
/// expose delta functions of it's fields.
///
/// ## Example:
///
/// ```
/// # use deltastruct_proc::deltastruct;
/// # use deltastruct::*;
/// #[deltastruct]
/// mod Foo {
///   struct Foo {
///     x : i32,
///     y : i32
///   }
///
///   impl Foo {
///     fn swap(&mut self) {
///       let tmp = self.x;
///       self.x = self.y;
///       self.y = tmp;
///     }
///     
///     fn do_stuff(&mut self, n : f64) {
///       self.x = (n * (self.x as f64)) as i32;
///     }
///   }
/// }
/// ```
///
/// will generate:
/// ```
/// # use deltastruct::DeltaStruct;
/// # struct Foo;
/// # #[allow(non_camel_case_types)] struct i32Delta;
/// enum FooDelta {
///   Swap(),
///   DoStuff(f64),
///   X(i32Delta),
///   Y(i32Delta),
/// }
///
/// impl DeltaStruct<FooDelta> for Foo {
///   fn apply(&mut self, delta : &FooDelta) {
///     /* ... */
///   }
/// }
/// ```
pub use deltastruct_proc::deltastruct;

/// A trait derived for each tagged struct where `T` is it's generated delta.
///
/// ```
/// # use deltastruct::*;
/// #[deltastruct]
/// mod Foo {
///   struct Foo {
///     bar : bool
///   }
///   impl Foo {
///     fn foobar(&mut self) {}
///   }
/// }
/// ```
///
/// will generate:
/// ```
/// # use deltastruct::*;
/// # struct Foo;
/// # struct FooDelta;
/// impl DeltaStruct<FooDelta> for Foo {
///   fn apply(&mut self, delta : &FooDelta) {
///     /* ... */
///   }
/// }
/// ```
pub trait DeltaStruct<T> {
  fn apply(&mut self, delta: &T);
}

#[cfg(test)]
mod tests {
  use super::*;

  #[deltastruct]
  mod Foo {
    struct Foo {
      x: i32,
      y: i32,
    }

    impl Foo {
      pub fn bar(&mut self, a: i64, b: i64) {
        self.x = ((a * b) as i32) - self.y;
      }

      pub fn baz(&mut self, data: u32) {
        self.x += data as i32;
        self.y -= data as i32;
      }
    }
  }

  #[test]
  fn self_func() {
    let mut foo = Foo { x: 4, y: 7 };

    let dfoo = FooDelta::Baz(5);
    foo.apply(&dfoo);

    assert_eq!(foo.x, 9);
    assert_eq!(foo.y, 2);

    foo.apply(&dfoo);

    assert_eq!(foo.x, 14);
    assert_eq!(foo.y, -3);

    let dfoo = FooDelta::Bar(3, 4);
    foo.apply(&dfoo);

    assert_eq!(foo.x, 15);
    assert_eq!(foo.y, -3);
  }

  #[test]
  fn field_func() {
    let mut foo = Foo { x: 3, y: 6 };

    let dfoo = FooDelta::X(i32Delta::Set(1));
    foo.apply(&dfoo);

    assert_eq!(foo.x, 1);
    assert_eq!(foo.y, 6);

    let dfoo = FooDelta::Y(i32Delta::Set(-20));
    foo.apply(&dfoo);

    assert_eq!(foo.x, 1);
    assert_eq!(foo.y, -20);
  }

  #[test]
  fn delta_derives() {
    #[deltastruct(derive(Clone))]
    mod Testbug {
      struct Testbug {
        meh: u8,
      }

      impl Testbug {
        fn bar(&mut self) {}
      }
    }

    let testbugdelta = TestbugDelta::Bar();
    testbugdelta.clone();
  }
}