//! Interactive visual applications in Rust. //! //! ``` //! # #![allow(clippy::needless_doctest_main)] //! use sketchbook::*; //! use sketchbook::ream::Single; //! //! #[apply(derive_sketch)] //! #[sketch( //! env = minimal, //! aspects = (/* aspects go here */), //! )] //! struct App { //! #[page] page: minimal::Page, //! } //! //! impl Setup for App { //! fn setup(page: minimal::Page, _: ()) -> Self { //! Self { page } //! } //! } //! //! fn main() { //! Book::>::bind(); //! } //! ``` //! //! ## Environments //! //! | Crate | Description | Status | //! |-------------------------------------------------------------|------------------------------------------------------------------|----------------| //! | [sketchbook-wgpu](https://crates.io/crates/sketchbook-wgpu) | Directly uses `winit` and `wgpu` to run sketches. | In Development | //! | sketchbook-web | Runs sketches in a web browser. | Planned | //! | sketchbook-avr | Runs sketches on AVR micro-controllers (E.g. AVR based Arduinos) | Planned | //! //! ## Feature Flags #![cfg_attr( docsrs, cfg_attr(doc, doc = ::document_features::document_features!()) )] // #![warn(missing_docs)] #![cfg_attr(not(feature = "std"), no_std)] // only enables the `doc_cfg` feature when // the `docsrs` configuration attribute is defined #![cfg_attr(docsrs, feature(doc_cfg))] #![deny( bad_style, const_err, dead_code, improper_ctypes, non_shorthand_field_patterns, no_mangle_generic_items, overflowing_literals, path_statements, patterns_in_fns_without_body, private_in_public, unconditional_recursion, unused, unused_allocation, unused_comparisons, unused_parens, while_true )] #![warn( rust_2018_idioms, missing_debug_implementations, missing_docs, trivial_casts, trivial_numeric_casts, unused_extern_crates, unused_import_braces, unused_qualifications, unused_results, unsafe_code )] #![deny(clippy::unwrap_used, clippy::expect_used)] #[cfg(feature = "alloc")] extern crate alloc; pub mod compose; mod env; pub mod ream; mod book; mod real; pub mod aspects; mod geometry; pub use book::*; // pub use ream::*; pub use env::*; // pub use aspects::*; pub use geometry::*; pub use real::*; /// Base trait for all sketches. /// /// A user does not need to interact with this trait directly. /// /// A sketch is a type that contains a page from an environment. /// The sketch is then run within the environment and handles the events it generates. pub trait Sketch { /// Environment the sketch can run in. type Env: Environment; /// Get page for sketch. fn get_page(&self) -> &PageOf; /// Get page mutabily for sketch. fn get_page_mut(&mut self) -> &mut PageOf; /// Handle an event from the environment. /// /// This is called by the ream the sketch is running in. fn handle_environment_event(&mut self, event: &EventOf); } /// Allow aspect extension traits to be called directly on `S` instead of using the page field. impl compose::AsPart for S where S: Sketch, PageOf: compose::AsPart, { fn as_part(&self) -> &C { self.get_page().as_part() } fn as_part_mut(&mut self) -> &mut C { self.get_page_mut().as_part_mut() } } /// Trait for setting up a sketch given some input. pub trait Setup where Self: Sketch, { /// Setup sketch using a page from the environment and given input. fn setup(page: PageOf, input: Input) -> Self; } /// Implements the `Sketch` trait for a struct. /// /// To enable event handlers for aspects put the event in the `aspects` list of the `sketch` /// attribute. /// See a spesific aspect's docs for examples of using events. /// ``` /// # use sketchbook::minimal; /// # use sketchbook::derive_sketch; /// derive_sketch! { /// #[sketch( /// env = minimal, /// aspects = (/* aspects go here */), /// )] /// struct App { /// #[page] page: minimal::Page, /// } /// } /// ``` /// /// ## Usage With `macro_rules_attribute` /// ``` /// # use sketchbook::minimal; /// # use sketchbook::derive_sketch; /// # use macro_rules_attribute::apply; /// #[apply(derive_sketch)] /// #[sketch( /// env = minimal, /// aspects = (/* aspects go here */), /// )] /// struct App { /// #[page] page: minimal::Page, /// } /// ``` #[macro_export] macro_rules! derive_sketch { { $(#[doc = $docs:literal])? #[sketch(env = $env_name:ident $(, aspects = ($($aspect_name:ident),* $(,)?))? $(,)?)] $struct_vis:vis struct $sketch_name:ident { $($($before_vis:vis $before_field_name:ident : $before_field_type:ty),+,)? #[page] $page_vis:vis $page_name:ident: $page_type:ty $(,$($after_vis:vis $after_field_name:ident : $after_field_type:ty),+)?$(,)? } } => { $(#[doc = $docs])? $struct_vis struct $sketch_name { $($($before_vis $before_field_name : $before_field_type),+,)? $page_vis $page_name: $page_type $(,$($after_vis $after_field_name : $after_field_type),+)? } #[automatically_derived] #[allow(unused_qualifications)] impl $crate::Sketch for $sketch_name { type Env = $env_name::Env; fn get_page(&self) -> &$crate::PageOf<$env_name::Env> { &self.$page_name } fn get_page_mut(&mut self) -> &mut $crate::PageOf<$env_name::Env> { &mut self.$page_name } fn handle_environment_event( &mut self, event: &$crate::EventOf, ) { use $crate::compose::TryAsPart; $($( if let Some(event) = event.try_as_part() { ::run_handlers(self, event); } )*)? } } $($( #[automatically_derived] #[allow(unused_qualifications)] impl $aspect_name::RunHandlers for $sketch_name {} )*)? }; { $(#[doc = $docs:literal])? #[sketch(env = $env_name:ident $(, aspects = ($($aspect_name:ident),* $(,)?))? $(,)?)] $struct_vis:vis struct $sketch_name:ident { $($code:tt)* } } => { compile_error!("Missing `#[page]` attribute on field for environment's page."); }; { $(#[doc = $docs:literal])? $(#[sketch($($attr:tt)*)])? $struct_vis:vis struct $sketch_name:ident { $($code:tt)* } } => { compile_error!("Missing `#[sketch(env = .., aspects = (.., ...))]` attribute."); }; { $($tokens:tt)* } => { compile_error!("Unable to parse struct. See docs for `derive_sketch!` for expected syntax."); } } /// Re-export of `macro_rules_attribute`'s `apply` macro. /// /// Visit [the crates.io page](https://crates.io/crates/macro_rules_attribute) for /// `macro_rules_attribute` for information about it. /// /// Visit [the docs.rs page](https://docs.rs/macro_rules_attribute/latest/macro_rules_attribute/attr.apply.html) /// for more details about this specific macro. #[cfg(feature = "derive")] pub use macro_rules_attribute::apply;