1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
//! The rlua-builders crate provides helpers for Rust/Lua interop using
//! [`rlua`]. That means creating Rust struct/enums from Lua with almost the
//! same syntax as in Rust!
//!
//! This crate itself only provides a trait definition, but using the (default) `derive`
//! feature provides derive macros to automatically implement the defined trait for
//! any struct or enum, as long as it has [`UserData`] implemented for it (for which a derive
//! macro is also provided). After that, simply call `StructOrEnum::builder(ctx)` to create a
//! builder for that struct or enum.
//!
//! ## What do these builders look like?
//! - For [unit structs]: A builder is simply the unit value itself, which can be converted to
//! Lua since the struct implements [`UserData`].
//! - For [tuple structs]: A builder is a lua function that receives the tuple arguments in order
//! and returns the userdata for the struct.
//! - For [normal structs]: A builder is a lua function that receives a single table with
//! the named arguments to the struct.
//! - For [enums]: A builder is a table where each field is a builder for each of the enum's
//! variants, and each of them works the same way as the struct builders defined above.
//!
//! ## Examples:
//! This shows how to derive and use [`LuaBuilder`] and [`UserData`] on a simple struct. By default
//! the derive macros are imported with `rlua-builders`. See [`rlua`] for more documentation on how
//! to interop with Lua.
//! ```
//! use rlua_builders::{LuaBuilder, UserData};
//!
//! #[derive(LuaBuilder, UserData, Clone, PartialEq, Debug)]
//! struct Person {
//!     name: String,
//!     age: u8,
//! }
//!
//! let p = rlua::Lua::new().context(|ctx| {
//!     ctx.globals().set("Person", Person::builder(ctx)?)?;
//!     ctx.load(r#"Person { name = "Yan", age = 24 }"#).eval::<Person>()
//! }).unwrap();
//!
//! assert_eq!(p, Person {name: "Yan".to_owned(), age: 24})
//! ```
//!
//! Enums work in a similar way, except their constructor is a table where each function
//! is equivalent to a struct builder.
//!
//! Additionally, you can use `#[default=VALUE]` to specify a default value for the field.
//! That means if nil is specified in Lua, then instead that default will be used, without
//! needing to manually use `Option` + `unwrap_or`.
//!
//! ```
//! # use rlua::UserData;
//! # use rlua_builders::*;
//! #[derive(LuaBuilder, UserData, Clone)]
//! enum Valuables {
//!     Coins(u32),
//!     Book {
//!         name: String,
//!         #[default=true]
//!         read: bool,
//!     },
//!     Knowledge,
//! }
//! ```
//! If later binded to lua
//! ```
//! # use rlua::UserData;
//! # use rlua_builders::*;
//! # #[derive(LuaBuilder, UserData, Clone)]
//! # enum Valuables {}
//! # rlua::Lua::new().context::<_, rlua::Result<()>>(|ctx| {
//! ctx.globals().set("Valuables", Valuables::builder(ctx)?)?;
//! # Ok(())
//! # }).unwrap();
//! ```
//! Can be used in a very similar way to Rust
//! ```lua
//! local a = Valuables.Coins(12)
//! local b = Valuables.Knowledge
//! local c = Valuables.Book { name = "A Dance with Dragons" }
//! ```
//!
//! [`UserData`]: rlua::UserData
//! [`rlua-builders-derive`]: https://crates.io/crates/rlua-builders-derive
//! [unit structs]: http://doc.rust-lang.org/1.43.1/book/ch05-01-defining-structs.html#unit-like-structs-without-any-fields
//! [tuple structs]: https://doc.rust-lang.org/1.43.1/book/ch05-01-defining-structs.html#using-tuple-structs-without-named-fields-to-create-different-types
//! [normal structs]: https://doc.rust-lang.org/1.43.1/book/ch05-01-defining-structs.html#defining-and-instantiating-structs
//! [enums]: https://doc.rust-lang.org/1.43.1/book/ch06-01-defining-an-enum.html#defining-an-enum
use rlua::{Context, Result, ToLua, UserData};

/// A struct or enum with this Trait provides a Lua builder.
///
/// Should not be implemented manually, instead use the [`rlua-builders-derive`] crate
/// to derive it automatically for any struct or enum.
///
/// [`rlua-builders-derive`]: https://crates.io/crates/rlua-builders-derive
pub trait LuaBuilder<'s, T: ToLua<'s>>: UserData + Clone {
    /// Create a Lua builder for this type
    fn builder(ctx: Context<'s>) -> Result<T>;
}

#[cfg(feature = "derive")]
pub use rlua_builders_derive::*;