mod.rs 47 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174
  1. //! This code mostly comes from idanarye/rust-typed-builder
  2. //!
  3. //! However, it has been adopted to fit the Dioxus Props builder pattern.
  4. //!
  5. //! For Dioxus, we make a few changes:
  6. //! - [ ] Automatically implement Into<Option> on the setters (IE the strip setter option)
  7. //! - [ ] Automatically implement a default of none for optional fields (those explicitly wrapped with Option<T>)
  8. use proc_macro2::TokenStream;
  9. use syn::parse::Error;
  10. use syn::spanned::Spanned;
  11. use quote::quote;
  12. pub fn impl_my_derive(ast: &syn::DeriveInput) -> Result<TokenStream, Error> {
  13. let data = match &ast.data {
  14. syn::Data::Struct(data) => match &data.fields {
  15. syn::Fields::Named(fields) => {
  16. let struct_info = struct_info::StructInfo::new(ast, fields.named.iter())?;
  17. let builder_creation = struct_info.builder_creation_impl()?;
  18. let conversion_helper = struct_info.conversion_helper_impl()?;
  19. let fields = struct_info
  20. .included_fields()
  21. .map(|f| struct_info.field_impl(f))
  22. .collect::<Result<Vec<_>, _>>()?;
  23. let fields = quote!(#(#fields)*).into_iter();
  24. let required_fields = struct_info
  25. .included_fields()
  26. .filter(|f| f.builder_attr.default.is_none())
  27. .map(|f| struct_info.required_field_impl(f))
  28. .collect::<Result<Vec<_>, _>>()?;
  29. let build_method = struct_info.build_method_impl();
  30. quote! {
  31. #builder_creation
  32. #conversion_helper
  33. #( #fields )*
  34. #( #required_fields )*
  35. #build_method
  36. }
  37. }
  38. syn::Fields::Unnamed(_) => {
  39. return Err(Error::new(
  40. ast.span(),
  41. "Props is not supported for tuple structs",
  42. ))
  43. }
  44. syn::Fields::Unit => {
  45. return Err(Error::new(
  46. ast.span(),
  47. "Props is not supported for unit structs",
  48. ))
  49. }
  50. },
  51. syn::Data::Enum(_) => {
  52. return Err(Error::new(ast.span(), "Props is not supported for enums"))
  53. }
  54. syn::Data::Union(_) => {
  55. return Err(Error::new(ast.span(), "Props is not supported for unions"))
  56. }
  57. };
  58. Ok(data)
  59. }
  60. mod util {
  61. use quote::ToTokens;
  62. pub fn path_to_single_string(path: &syn::Path) -> Option<String> {
  63. if path.leading_colon.is_some() {
  64. return None;
  65. }
  66. let mut it = path.segments.iter();
  67. let segment = it.next()?;
  68. if it.next().is_some() {
  69. // Multipart path
  70. return None;
  71. }
  72. if segment.arguments != syn::PathArguments::None {
  73. return None;
  74. }
  75. Some(segment.ident.to_string())
  76. }
  77. pub fn expr_to_single_string(expr: &syn::Expr) -> Option<String> {
  78. if let syn::Expr::Path(path) = expr {
  79. path_to_single_string(&path.path)
  80. } else {
  81. None
  82. }
  83. }
  84. pub fn ident_to_type(ident: syn::Ident) -> syn::Type {
  85. let mut path = syn::Path {
  86. leading_colon: None,
  87. segments: Default::default(),
  88. };
  89. path.segments.push(syn::PathSegment {
  90. ident,
  91. arguments: Default::default(),
  92. });
  93. syn::Type::Path(syn::TypePath { qself: None, path })
  94. }
  95. pub fn empty_type() -> syn::Type {
  96. syn::TypeTuple {
  97. paren_token: Default::default(),
  98. elems: Default::default(),
  99. }
  100. .into()
  101. }
  102. pub fn type_tuple(elems: impl Iterator<Item = syn::Type>) -> syn::TypeTuple {
  103. let mut result = syn::TypeTuple {
  104. paren_token: Default::default(),
  105. elems: elems.collect(),
  106. };
  107. if !result.elems.empty_or_trailing() {
  108. result.elems.push_punct(Default::default());
  109. }
  110. result
  111. }
  112. pub fn empty_type_tuple() -> syn::TypeTuple {
  113. syn::TypeTuple {
  114. paren_token: Default::default(),
  115. elems: Default::default(),
  116. }
  117. }
  118. pub fn make_punctuated_single<T, P: Default>(value: T) -> syn::punctuated::Punctuated<T, P> {
  119. let mut punctuated = syn::punctuated::Punctuated::new();
  120. punctuated.push(value);
  121. punctuated
  122. }
  123. pub fn modify_types_generics_hack<F>(
  124. ty_generics: &syn::TypeGenerics,
  125. mut mutator: F,
  126. ) -> syn::AngleBracketedGenericArguments
  127. where
  128. F: FnMut(&mut syn::punctuated::Punctuated<syn::GenericArgument, syn::token::Comma>),
  129. {
  130. let mut abga: syn::AngleBracketedGenericArguments =
  131. syn::parse(ty_generics.clone().into_token_stream().into()).unwrap_or_else(|_| {
  132. syn::AngleBracketedGenericArguments {
  133. colon2_token: None,
  134. lt_token: Default::default(),
  135. args: Default::default(),
  136. gt_token: Default::default(),
  137. }
  138. });
  139. mutator(&mut abga.args);
  140. abga
  141. }
  142. pub fn strip_raw_ident_prefix(mut name: String) -> String {
  143. if name.starts_with("r#") {
  144. name.replace_range(0..2, "");
  145. }
  146. name
  147. }
  148. }
  149. mod field_info {
  150. use crate::props::type_from_inside_option;
  151. use proc_macro2::TokenStream;
  152. use quote::quote;
  153. use syn::spanned::Spanned;
  154. use syn::Expr;
  155. use syn::{parse::Error, punctuated::Punctuated};
  156. use super::util::{
  157. expr_to_single_string, ident_to_type, path_to_single_string, strip_raw_ident_prefix,
  158. };
  159. #[derive(Debug)]
  160. pub struct FieldInfo<'a> {
  161. pub ordinal: usize,
  162. pub name: &'a syn::Ident,
  163. pub generic_ident: syn::Ident,
  164. pub ty: &'a syn::Type,
  165. pub builder_attr: FieldBuilderAttr,
  166. }
  167. impl<'a> FieldInfo<'a> {
  168. pub fn new(
  169. ordinal: usize,
  170. field: &syn::Field,
  171. field_defaults: FieldBuilderAttr,
  172. ) -> Result<FieldInfo, Error> {
  173. if let Some(ref name) = field.ident {
  174. let mut builder_attr = field_defaults.with(&field.attrs)?;
  175. // children field is automatically defaulted to None
  176. if name == "children" {
  177. builder_attr.default = Some(
  178. syn::parse(quote!(::core::default::Default::default()).into()).unwrap(),
  179. );
  180. }
  181. // auto detect optional
  182. let strip_option_auto = builder_attr.strip_option
  183. || !builder_attr.ignore_option
  184. && type_from_inside_option(&field.ty, true).is_some();
  185. if !builder_attr.strip_option && strip_option_auto {
  186. builder_attr.strip_option = true;
  187. builder_attr.default = Some(
  188. syn::parse(quote!(::core::default::Default::default()).into()).unwrap(),
  189. );
  190. }
  191. Ok(FieldInfo {
  192. ordinal,
  193. name,
  194. generic_ident: syn::Ident::new(
  195. &format!("__{}", strip_raw_ident_prefix(name.to_string())),
  196. name.span(),
  197. ),
  198. ty: &field.ty,
  199. builder_attr,
  200. })
  201. } else {
  202. Err(Error::new(field.span(), "Nameless field in struct"))
  203. }
  204. }
  205. pub fn generic_ty_param(&self) -> syn::GenericParam {
  206. syn::GenericParam::Type(self.generic_ident.clone().into())
  207. }
  208. pub fn type_ident(&self) -> syn::Type {
  209. ident_to_type(self.generic_ident.clone())
  210. }
  211. pub fn tuplized_type_ty_param(&self) -> syn::Type {
  212. let mut types = syn::punctuated::Punctuated::default();
  213. types.push(self.ty.clone());
  214. types.push_punct(Default::default());
  215. syn::TypeTuple {
  216. paren_token: Default::default(),
  217. elems: types,
  218. }
  219. .into()
  220. }
  221. }
  222. #[derive(Debug, Default, Clone)]
  223. pub struct FieldBuilderAttr {
  224. pub default: Option<syn::Expr>,
  225. pub doc: Option<syn::Expr>,
  226. pub skip: bool,
  227. pub auto_into: bool,
  228. pub strip_option: bool,
  229. pub ignore_option: bool,
  230. }
  231. impl FieldBuilderAttr {
  232. pub fn with(mut self, attrs: &[syn::Attribute]) -> Result<Self, Error> {
  233. let mut skip_tokens = None;
  234. for attr in attrs {
  235. if path_to_single_string(attr.path()).as_deref() != Some("props") {
  236. continue;
  237. }
  238. match &attr.meta {
  239. syn::Meta::List(list) => {
  240. if list.tokens.is_empty() {
  241. continue;
  242. }
  243. }
  244. _ => {
  245. continue;
  246. }
  247. }
  248. let as_expr = attr.parse_args_with(
  249. Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
  250. )?;
  251. for expr in as_expr.into_iter() {
  252. self.apply_meta(expr)?;
  253. }
  254. // Stash its span for later (we don’t yet know if it’ll be an error)
  255. if self.skip && skip_tokens.is_none() {
  256. skip_tokens = Some(attr.meta.clone());
  257. }
  258. }
  259. if self.skip && self.default.is_none() {
  260. return Err(Error::new_spanned(
  261. skip_tokens.unwrap(),
  262. "#[props(skip)] must be accompanied by default or default_code",
  263. ));
  264. }
  265. Ok(self)
  266. }
  267. pub fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
  268. match expr {
  269. // #[props(default = "...")]
  270. syn::Expr::Assign(assign) => {
  271. let name = expr_to_single_string(&assign.left)
  272. .ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
  273. match name.as_str() {
  274. "default" => {
  275. self.default = Some(*assign.right);
  276. Ok(())
  277. }
  278. "doc" => {
  279. self.doc = Some(*assign.right);
  280. Ok(())
  281. }
  282. "default_code" => {
  283. if let syn::Expr::Lit(syn::ExprLit {
  284. lit: syn::Lit::Str(code),
  285. ..
  286. }) = *assign.right
  287. {
  288. use std::str::FromStr;
  289. let tokenized_code = TokenStream::from_str(&code.value())?;
  290. self.default = Some(
  291. syn::parse(tokenized_code.into())
  292. .map_err(|e| Error::new_spanned(code, format!("{e}")))?,
  293. );
  294. } else {
  295. return Err(Error::new_spanned(assign.right, "Expected string"));
  296. }
  297. Ok(())
  298. }
  299. _ => Err(Error::new_spanned(
  300. &assign,
  301. format!("Unknown parameter {name:?}"),
  302. )),
  303. }
  304. }
  305. // #[props(default)]
  306. syn::Expr::Path(path) => {
  307. let name = path_to_single_string(&path.path)
  308. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  309. match name.as_str() {
  310. "default" => {
  311. self.default = Some(
  312. syn::parse(quote!(::core::default::Default::default()).into())
  313. .unwrap(),
  314. );
  315. Ok(())
  316. }
  317. "optional" => {
  318. self.default = Some(
  319. syn::parse(quote!(::core::default::Default::default()).into())
  320. .unwrap(),
  321. );
  322. self.strip_option = true;
  323. Ok(())
  324. }
  325. _ => {
  326. macro_rules! handle_fields {
  327. ( $( $flag:expr, $field:ident, $already:expr; )* ) => {
  328. match name.as_str() {
  329. $(
  330. $flag => {
  331. if self.$field {
  332. Err(Error::new(path.span(), concat!("Illegal setting - field is already ", $already)))
  333. } else {
  334. self.$field = true;
  335. Ok(())
  336. }
  337. }
  338. )*
  339. _ => Err(Error::new_spanned(
  340. &path,
  341. format!("Unknown setter parameter {:?}", name),
  342. ))
  343. }
  344. }
  345. }
  346. handle_fields!(
  347. "skip", skip, "skipped";
  348. "into", auto_into, "calling into() on the argument";
  349. "strip_option", strip_option, "putting the argument in Some(...)";
  350. )
  351. }
  352. }
  353. }
  354. syn::Expr::Unary(syn::ExprUnary {
  355. op: syn::UnOp::Not(_),
  356. expr,
  357. ..
  358. }) => {
  359. if let syn::Expr::Path(path) = *expr {
  360. let name = path_to_single_string(&path.path)
  361. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  362. match name.as_str() {
  363. "default" => {
  364. self.default = None;
  365. Ok(())
  366. }
  367. "doc" => {
  368. self.doc = None;
  369. Ok(())
  370. }
  371. "skip" => {
  372. self.skip = false;
  373. Ok(())
  374. }
  375. "auto_into" => {
  376. self.auto_into = false;
  377. Ok(())
  378. }
  379. "optional" => {
  380. self.strip_option = false;
  381. self.ignore_option = true;
  382. Ok(())
  383. }
  384. _ => Err(Error::new_spanned(path, "Unknown setting".to_owned())),
  385. }
  386. } else {
  387. Err(Error::new_spanned(
  388. expr,
  389. "Expected simple identifier".to_owned(),
  390. ))
  391. }
  392. }
  393. _ => Err(Error::new_spanned(expr, "Expected (<...>=<...>)")),
  394. }
  395. }
  396. }
  397. }
  398. fn type_from_inside_option(ty: &syn::Type, check_option_name: bool) -> Option<&syn::Type> {
  399. let path = if let syn::Type::Path(type_path) = ty {
  400. if type_path.qself.is_some() {
  401. return None;
  402. } else {
  403. &type_path.path
  404. }
  405. } else {
  406. return None;
  407. };
  408. let segment = path.segments.last()?;
  409. if check_option_name && segment.ident != "Option" {
  410. return None;
  411. }
  412. let generic_params =
  413. if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments {
  414. generic_params
  415. } else {
  416. return None;
  417. };
  418. if let syn::GenericArgument::Type(ty) = generic_params.args.first()? {
  419. Some(ty)
  420. } else {
  421. None
  422. }
  423. }
  424. mod struct_info {
  425. use proc_macro2::TokenStream;
  426. use quote::quote;
  427. use syn::parse::Error;
  428. use syn::punctuated::Punctuated;
  429. use syn::Expr;
  430. use super::field_info::{FieldBuilderAttr, FieldInfo};
  431. use super::util::{
  432. empty_type, empty_type_tuple, expr_to_single_string, make_punctuated_single,
  433. modify_types_generics_hack, path_to_single_string, strip_raw_ident_prefix, type_tuple,
  434. };
  435. #[derive(Debug)]
  436. pub struct StructInfo<'a> {
  437. pub vis: &'a syn::Visibility,
  438. pub name: &'a syn::Ident,
  439. pub generics: &'a syn::Generics,
  440. pub fields: Vec<FieldInfo<'a>>,
  441. pub builder_attr: TypeBuilderAttr,
  442. pub builder_name: syn::Ident,
  443. pub conversion_helper_trait_name: syn::Ident,
  444. pub core: syn::Ident,
  445. }
  446. impl<'a> StructInfo<'a> {
  447. pub fn included_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
  448. self.fields.iter().filter(|f| !f.builder_attr.skip)
  449. }
  450. pub fn new(
  451. ast: &'a syn::DeriveInput,
  452. fields: impl Iterator<Item = &'a syn::Field>,
  453. ) -> Result<StructInfo<'a>, Error> {
  454. let builder_attr = TypeBuilderAttr::new(&ast.attrs)?;
  455. let builder_name = strip_raw_ident_prefix(format!("{}Builder", ast.ident));
  456. Ok(StructInfo {
  457. vis: &ast.vis,
  458. name: &ast.ident,
  459. generics: &ast.generics,
  460. fields: fields
  461. .enumerate()
  462. .map(|(i, f)| FieldInfo::new(i, f, builder_attr.field_defaults.clone()))
  463. .collect::<Result<_, _>>()?,
  464. builder_attr,
  465. builder_name: syn::Ident::new(&builder_name, ast.ident.span()),
  466. conversion_helper_trait_name: syn::Ident::new(
  467. &format!("{builder_name}_Optional"),
  468. ast.ident.span(),
  469. ),
  470. core: syn::Ident::new(&format!("{builder_name}_core"), ast.ident.span()),
  471. })
  472. }
  473. fn modify_generics<F: FnMut(&mut syn::Generics)>(&self, mut mutator: F) -> syn::Generics {
  474. let mut generics = self.generics.clone();
  475. mutator(&mut generics);
  476. generics
  477. }
  478. pub fn builder_creation_impl(&self) -> Result<TokenStream, Error> {
  479. let StructInfo {
  480. ref vis,
  481. ref name,
  482. ref builder_name,
  483. ..
  484. } = *self;
  485. // we're generating stuff that goes into unsafe code here
  486. // we use the heuristic: are there *any* generic parameters?
  487. // If so, then they might have non-static lifetimes and we can't compare two generic things that *might borrow*
  488. // Therefore, we will generate code that shortcircuits the "comparison" in memoization
  489. let are_there_generics = !self.generics.params.is_empty();
  490. let (impl_generics, ty_generics, where_clause) = self.generics.split_for_impl();
  491. let all_fields_param = syn::GenericParam::Type(
  492. syn::Ident::new("TypedBuilderFields", proc_macro2::Span::call_site()).into(),
  493. );
  494. let b_generics = self.modify_generics(|g| {
  495. g.params.insert(0, all_fields_param.clone());
  496. });
  497. let empties_tuple = type_tuple(self.included_fields().map(|_| empty_type()));
  498. let generics_with_empty = modify_types_generics_hack(&ty_generics, |args| {
  499. args.insert(0, syn::GenericArgument::Type(empties_tuple.clone().into()));
  500. });
  501. let phantom_generics = self.generics.params.iter().filter_map(|param| match param {
  502. syn::GenericParam::Lifetime(lifetime) => {
  503. let lifetime = &lifetime.lifetime;
  504. Some(quote!(::core::marker::PhantomData<&#lifetime ()>))
  505. }
  506. syn::GenericParam::Type(ty) => {
  507. let ty = &ty.ident;
  508. Some(quote!(::core::marker::PhantomData<#ty>))
  509. }
  510. syn::GenericParam::Const(_cnst) => None,
  511. });
  512. let builder_method_doc = match self.builder_attr.builder_method_doc {
  513. Some(ref doc) => quote!(#doc),
  514. None => {
  515. let doc = format!(
  516. "
  517. Create a builder for building `{name}`.
  518. On the builder, call {setters} to set the values of the fields.
  519. Finally, call `.build()` to create the instance of `{name}`.
  520. ",
  521. name = self.name,
  522. setters = {
  523. let mut result = String::new();
  524. let mut is_first = true;
  525. for field in self.included_fields() {
  526. use std::fmt::Write;
  527. if is_first {
  528. is_first = false;
  529. } else {
  530. write!(&mut result, ", ").unwrap();
  531. }
  532. write!(&mut result, "`.{}(...)`", field.name).unwrap();
  533. if field.builder_attr.default.is_some() {
  534. write!(&mut result, "(optional)").unwrap();
  535. }
  536. }
  537. result
  538. }
  539. );
  540. quote!(#doc)
  541. }
  542. };
  543. let builder_type_doc = if self.builder_attr.doc {
  544. match self.builder_attr.builder_type_doc {
  545. Some(ref doc) => quote!(#[doc = #doc]),
  546. None => {
  547. let doc = format!(
  548. "Builder for [`{name}`] instances.\n\nSee [`{name}::builder()`] for more info.",
  549. );
  550. quote!(#[doc = #doc])
  551. }
  552. }
  553. } else {
  554. quote!(#[doc(hidden)])
  555. };
  556. let (b_generics_impl, b_generics_ty, b_generics_where_extras_predicates) =
  557. b_generics.split_for_impl();
  558. let mut b_generics_where: syn::WhereClause = syn::parse2(quote! {
  559. where TypedBuilderFields: Clone
  560. })?;
  561. if let Some(predicates) = b_generics_where_extras_predicates {
  562. b_generics_where
  563. .predicates
  564. .extend(predicates.predicates.clone());
  565. }
  566. let can_memoize = match are_there_generics {
  567. true => quote! { false },
  568. false => quote! { self == other },
  569. };
  570. let is_static = match are_there_generics {
  571. true => quote! { false },
  572. false => quote! { true },
  573. };
  574. Ok(quote! {
  575. impl #impl_generics #name #ty_generics #where_clause {
  576. #[doc = #builder_method_doc]
  577. #[allow(dead_code, clippy::type_complexity)]
  578. #vis fn builder() -> #builder_name #generics_with_empty {
  579. #builder_name {
  580. fields: #empties_tuple,
  581. _phantom: ::core::default::Default::default(),
  582. }
  583. }
  584. }
  585. #[must_use]
  586. #builder_type_doc
  587. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  588. #vis struct #builder_name #b_generics {
  589. fields: #all_fields_param,
  590. _phantom: (#( #phantom_generics ),*),
  591. }
  592. impl #b_generics_impl Clone for #builder_name #b_generics_ty #b_generics_where {
  593. fn clone(&self) -> Self {
  594. Self {
  595. fields: self.fields.clone(),
  596. _phantom: ::core::default::Default::default(),
  597. }
  598. }
  599. }
  600. impl #impl_generics ::dioxus::prelude::Properties for #name #ty_generics
  601. #b_generics_where_extras_predicates
  602. {
  603. type Builder = #builder_name #generics_with_empty;
  604. const IS_STATIC: bool = #is_static;
  605. fn builder() -> Self::Builder {
  606. #name::builder()
  607. }
  608. unsafe fn memoize(&self, other: &Self) -> bool {
  609. #can_memoize
  610. }
  611. }
  612. })
  613. }
  614. // TODO: once the proc-macro crate limitation is lifted, make this an util trait of this
  615. // crate.
  616. pub fn conversion_helper_impl(&self) -> Result<TokenStream, Error> {
  617. let trait_name = &self.conversion_helper_trait_name;
  618. Ok(quote! {
  619. #[doc(hidden)]
  620. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  621. pub trait #trait_name<T> {
  622. fn into_value<F: FnOnce() -> T>(self, default: F) -> T;
  623. }
  624. impl<T> #trait_name<T> for () {
  625. fn into_value<F: FnOnce() -> T>(self, default: F) -> T {
  626. default()
  627. }
  628. }
  629. impl<T> #trait_name<T> for (T,) {
  630. fn into_value<F: FnOnce() -> T>(self, _: F) -> T {
  631. self.0
  632. }
  633. }
  634. })
  635. }
  636. pub fn field_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> {
  637. let FieldInfo {
  638. name: field_name,
  639. ty: field_type,
  640. ..
  641. } = field;
  642. if *field_name == "key" {
  643. return Err(Error::new_spanned(field_name, "Naming a prop `key` is not allowed because the name can conflict with the built in key attribute. See https://dioxuslabs.com/learn/0.4/reference/dynamic_rendering#rendering-lists for more information about keys"));
  644. }
  645. let StructInfo {
  646. ref builder_name, ..
  647. } = *self;
  648. let descructuring = self.included_fields().map(|f| {
  649. if f.ordinal == field.ordinal {
  650. quote!(_)
  651. } else {
  652. let name = f.name;
  653. quote!(#name)
  654. }
  655. });
  656. let reconstructing = self.included_fields().map(|f| f.name);
  657. let mut ty_generics: Vec<syn::GenericArgument> = self
  658. .generics
  659. .params
  660. .iter()
  661. .map(|generic_param| match generic_param {
  662. syn::GenericParam::Type(type_param) => {
  663. let ident = type_param.ident.clone();
  664. syn::parse(quote!(#ident).into()).unwrap()
  665. }
  666. syn::GenericParam::Lifetime(lifetime_def) => {
  667. syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone())
  668. }
  669. syn::GenericParam::Const(const_param) => {
  670. let ident = const_param.ident.clone();
  671. syn::parse(quote!(#ident).into()).unwrap()
  672. }
  673. })
  674. .collect();
  675. let mut target_generics_tuple = empty_type_tuple();
  676. let mut ty_generics_tuple = empty_type_tuple();
  677. let generics = self.modify_generics(|g| {
  678. let index_after_lifetime_in_generics = g
  679. .params
  680. .iter()
  681. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  682. .count();
  683. for f in self.included_fields() {
  684. if f.ordinal == field.ordinal {
  685. ty_generics_tuple.elems.push_value(empty_type());
  686. target_generics_tuple
  687. .elems
  688. .push_value(f.tuplized_type_ty_param());
  689. } else {
  690. g.params
  691. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  692. let generic_argument: syn::Type = f.type_ident();
  693. ty_generics_tuple.elems.push_value(generic_argument.clone());
  694. target_generics_tuple.elems.push_value(generic_argument);
  695. }
  696. ty_generics_tuple.elems.push_punct(Default::default());
  697. target_generics_tuple.elems.push_punct(Default::default());
  698. }
  699. });
  700. let mut target_generics = ty_generics.clone();
  701. let index_after_lifetime_in_generics = target_generics
  702. .iter()
  703. .filter(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
  704. .count();
  705. target_generics.insert(
  706. index_after_lifetime_in_generics,
  707. syn::GenericArgument::Type(target_generics_tuple.into()),
  708. );
  709. ty_generics.insert(
  710. index_after_lifetime_in_generics,
  711. syn::GenericArgument::Type(ty_generics_tuple.into()),
  712. );
  713. let (impl_generics, _, where_clause) = generics.split_for_impl();
  714. let doc = match field.builder_attr.doc {
  715. Some(ref doc) => quote!(#[doc = #doc]),
  716. None => quote!(),
  717. };
  718. let arg_type = field_type;
  719. let (arg_type, arg_expr) =
  720. if field.builder_attr.auto_into || field.builder_attr.strip_option {
  721. (
  722. quote!(impl ::core::convert::Into<#arg_type>),
  723. quote!(#field_name.into()),
  724. )
  725. } else {
  726. (quote!(#arg_type), quote!(#field_name))
  727. };
  728. let repeated_fields_error_type_name = syn::Ident::new(
  729. &format!(
  730. "{}_Error_Repeated_field_{}",
  731. builder_name,
  732. strip_raw_ident_prefix(field_name.to_string())
  733. ),
  734. builder_name.span(),
  735. );
  736. let repeated_fields_error_message = format!("Repeated field {field_name}");
  737. Ok(quote! {
  738. #[allow(dead_code, non_camel_case_types, missing_docs)]
  739. impl #impl_generics #builder_name < #( #ty_generics ),* > #where_clause {
  740. #doc
  741. #[allow(clippy::type_complexity)]
  742. pub fn #field_name (self, #field_name: #arg_type) -> #builder_name < #( #target_generics ),* > {
  743. let #field_name = (#arg_expr,);
  744. let ( #(#descructuring,)* ) = self.fields;
  745. #builder_name {
  746. fields: ( #(#reconstructing,)* ),
  747. _phantom: self._phantom,
  748. }
  749. }
  750. }
  751. #[doc(hidden)]
  752. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  753. pub enum #repeated_fields_error_type_name {}
  754. #[doc(hidden)]
  755. #[allow(dead_code, non_camel_case_types, missing_docs)]
  756. impl #impl_generics #builder_name < #( #target_generics ),* > #where_clause {
  757. #[deprecated(
  758. note = #repeated_fields_error_message
  759. )]
  760. #[allow(clippy::type_complexity)]
  761. pub fn #field_name (self, _: #repeated_fields_error_type_name) -> #builder_name < #( #target_generics ),* > {
  762. self
  763. }
  764. }
  765. })
  766. }
  767. pub fn required_field_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> {
  768. let StructInfo {
  769. ref name,
  770. ref builder_name,
  771. ..
  772. } = self;
  773. let FieldInfo {
  774. name: ref field_name,
  775. ..
  776. } = field;
  777. let mut builder_generics: Vec<syn::GenericArgument> = self
  778. .generics
  779. .params
  780. .iter()
  781. .map(|generic_param| match generic_param {
  782. syn::GenericParam::Type(type_param) => {
  783. let ident = &type_param.ident;
  784. syn::parse(quote!(#ident).into()).unwrap()
  785. }
  786. syn::GenericParam::Lifetime(lifetime_def) => {
  787. syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone())
  788. }
  789. syn::GenericParam::Const(const_param) => {
  790. let ident = &const_param.ident;
  791. syn::parse(quote!(#ident).into()).unwrap()
  792. }
  793. })
  794. .collect();
  795. let mut builder_generics_tuple = empty_type_tuple();
  796. let generics = self.modify_generics(|g| {
  797. let index_after_lifetime_in_generics = g
  798. .params
  799. .iter()
  800. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  801. .count();
  802. for f in self.included_fields() {
  803. if f.builder_attr.default.is_some() {
  804. // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need
  805. // to warn about missing `field` whether or not `f` is set.
  806. assert!(
  807. f.ordinal != field.ordinal,
  808. "`required_field_impl` called for optional field {}",
  809. field.name
  810. );
  811. g.params
  812. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  813. builder_generics_tuple.elems.push_value(f.type_ident());
  814. } else if f.ordinal < field.ordinal {
  815. // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set,
  816. // `f`'s `build` method will warn, since it appears earlier in the argument list.
  817. builder_generics_tuple
  818. .elems
  819. .push_value(f.tuplized_type_ty_param());
  820. } else if f.ordinal == field.ordinal {
  821. builder_generics_tuple.elems.push_value(empty_type());
  822. } else {
  823. // `f` appears later in the argument list after `field`, so if they are both missing we will
  824. // show a warning for `field` and not for `f` - which means this warning should appear whether
  825. // or not `f` is set.
  826. g.params
  827. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  828. builder_generics_tuple.elems.push_value(f.type_ident());
  829. }
  830. builder_generics_tuple.elems.push_punct(Default::default());
  831. }
  832. });
  833. let index_after_lifetime_in_generics = builder_generics
  834. .iter()
  835. .filter(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
  836. .count();
  837. builder_generics.insert(
  838. index_after_lifetime_in_generics,
  839. syn::GenericArgument::Type(builder_generics_tuple.into()),
  840. );
  841. let (impl_generics, _, where_clause) = generics.split_for_impl();
  842. let (_, ty_generics, _) = self.generics.split_for_impl();
  843. let early_build_error_type_name = syn::Ident::new(
  844. &format!(
  845. "{}_Error_Missing_required_field_{}",
  846. builder_name,
  847. strip_raw_ident_prefix(field_name.to_string())
  848. ),
  849. builder_name.span(),
  850. );
  851. let early_build_error_message = format!("Missing required field {field_name}");
  852. Ok(quote! {
  853. #[doc(hidden)]
  854. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  855. pub enum #early_build_error_type_name {}
  856. #[doc(hidden)]
  857. #[allow(dead_code, non_camel_case_types, missing_docs, clippy::panic)]
  858. impl #impl_generics #builder_name < #( #builder_generics ),* > #where_clause {
  859. #[deprecated(
  860. note = #early_build_error_message
  861. )]
  862. pub fn build(self, _: #early_build_error_type_name) -> #name #ty_generics {
  863. panic!();
  864. }
  865. }
  866. })
  867. }
  868. pub fn build_method_impl(&self) -> TokenStream {
  869. let StructInfo {
  870. ref name,
  871. ref builder_name,
  872. ..
  873. } = *self;
  874. let generics = self.modify_generics(|g| {
  875. let index_after_lifetime_in_generics = g
  876. .params
  877. .iter()
  878. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  879. .count();
  880. for field in self.included_fields() {
  881. if field.builder_attr.default.is_some() {
  882. let trait_ref = syn::TraitBound {
  883. paren_token: None,
  884. lifetimes: None,
  885. modifier: syn::TraitBoundModifier::None,
  886. path: syn::PathSegment {
  887. ident: self.conversion_helper_trait_name.clone(),
  888. arguments: syn::PathArguments::AngleBracketed(
  889. syn::AngleBracketedGenericArguments {
  890. colon2_token: None,
  891. lt_token: Default::default(),
  892. args: make_punctuated_single(syn::GenericArgument::Type(
  893. field.ty.clone(),
  894. )),
  895. gt_token: Default::default(),
  896. },
  897. ),
  898. }
  899. .into(),
  900. };
  901. let mut generic_param: syn::TypeParam = field.generic_ident.clone().into();
  902. generic_param.bounds.push(trait_ref.into());
  903. g.params
  904. .insert(index_after_lifetime_in_generics, generic_param.into());
  905. }
  906. }
  907. });
  908. let (impl_generics, _, _) = generics.split_for_impl();
  909. let (_, ty_generics, where_clause) = self.generics.split_for_impl();
  910. let modified_ty_generics = modify_types_generics_hack(&ty_generics, |args| {
  911. args.insert(
  912. 0,
  913. syn::GenericArgument::Type(
  914. type_tuple(self.included_fields().map(|field| {
  915. if field.builder_attr.default.is_some() {
  916. field.type_ident()
  917. } else {
  918. field.tuplized_type_ty_param()
  919. }
  920. }))
  921. .into(),
  922. ),
  923. );
  924. });
  925. let descructuring = self.included_fields().map(|f| f.name);
  926. let helper_trait_name = &self.conversion_helper_trait_name;
  927. // The default of a field can refer to earlier-defined fields, which we handle by
  928. // writing out a bunch of `let` statements first, which can each refer to earlier ones.
  929. // This means that field ordering may actually be significant, which isn’t ideal. We could
  930. // relax that restriction by calculating a DAG of field default dependencies and
  931. // reordering based on that, but for now this much simpler thing is a reasonable approach.
  932. let assignments = self.fields.iter().map(|field| {
  933. let name = &field.name;
  934. if let Some(ref default) = field.builder_attr.default {
  935. if field.builder_attr.skip {
  936. quote!(let #name = #default;)
  937. } else {
  938. quote!(let #name = #helper_trait_name::into_value(#name, || #default);)
  939. }
  940. } else {
  941. quote!(let #name = #name.0;)
  942. }
  943. });
  944. let field_names = self.fields.iter().map(|field| field.name);
  945. let doc = if self.builder_attr.doc {
  946. match self.builder_attr.build_method_doc {
  947. Some(ref doc) => quote!(#[doc = #doc]),
  948. None => {
  949. // I’d prefer “a” or “an” to “its”, but determining which is grammatically
  950. // correct is roughly impossible.
  951. let doc =
  952. format!("Finalise the builder and create its [`{name}`] instance");
  953. quote!(#[doc = #doc])
  954. }
  955. }
  956. } else {
  957. quote!()
  958. };
  959. quote!(
  960. #[allow(dead_code, non_camel_case_types, missing_docs)]
  961. impl #impl_generics #builder_name #modified_ty_generics #where_clause {
  962. #doc
  963. pub fn build(self) -> #name #ty_generics {
  964. let ( #(#descructuring,)* ) = self.fields;
  965. #( #assignments )*
  966. #name {
  967. #( #field_names ),*
  968. }
  969. }
  970. }
  971. )
  972. }
  973. }
  974. #[derive(Debug, Default)]
  975. pub struct TypeBuilderAttr {
  976. /// Whether to show docs for the `TypeBuilder` type (rather than hiding them).
  977. pub doc: bool,
  978. /// Docs on the `Type::builder()` method.
  979. pub builder_method_doc: Option<syn::Expr>,
  980. /// Docs on the `TypeBuilder` type. Specifying this implies `doc`, but you can just specify
  981. /// `doc` instead and a default value will be filled in here.
  982. pub builder_type_doc: Option<syn::Expr>,
  983. /// Docs on the `TypeBuilder.build()` method. Specifying this implies `doc`, but you can just
  984. /// specify `doc` instead and a default value will be filled in here.
  985. pub build_method_doc: Option<syn::Expr>,
  986. pub field_defaults: FieldBuilderAttr,
  987. }
  988. impl TypeBuilderAttr {
  989. pub fn new(attrs: &[syn::Attribute]) -> Result<TypeBuilderAttr, Error> {
  990. let mut result = TypeBuilderAttr::default();
  991. for attr in attrs {
  992. if path_to_single_string(attr.path()).as_deref() != Some("builder") {
  993. continue;
  994. }
  995. match &attr.meta {
  996. syn::Meta::List(list) => {
  997. if list.tokens.is_empty() {
  998. continue;
  999. }
  1000. }
  1001. _ => {
  1002. continue;
  1003. }
  1004. }
  1005. let as_expr = attr.parse_args_with(
  1006. Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
  1007. )?;
  1008. for expr in as_expr.into_iter() {
  1009. result.apply_meta(expr)?;
  1010. }
  1011. }
  1012. Ok(result)
  1013. }
  1014. fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
  1015. match expr {
  1016. syn::Expr::Assign(assign) => {
  1017. let name = expr_to_single_string(&assign.left)
  1018. .ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
  1019. match name.as_str() {
  1020. "builder_method_doc" => {
  1021. self.builder_method_doc = Some(*assign.right);
  1022. Ok(())
  1023. }
  1024. "builder_type_doc" => {
  1025. self.builder_type_doc = Some(*assign.right);
  1026. self.doc = true;
  1027. Ok(())
  1028. }
  1029. "build_method_doc" => {
  1030. self.build_method_doc = Some(*assign.right);
  1031. self.doc = true;
  1032. Ok(())
  1033. }
  1034. _ => Err(Error::new_spanned(
  1035. &assign,
  1036. format!("Unknown parameter {name:?}"),
  1037. )),
  1038. }
  1039. }
  1040. syn::Expr::Path(path) => {
  1041. let name = path_to_single_string(&path.path)
  1042. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  1043. match name.as_str() {
  1044. "doc" => {
  1045. self.doc = true;
  1046. Ok(())
  1047. }
  1048. _ => Err(Error::new_spanned(
  1049. &path,
  1050. format!("Unknown parameter {name:?}"),
  1051. )),
  1052. }
  1053. }
  1054. syn::Expr::Call(call) => {
  1055. let subsetting_name = if let syn::Expr::Path(path) = &*call.func {
  1056. path_to_single_string(&path.path)
  1057. } else {
  1058. None
  1059. }
  1060. .ok_or_else(|| {
  1061. let call_func = &call.func;
  1062. let call_func = quote!(#call_func);
  1063. Error::new_spanned(
  1064. &call.func,
  1065. format!("Illegal builder setting group {call_func}"),
  1066. )
  1067. })?;
  1068. match subsetting_name.as_str() {
  1069. "field_defaults" => {
  1070. for arg in call.args {
  1071. self.field_defaults.apply_meta(arg)?;
  1072. }
  1073. Ok(())
  1074. }
  1075. _ => Err(Error::new_spanned(
  1076. &call.func,
  1077. format!("Illegal builder setting group name {subsetting_name}"),
  1078. )),
  1079. }
  1080. }
  1081. _ => Err(Error::new_spanned(expr, "Expected (<...>=<...>)")),
  1082. }
  1083. }
  1084. }
  1085. }