lib.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. extern crate proc_macro;
  2. mod sorted_slice;
  3. use proc_macro::TokenStream;
  4. use quote::{quote, ToTokens, __private::Span};
  5. use sorted_slice::StrSlice;
  6. use syn::parenthesized;
  7. use syn::parse::ParseBuffer;
  8. use syn::punctuated::Punctuated;
  9. use syn::{
  10. self,
  11. parse::{Parse, ParseStream, Result},
  12. parse_macro_input, parse_quote, Error, Field, Ident, Token, Type,
  13. };
  14. /// Sorts a slice of string literals at compile time.
  15. #[proc_macro]
  16. pub fn sorted_str_slice(input: TokenStream) -> TokenStream {
  17. let slice: StrSlice = parse_macro_input!(input as StrSlice);
  18. let strings = slice.map.values();
  19. quote!([#(#strings, )*]).into()
  20. }
  21. #[derive(PartialEq, Debug, Clone)]
  22. enum DependencyKind {
  23. Node,
  24. Child,
  25. Parent,
  26. }
  27. /// Derive's the state from any elements that have a node_dep_state, child_dep_state, parent_dep_state, or state attribute.
  28. ///
  29. /// # Declaring elements
  30. /// Each of the attributes require specifying the members of the struct it depends on to allow the macro to find the optimal resultion order.
  31. /// These dependencies should match the types declared in the trait the member implements.
  32. ///
  33. /// # The node_dep_state attribute
  34. /// The node_dep_state attribute declares a member that implements the NodeDepState trait.
  35. /// ```rust, ignore
  36. /// #[derive(State)]
  37. /// struct MyStruct {
  38. /// // MyDependency implements ChildDepState<()>
  39. /// #[node_dep_state()]
  40. /// my_dependency_1: MyDependency,
  41. /// // MyDependency2 implements ChildDepState<(MyDependency,)>
  42. /// #[node_dep_state(my_dependency_1)]
  43. /// my_dependency_2: MyDependency2,
  44. /// }
  45. /// // or
  46. /// #[derive(State)]
  47. /// struct MyStruct {
  48. /// // MyDependnancy implements NodeDepState<()>
  49. /// #[node_dep_state()]
  50. /// my_dependency_1: MyDependency,
  51. /// // MyDependency2 implements NodeDepState<()>
  52. /// #[node_dep_state()]
  53. /// my_dependency_2: MyDependency2,
  54. /// // MyDependency3 implements NodeDepState<(MyDependency, MyDependency2)> with Ctx = f32
  55. /// #[node_dep_state((my_dependency_1, my_dependency_2), f32)]
  56. /// my_dependency_3: MyDependency2,
  57. /// }
  58. /// ```
  59. /// # The child_dep_state attribute
  60. /// The child_dep_state attribute declares a member that implements the ChildDepState trait.
  61. /// ```rust, ignore
  62. /// #[derive(State)]
  63. /// struct MyStruct {
  64. /// // MyDependnacy implements ChildDepState with DepState = Self
  65. /// #[child_dep_state(my_dependency_1)]
  66. /// my_dependency_1: MyDependency,
  67. /// }
  68. /// // or
  69. /// #[derive(State)]
  70. /// struct MyStruct {
  71. /// // MyDependnacy implements ChildDepState with DepState = Self
  72. /// #[child_dep_state(my_dependency_1)]
  73. /// my_dependency_1: MyDependency,
  74. /// // MyDependnacy2 implements ChildDepState with DepState = MyDependency and Ctx = f32
  75. /// #[child_dep_state(my_dependency_1, f32)]
  76. /// my_dependency_2: MyDependency2,
  77. /// }
  78. /// ```
  79. /// # The parent_dep_state attribute
  80. /// The parent_dep_state attribute declares a member that implements the ParentDepState trait.
  81. /// The parent_dep_state attribute can be called in the forms:
  82. /// ```rust, ignore
  83. /// #[derive(State)]
  84. /// struct MyStruct {
  85. /// // MyDependnacy implements ParentDepState with DepState = Self
  86. /// #[parent_dep_state(my_dependency_1)]
  87. /// my_dependency_1: MyDependency,
  88. /// }
  89. /// // or
  90. /// #[derive(State)]
  91. /// struct MyStruct {
  92. /// // MyDependnacy implements ParentDepState with DepState = Self
  93. /// #[parent_dep_state(my_dependency_1)]
  94. /// my_dependency_1: MyDependency,
  95. /// // MyDependnacy2 implements ParentDepState with DepState = MyDependency and Ctx = f32
  96. /// #[parent_dep_state(my_dependency_1, f32)]
  97. /// my_dependency_2: MyDependency2,
  98. /// }
  99. /// ```
  100. ///
  101. /// # Combining dependancies
  102. /// The node_dep_state, parent_dep_state, and child_dep_state attributes can be combined to allow for more complex dependancies.
  103. /// For example if we wanted to combine the font that is passed from the parent to the child and the layout of the size children to find the size of the current node we could do:
  104. /// ```rust, ignore
  105. /// #[derive(State)]
  106. /// struct MyStruct {
  107. /// // ChildrenSize implements ChildDepState with DepState = Size
  108. /// #[child_dep_state(size)]
  109. /// children_size: ChildrenSize,
  110. /// // FontSize implements ParentDepState with DepState = Self
  111. /// #[parent_dep_state(font_size)]
  112. /// font_size: FontSize,
  113. /// // Size implements NodeDepState<(ChildrenSize, FontSize)>
  114. /// #[parent_dep_state((children_size, font_size))]
  115. /// size: Size,
  116. /// }
  117. /// ```
  118. ///
  119. /// # The state attribute
  120. /// The state macro declares a member that implements the State trait. This allows you to organize your state into multiple isolated components.
  121. /// Unlike the other attributes, the state attribute does not accept any arguments, because a nested state cannot depend on any other part of the state.
  122. ///
  123. /// # Custom values
  124. ///
  125. /// If your state has a custom value type you can specify it with the state attribute.
  126. ///
  127. /// ```rust, ignore
  128. /// #[derive(State)]
  129. /// #[state(custom_value = MyCustomType)]
  130. /// struct MyStruct {
  131. /// // ...
  132. /// }
  133. #[proc_macro_derive(
  134. State,
  135. attributes(node_dep_state, child_dep_state, parent_dep_state, state)
  136. )]
  137. pub fn state_macro_derive(input: TokenStream) -> TokenStream {
  138. let ast = syn::parse(input).unwrap();
  139. impl_derive_macro(&ast)
  140. }
  141. fn impl_derive_macro(ast: &syn::DeriveInput) -> TokenStream {
  142. let custom_type = ast
  143. .attrs
  144. .iter()
  145. .find(|a| a.path.is_ident("state"))
  146. .and_then(|attr| {
  147. // parse custom_type = "MyType"
  148. let assignment = attr.parse_args::<syn::Expr>().unwrap();
  149. if let syn::Expr::Assign(assign) = assignment {
  150. let (left, right) = (&*assign.left, &*assign.right);
  151. if let syn::Expr::Path(e) = left {
  152. let path = &e.path;
  153. if let Some(ident) = path.get_ident() {
  154. if ident == "custom_value" {
  155. return match right {
  156. syn::Expr::Path(e) => {
  157. let path = &e.path;
  158. Some(quote! {#path})
  159. }
  160. _ => None,
  161. };
  162. }
  163. }
  164. }
  165. }
  166. None
  167. })
  168. .unwrap_or(quote! {()});
  169. let type_name = &ast.ident;
  170. let fields: Vec<_> = match &ast.data {
  171. syn::Data::Struct(data) => match &data.fields {
  172. syn::Fields::Named(e) => &e.named,
  173. syn::Fields::Unnamed(_) => todo!("unnamed fields"),
  174. syn::Fields::Unit => todo!("unit structs"),
  175. }
  176. .iter()
  177. .collect(),
  178. _ => unimplemented!(),
  179. };
  180. let strct = Struct::new(type_name.clone(), &fields);
  181. match StateStruct::parse(&fields, &strct) {
  182. Ok(state_strct) => {
  183. let passes = state_strct.state_members.iter().map(|m| {
  184. let unit = &m.mem.unit_type;
  185. match m.dep_kind {
  186. DependencyKind::Node => quote! {dioxus_native_core::AnyPass::Node(&#unit)},
  187. DependencyKind::Child => quote! {dioxus_native_core::AnyPass::Upward(&#unit)},
  188. DependencyKind::Parent => {
  189. quote! {dioxus_native_core::AnyPass::Downward(&#unit)}
  190. }
  191. }
  192. });
  193. let member_types = state_strct.state_members.iter().map(|m| &m.mem.ty);
  194. let impl_members = state_strct
  195. .state_members
  196. .iter()
  197. .map(|m| m.impl_pass(state_strct.ty, &custom_type));
  198. let gen = quote! {
  199. #(#impl_members)*
  200. impl State<#custom_type> for #type_name {
  201. const PASSES: &'static [dioxus_native_core::AnyPass<dioxus_native_core::node::Node<Self, #custom_type>>] = &[
  202. #(#passes),*
  203. ];
  204. const MASKS: &'static [dioxus_native_core::NodeMask] = &[#(#member_types::NODE_MASK),*];
  205. }
  206. };
  207. gen.into()
  208. }
  209. Err(e) => e.into_compile_error().into(),
  210. }
  211. }
  212. struct Struct {
  213. name: Ident,
  214. members: Vec<Member>,
  215. }
  216. impl Struct {
  217. fn new(name: Ident, fields: &[&Field]) -> Self {
  218. let members = fields
  219. .iter()
  220. .enumerate()
  221. .filter_map(|(i, f)| Member::parse(&name, f, i as u64))
  222. .collect();
  223. Self { name, members }
  224. }
  225. }
  226. struct StateStruct<'a> {
  227. state_members: Vec<StateMember<'a>>,
  228. #[allow(unused)]
  229. child_states: Vec<&'a Member>,
  230. ty: &'a Ident,
  231. }
  232. impl<'a> StateStruct<'a> {
  233. /// Parse the state structure, and find a resolution order that will allow us to update the state for each node in after the state(s) it depends on have been resolved.
  234. fn parse(fields: &[&'a Field], strct: &'a Struct) -> Result<Self> {
  235. let mut parse_err = Ok(());
  236. let mut state_members: Vec<_> = strct
  237. .members
  238. .iter()
  239. .zip(fields.iter())
  240. .filter_map(|(m, f)| match StateMember::parse(f, m, strct) {
  241. Ok(m) => m,
  242. Err(err) => {
  243. parse_err = Err(err);
  244. None
  245. }
  246. })
  247. .collect();
  248. parse_err?;
  249. for i in 0..state_members.len() {
  250. let deps: Vec<_> = state_members[i].dep_mems.iter().map(|m| m.id).collect();
  251. for dep in deps {
  252. state_members[dep as usize].dependant_mems.push(i as u64);
  253. }
  254. }
  255. let child_states = strct
  256. .members
  257. .iter()
  258. .zip(fields.iter())
  259. .filter(|(_, f)| {
  260. f.attrs.iter().any(|a| {
  261. a.path
  262. .get_ident()
  263. .filter(|i| i.to_string().as_str() == "state")
  264. .is_some()
  265. })
  266. })
  267. .map(|(m, _)| m);
  268. // members need to be sorted so that members are updated after the members they depend on
  269. Ok(Self {
  270. ty: &strct.name,
  271. state_members,
  272. child_states: child_states.collect(),
  273. })
  274. }
  275. }
  276. fn try_parenthesized(input: ParseStream) -> Result<ParseBuffer> {
  277. let inside;
  278. parenthesized!(inside in input);
  279. Ok(inside)
  280. }
  281. struct Dependency {
  282. ctx_ty: Option<Type>,
  283. deps: Vec<Ident>,
  284. }
  285. impl Parse for Dependency {
  286. fn parse(input: ParseStream) -> Result<Self> {
  287. let deps: Option<Punctuated<Ident, Token![,]>> = {
  288. try_parenthesized(input)
  289. .ok()
  290. .and_then(|inside| inside.parse_terminated(Ident::parse).ok())
  291. };
  292. let deps: Vec<_> = deps
  293. .map(|deps| deps.into_iter().collect())
  294. .or_else(|| {
  295. input
  296. .parse::<Ident>()
  297. .ok()
  298. .filter(|i: &Ident| i != "NONE")
  299. .map(|i| vec![i])
  300. })
  301. .unwrap_or_default();
  302. let comma: Option<Token![,]> = input.parse().ok();
  303. let ctx_ty = input.parse().ok();
  304. Ok(Self {
  305. ctx_ty: comma.and(ctx_ty),
  306. deps,
  307. })
  308. }
  309. }
  310. /// The type of the member and the ident of the member
  311. #[derive(PartialEq, Debug)]
  312. struct Member {
  313. id: u64,
  314. ty: Type,
  315. unit_type: Ident,
  316. ident: Ident,
  317. }
  318. impl Member {
  319. fn parse(parent: &Ident, field: &Field, id: u64) -> Option<Self> {
  320. Some(Self {
  321. id,
  322. ty: field.ty.clone(),
  323. unit_type: Ident::new(
  324. ("_Unit".to_string()
  325. + parent.to_token_stream().to_string().as_str()
  326. + field.ty.to_token_stream().to_string().as_str())
  327. .as_str(),
  328. Span::call_site(),
  329. ),
  330. ident: field.ident.as_ref()?.clone(),
  331. })
  332. }
  333. }
  334. #[derive(Debug, Clone)]
  335. struct StateMember<'a> {
  336. mem: &'a Member,
  337. // the kind of dependncies this state has
  338. dep_kind: DependencyKind,
  339. // the depenancy and if it is satified
  340. dep_mems: Vec<&'a Member>,
  341. // any members that depend on this member
  342. dependant_mems: Vec<u64>,
  343. // the context this state requires
  344. ctx_ty: Option<Type>,
  345. }
  346. impl<'a> StateMember<'a> {
  347. fn parse(
  348. field: &Field,
  349. mem: &'a Member,
  350. parent: &'a Struct,
  351. ) -> Result<Option<StateMember<'a>>> {
  352. let mut err = Ok(());
  353. let member = field.attrs.iter().find_map(|a| {
  354. let dep_kind = a
  355. .path
  356. .get_ident()
  357. .and_then(|i| match i.to_string().as_str() {
  358. "node_dep_state" => Some(DependencyKind::Node),
  359. "child_dep_state" => Some(DependencyKind::Child),
  360. "parent_dep_state" => Some(DependencyKind::Parent),
  361. _ => None,
  362. })?;
  363. match a.parse_args::<Dependency>() {
  364. Ok(dependency) => {
  365. let dep_mems = dependency
  366. .deps
  367. .iter()
  368. .filter_map(|name| {
  369. if let Some(found) = parent.members.iter().find(|m| &m.ident == name) {
  370. Some(found)
  371. } else {
  372. err = Err(Error::new(
  373. name.span(),
  374. format!("{} not found in {}", name, parent.name),
  375. ));
  376. None
  377. }
  378. })
  379. .collect();
  380. Some(Self {
  381. mem,
  382. dep_kind,
  383. dep_mems,
  384. dependant_mems: Vec::new(),
  385. ctx_ty: dependency.ctx_ty,
  386. })
  387. }
  388. Err(e) => {
  389. err = Err(e);
  390. None
  391. }
  392. }
  393. });
  394. err?;
  395. Ok(member)
  396. }
  397. /// generate code to call the resolve function for the state. This does not handle checking if resolving the state is necessary, or marking the states that depend on this state as dirty.
  398. fn impl_pass(
  399. &self,
  400. parent_type: &Ident,
  401. custom_type: impl ToTokens,
  402. ) -> quote::__private::TokenStream {
  403. let ident = &self.mem.ident;
  404. let get_ctx = if let Some(ctx_ty) = &self.ctx_ty {
  405. if ctx_ty == &parse_quote!(()) {
  406. quote! {&()}
  407. } else {
  408. let msg = ctx_ty.to_token_stream().to_string() + " not found in context";
  409. quote! {ctx.get().expect(#msg)}
  410. }
  411. } else {
  412. quote! {&()}
  413. };
  414. let ty = &self.mem.ty;
  415. let unit_type = &self.mem.unit_type;
  416. let node_view =
  417. quote!(dioxus_native_core::node_ref::NodeView::new(&node.node_data, #ty::NODE_MASK));
  418. let dep_idents = self.dep_mems.iter().map(|m| &m.ident);
  419. let impl_specific = match self.dep_kind {
  420. DependencyKind::Node => {
  421. quote! {
  422. impl dioxus_native_core::NodePass<dioxus_native_core::node::Node<#parent_type, #custom_type>> for #unit_type {
  423. fn pass(&self, node: &mut dioxus_native_core::node::Node<#parent_type, #custom_type>, ctx: &dioxus_native_core::SendAnyMap) -> bool {
  424. node.state.#ident.reduce(#node_view, (#(&node.state.#dep_idents,)*), #get_ctx)
  425. }
  426. }
  427. }
  428. }
  429. DependencyKind::Child => {
  430. let update = if self.dep_mems.iter().any(|m| m.id == self.mem.id) {
  431. quote! {
  432. if update {
  433. dioxus_native_core::PassReturn{
  434. progress: true,
  435. mark_dirty: true,
  436. }
  437. } else {
  438. dioxus_native_core::PassReturn{
  439. progress: false,
  440. mark_dirty: false,
  441. }
  442. }
  443. }
  444. } else {
  445. quote! {
  446. if update {
  447. dioxus_native_core::PassReturn{
  448. progress: false,
  449. mark_dirty: true,
  450. }
  451. } else {
  452. dioxus_native_core::PassReturn{
  453. progress: false,
  454. mark_dirty: false,
  455. }
  456. }
  457. }
  458. };
  459. quote!(
  460. impl dioxus_native_core::UpwardPass<dioxus_native_core::node::Node<#parent_type, #custom_type>> for #unit_type{
  461. fn pass<'a>(
  462. &self,
  463. node: &mut dioxus_native_core::node::Node<#parent_type, #custom_type>,
  464. children: &mut dyn Iterator<Item = &'a mut dioxus_native_core::node::Node<#parent_type, #custom_type>>,
  465. ctx: &dioxus_native_core::SendAnyMap,
  466. ) -> dioxus_native_core::PassReturn {
  467. let update = node.state.#ident.reduce(#node_view, children.map(|c| (#(&c.state.#dep_idents,)*)), #get_ctx);
  468. #update
  469. }
  470. }
  471. )
  472. }
  473. DependencyKind::Parent => {
  474. let update = if self.dep_mems.iter().any(|m| m.id == self.mem.id) {
  475. quote! {
  476. if update {
  477. dioxus_native_core::PassReturn{
  478. progress: true,
  479. mark_dirty: true,
  480. }
  481. } else {
  482. dioxus_native_core::PassReturn{
  483. progress: false,
  484. mark_dirty: false,
  485. }
  486. }
  487. }
  488. } else {
  489. quote! {
  490. if update {
  491. dioxus_native_core::PassReturn{
  492. progress: false,
  493. mark_dirty: true,
  494. }
  495. } else {
  496. dioxus_native_core::PassReturn{
  497. progress: false,
  498. mark_dirty: false,
  499. }
  500. }
  501. }
  502. };
  503. quote!(
  504. impl dioxus_native_core::DownwardPass<dioxus_native_core::node::Node<#parent_type, #custom_type>> for #unit_type {
  505. fn pass(&self, node: &mut dioxus_native_core::node::Node<#parent_type, #custom_type>, parent: Option<&mut dioxus_native_core::node::Node<#parent_type, #custom_type>>, ctx: &dioxus_native_core::SendAnyMap) -> dioxus_native_core::PassReturn{
  506. let update = node.state.#ident.reduce(#node_view, parent.as_ref().map(|p| (#(&p.state.#dep_idents,)*)), #get_ctx);
  507. #update
  508. }
  509. }
  510. )
  511. }
  512. };
  513. let pass_id = self.mem.id;
  514. let depenancies = self.dep_mems.iter().map(|m| m.id);
  515. let dependants = &self.dependant_mems;
  516. let mask = self
  517. .dep_mems
  518. .iter()
  519. .map(|m| 1u64 << m.id)
  520. .fold(1 << self.mem.id, |a, b| a | b);
  521. quote! {
  522. #[derive(Clone, Copy)]
  523. struct #unit_type;
  524. #impl_specific
  525. impl dioxus_native_core::Pass for #unit_type {
  526. fn pass_id(&self) -> dioxus_native_core::PassId {
  527. dioxus_native_core::PassId(#pass_id)
  528. }
  529. fn dependancies(&self) -> &'static [dioxus_native_core::PassId] {
  530. &[#(dioxus_native_core::PassId(#depenancies)),*]
  531. }
  532. fn dependants(&self) -> &'static [dioxus_native_core::PassId] {
  533. &[#(dioxus_native_core::PassId(#dependants)),*]
  534. }
  535. fn mask(&self) -> dioxus_native_core::MemberMask {
  536. dioxus_native_core::MemberMask(#mask)
  537. }
  538. }
  539. }
  540. }
  541. }