mod.rs 48 KB

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