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 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
/// Provides useful hooks and supporting utilities.
pub mod hooks;
/// Holds platform-specific rendering interfaces.
pub mod renderer;
/// A reference-counted interior-mutable type designed to reduce runtime borrow rule violations.
pub mod shared;
/// Holds types and macros used for propogating and tracking data updates.
pub mod tracked;
/// A `Vec`-backed implementation of a tree, with a relatively friendly mutation api.
pub(crate) mod tree;
/// An in-memory representation of the current component tree.
#[doc(hidden)]
pub mod vdom;
use downcast_rs::{impl_downcast, Downcast};
use std::rc::Rc;
use renderer::NativeType;
use shared::Shared;
use tree::NodeId;
use vdom::{VDom, VNode};
pub use hooks::{state, vec, Context};
pub use tracked::Tracked;
/// An attribute macro used to define components.
///
/// # Basic usage
/// The macro must be applied to a function that returns a [View](View).
/// It generates a `struct` implementing [Component](Component) with the name of the input function, and a builder struct.
/// The function's name should start with a capital ASCII character.
///
/// The function can optionally take parameters. Parameter types must be `Clone` and `'static`.
/// Parameters must have concrete types: they cannot use the `impl Trait`
/// syntax. Components cannot be `async` or generic.
///
/// A component must return a [View] describing what it will render.
/// Components are invoked with the same syntax as function calls, except with
/// the macro `!` after the type name:
/// ```rust
/// use avalanche::{component, tracked, View};
/// use avalanche_web::components::{H1, Text};
///
/// const class: &str = "hello-world";
///
/// #[component]
/// pub fn HelloWorld(name: String) -> View {
/// H1!(
/// id: class,
/// class: class,
/// child: Text!(format!("Hi there, {}!", tracked!(name)))
/// )
/// }
/// ```
///
/// In the case of `H1`, all of its parameters are optional and have default values, but for components generated by this
/// macro, all parameters must be provided, or component instantiation will panic at runtime. In the future, this will
/// instead be a compile-time error.
///
/// Note that all macro invocations beginning with a capital ASCII character will be interpreted as component invocations
/// within the function. If you need to invoke a macro beginning with a capital letter, consider using it with an alias
/// beginning with `_`.
///
/// ## Tracked values
/// Parameter values are passed into a function with the [Tracked](Tracked) wrapper. More details on how that works is found in
/// the [tracked](tracked!) macro documentation.
///
/// ## Avoid side effects and mutability
/// `avalanche` considers a parameter updated if one of the parameters or hooks that influence it change, but
/// a function like [rand::thread_rng](https://docs.rs/rand/0.8/rand/fn.thread_rng.html) has a different value on every call
/// despite having no parameter or hook dependencies.
/// Using values from functions and methods that are not pure or mutate values will lead to missed updates. Instead, create new variables:
/// use `let string = string + " appended"` instead of `string += "appended"`.
/// If you need to use mutation in a component, including interior mutability, use the [state](state) hook.
///
/// ## Eschew third-party macros
/// Unfortunately, macros are syntax extensions and `component` cannot keep track of tracked variables in most of them.
/// All `std` macros (like [vec!](std::vec!()) and [format!](std::format!())) and `avalanche` macros (like [enclose!()])
/// work well, but any others may lead to parameters being incorrectly marked as not updated.
#[doc(inline)]
pub use avalanche_macro::component;
/// Takes a list of identifiers terminated by a semicolon and expression. Each identifier is
/// cloned, and made available to the expression. The macro evaluates to that expression.
/// This is useful for passing things like state and setters to multiple component props.
/// # Example
/// ```rust
/// # use avalanche::enclose;
/// let message = "Enclose me!".to_owned();
/// let closure1 = enclose!(message; move || println!("{}", message));
/// let closure2 = enclose!(message; move || eprintln!("{}", message));
/// ```
#[macro_export]
macro_rules! enclose {
( $( $x:ident ),*; $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
/// For internal use only, does not obey semver and is unsupported
/// A hack used to work around a seeming syn limitation
/// syn will interpret some macro calls as items rather than expressions
/// syn expects an item to be replaced by another, so when parsing Component! type macros,
/// `#[component]` will replace that call with an expression within this macro
/// to syn, this is replacing one macro item with another
#[doc(hidden)]
#[macro_export]
macro_rules! __internal_identity {
($e:expr) => {
$e
};
}
/// A reference-counted type that holds an instance of a component.
/// Component functions must return a [`View`].
#[derive(Clone)]
pub struct View {
rc: Rc<dyn DynComponent>,
}
impl View {
fn new<T: DynComponent>(val: T) -> Self {
Self { rc: Rc::new(val) }
}
}
impl std::ops::Deref for View {
type Target = dyn DynComponent;
fn deref(&self) -> &dyn DynComponent {
&*self.rc
}
}
impl<T: DynComponent> From<T> for View {
fn from(val: T) -> Self {
Self::new(val)
}
}
impl<T: DynComponent> From<Option<T>> for View {
fn from(val: Option<T>) -> Self {
match val {
Some(val) => View::new(val),
None => View::new(()),
}
}
}
impl From<Option<View>> for View {
fn from(val: Option<View>) -> Self {
match val {
Some(val) => val,
None => View::new(()),
}
}
}
/// The trait representing a component.
///
/// Users should not implement this trait manually but instead use the `component` attribute.
/// However, native component implementations may need to use manual component implementations.
pub trait Component: 'static {
type Builder;
fn render(&self, ctx: Context) -> View;
fn updated(&self) -> bool;
fn native_type(&self) -> Option<NativeType> {
None
}
fn location(&self) -> Option<(u32, u32)> {
None
}
fn key(&self) -> Option<&str> {
None
}
}
impl Component for () {
// TODO: make ! when never stabilizes
type Builder = ();
fn render(&self, _: Context) -> View {
unreachable!()
}
fn updated(&self) -> bool {
false
}
}
/// An internal trait implemented for all [`Component`]s. This should not be
/// implemented manually.
#[doc(hidden)]
pub trait DynComponent: Downcast + 'static {
fn render(&self, ctx: Context) -> View;
fn native_type(&self) -> Option<NativeType>;
fn updated(&self) -> bool;
fn location(&self) -> Option<(u32, u32)>;
fn key(&self) -> Option<&str>;
}
impl_downcast!(DynComponent);
impl<T: Component> DynComponent for T {
fn render(&self, ctx: Context) -> View {
Component::render(self, ctx)
}
fn native_type(&self) -> Option<NativeType> {
Component::native_type(self)
}
fn updated(&self) -> bool {
Component::updated(self)
}
fn location(&self) -> Option<(u32, u32)> {
Component::location(self)
}
fn key(&self) -> Option<&str> {
Component::key(self)
}
}
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct ComponentNodeId {
pub(crate) id: NodeId<VNode>,
}
impl From<NodeId<VNode>> for ComponentNodeId {
fn from(node: NodeId<VNode>) -> Self {
Self { id: node }
}
}
#[doc(hidden)]
#[derive(Copy, Clone)]
/// Internal data structure that stores what tree a component
/// belongs to, and its position within it
pub struct ComponentPos<'a> {
/// Shared value ONLY for passing to UseState
/// within the render function this value is mutably borrowed,
/// so exec and exec_mut will panic
pub node_id: ComponentNodeId,
/// Shared container to the VDom of which the [`vnode`] is a part.
pub vdom: &'a Shared<VDom>,
}