mod.rs 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574
  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. //! - [x] Automatically implement Into<Option> on the setters (IE the strip setter option)
  7. //! - [x] Automatically implement a default of none for optional fields (those explicitly wrapped with Option<T>)
  8. use proc_macro2::TokenStream;
  9. use syn::punctuated::Punctuated;
  10. use syn::spanned::Spanned;
  11. use syn::{parse::Error, PathArguments};
  12. use quote::quote;
  13. use syn::{parse_quote, Type};
  14. pub fn impl_my_derive(ast: &syn::DeriveInput) -> Result<TokenStream, Error> {
  15. let data = match &ast.data {
  16. syn::Data::Struct(data) => match &data.fields {
  17. syn::Fields::Named(fields) => {
  18. let struct_info = struct_info::StructInfo::new(ast, fields.named.iter())?;
  19. let builder_creation = struct_info.builder_creation_impl()?;
  20. let conversion_helper = struct_info.conversion_helper_impl()?;
  21. let fields = struct_info
  22. .included_fields()
  23. .map(|f| struct_info.field_impl(f))
  24. .collect::<Result<Vec<_>, _>>()?;
  25. let extends = struct_info
  26. .extend_fields()
  27. .map(|f| struct_info.extends_impl(f))
  28. .collect::<Result<Vec<_>, _>>()?;
  29. let fields = quote!(#(#fields)*).into_iter();
  30. let required_fields = struct_info
  31. .included_fields()
  32. .filter(|f| f.builder_attr.default.is_none())
  33. .map(|f| struct_info.required_field_impl(f))
  34. .collect::<Result<Vec<_>, _>>()?;
  35. let build_method = struct_info.build_method_impl();
  36. quote! {
  37. #builder_creation
  38. #conversion_helper
  39. #( #fields )*
  40. #( #extends )*
  41. #( #required_fields )*
  42. #build_method
  43. }
  44. }
  45. syn::Fields::Unnamed(_) => {
  46. return Err(Error::new(
  47. ast.span(),
  48. "Props is not supported for tuple structs",
  49. ))
  50. }
  51. syn::Fields::Unit => {
  52. return Err(Error::new(
  53. ast.span(),
  54. "Props is not supported for unit structs",
  55. ))
  56. }
  57. },
  58. syn::Data::Enum(_) => {
  59. return Err(Error::new(ast.span(), "Props is not supported for enums"))
  60. }
  61. syn::Data::Union(_) => {
  62. return Err(Error::new(ast.span(), "Props is not supported for unions"))
  63. }
  64. };
  65. Ok(data)
  66. }
  67. mod util {
  68. use quote::ToTokens;
  69. pub fn path_to_single_string(path: &syn::Path) -> Option<String> {
  70. if path.leading_colon.is_some() {
  71. return None;
  72. }
  73. let mut it = path.segments.iter();
  74. let segment = it.next()?;
  75. if it.next().is_some() {
  76. // Multipart path
  77. return None;
  78. }
  79. if segment.arguments != syn::PathArguments::None {
  80. return None;
  81. }
  82. Some(segment.ident.to_string())
  83. }
  84. pub fn expr_to_single_string(expr: &syn::Expr) -> Option<String> {
  85. if let syn::Expr::Path(path) = expr {
  86. path_to_single_string(&path.path)
  87. } else {
  88. None
  89. }
  90. }
  91. pub fn ident_to_type(ident: syn::Ident) -> syn::Type {
  92. let mut path = syn::Path {
  93. leading_colon: None,
  94. segments: Default::default(),
  95. };
  96. path.segments.push(syn::PathSegment {
  97. ident,
  98. arguments: Default::default(),
  99. });
  100. syn::Type::Path(syn::TypePath { qself: None, path })
  101. }
  102. pub fn empty_type() -> syn::Type {
  103. syn::TypeTuple {
  104. paren_token: Default::default(),
  105. elems: Default::default(),
  106. }
  107. .into()
  108. }
  109. pub fn type_tuple(elems: impl Iterator<Item = syn::Type>) -> syn::TypeTuple {
  110. let mut result = syn::TypeTuple {
  111. paren_token: Default::default(),
  112. elems: elems.collect(),
  113. };
  114. if !result.elems.empty_or_trailing() {
  115. result.elems.push_punct(Default::default());
  116. }
  117. result
  118. }
  119. pub fn empty_type_tuple() -> syn::TypeTuple {
  120. syn::TypeTuple {
  121. paren_token: Default::default(),
  122. elems: Default::default(),
  123. }
  124. }
  125. pub fn make_punctuated_single<T, P: Default>(value: T) -> syn::punctuated::Punctuated<T, P> {
  126. let mut punctuated = syn::punctuated::Punctuated::new();
  127. punctuated.push(value);
  128. punctuated
  129. }
  130. pub fn modify_types_generics_hack<F>(
  131. ty_generics: &syn::TypeGenerics,
  132. mut mutator: F,
  133. ) -> syn::AngleBracketedGenericArguments
  134. where
  135. F: FnMut(&mut syn::punctuated::Punctuated<syn::GenericArgument, syn::token::Comma>),
  136. {
  137. let mut abga: syn::AngleBracketedGenericArguments =
  138. syn::parse(ty_generics.clone().into_token_stream().into()).unwrap_or_else(|_| {
  139. syn::AngleBracketedGenericArguments {
  140. colon2_token: None,
  141. lt_token: Default::default(),
  142. args: Default::default(),
  143. gt_token: Default::default(),
  144. }
  145. });
  146. mutator(&mut abga.args);
  147. abga
  148. }
  149. pub fn strip_raw_ident_prefix(mut name: String) -> String {
  150. if name.starts_with("r#") {
  151. name.replace_range(0..2, "");
  152. }
  153. name
  154. }
  155. }
  156. mod field_info {
  157. use crate::props::type_from_inside_option;
  158. use proc_macro2::TokenStream;
  159. use quote::quote;
  160. use syn::spanned::Spanned;
  161. use syn::{parse::Error, punctuated::Punctuated};
  162. use syn::{parse_quote, Expr, Path};
  163. use super::util::{
  164. expr_to_single_string, ident_to_type, path_to_single_string, strip_raw_ident_prefix,
  165. };
  166. #[derive(Debug)]
  167. pub struct FieldInfo<'a> {
  168. pub ordinal: usize,
  169. pub name: &'a syn::Ident,
  170. pub generic_ident: syn::Ident,
  171. pub ty: &'a syn::Type,
  172. pub builder_attr: FieldBuilderAttr,
  173. }
  174. impl<'a> FieldInfo<'a> {
  175. pub fn new(
  176. ordinal: usize,
  177. field: &syn::Field,
  178. field_defaults: FieldBuilderAttr,
  179. ) -> Result<FieldInfo, Error> {
  180. if let Some(ref name) = field.ident {
  181. let mut builder_attr = field_defaults.with(&field.attrs)?;
  182. // children field is automatically defaulted to None
  183. if name == "children" {
  184. builder_attr.default = Some(
  185. syn::parse(quote!(::core::default::Default::default()).into()).unwrap(),
  186. );
  187. }
  188. // String fields automatically use impl Display
  189. if field.ty == parse_quote!(::std::string::String)
  190. || field.ty == parse_quote!(std::string::String)
  191. || field.ty == parse_quote!(string::String)
  192. || field.ty == parse_quote!(String)
  193. {
  194. builder_attr.from_displayable = true;
  195. }
  196. // extended field is automatically empty
  197. if !builder_attr.extends.is_empty() {
  198. builder_attr.default = Some(
  199. syn::parse(quote!(::core::default::Default::default()).into()).unwrap(),
  200. );
  201. }
  202. // auto detect optional
  203. let strip_option_auto = builder_attr.strip_option
  204. || !builder_attr.ignore_option
  205. && type_from_inside_option(&field.ty, true).is_some();
  206. if !builder_attr.strip_option && strip_option_auto {
  207. builder_attr.strip_option = true;
  208. builder_attr.default = Some(
  209. syn::parse(quote!(::core::default::Default::default()).into()).unwrap(),
  210. );
  211. }
  212. Ok(FieldInfo {
  213. ordinal,
  214. name,
  215. generic_ident: syn::Ident::new(
  216. &format!("__{}", strip_raw_ident_prefix(name.to_string())),
  217. name.span(),
  218. ),
  219. ty: &field.ty,
  220. builder_attr,
  221. })
  222. } else {
  223. Err(Error::new(field.span(), "Nameless field in struct"))
  224. }
  225. }
  226. pub fn generic_ty_param(&self) -> syn::GenericParam {
  227. syn::GenericParam::Type(self.generic_ident.clone().into())
  228. }
  229. pub fn type_ident(&self) -> syn::Type {
  230. ident_to_type(self.generic_ident.clone())
  231. }
  232. pub fn tuplized_type_ty_param(&self) -> syn::Type {
  233. let mut types = syn::punctuated::Punctuated::default();
  234. types.push(self.ty.clone());
  235. types.push_punct(Default::default());
  236. syn::TypeTuple {
  237. paren_token: Default::default(),
  238. elems: types,
  239. }
  240. .into()
  241. }
  242. }
  243. #[derive(Debug, Default, Clone)]
  244. pub struct FieldBuilderAttr {
  245. pub default: Option<syn::Expr>,
  246. pub doc: Option<syn::Expr>,
  247. pub skip: bool,
  248. pub auto_into: bool,
  249. pub from_displayable: bool,
  250. pub strip_option: bool,
  251. pub ignore_option: bool,
  252. pub extends: Vec<Path>,
  253. }
  254. impl FieldBuilderAttr {
  255. pub fn with(mut self, attrs: &[syn::Attribute]) -> Result<Self, Error> {
  256. let mut skip_tokens = None;
  257. for attr in attrs {
  258. if path_to_single_string(attr.path()).as_deref() != Some("props") {
  259. continue;
  260. }
  261. match &attr.meta {
  262. syn::Meta::List(list) => {
  263. if list.tokens.is_empty() {
  264. continue;
  265. }
  266. }
  267. _ => {
  268. continue;
  269. }
  270. }
  271. let as_expr = attr.parse_args_with(
  272. Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
  273. )?;
  274. for expr in as_expr.into_iter() {
  275. self.apply_meta(expr)?;
  276. }
  277. // Stash its span for later (we don’t yet know if it’ll be an error)
  278. if self.skip && skip_tokens.is_none() {
  279. skip_tokens = Some(attr.meta.clone());
  280. }
  281. }
  282. if self.skip && self.default.is_none() {
  283. return Err(Error::new_spanned(
  284. skip_tokens.unwrap(),
  285. "#[props(skip)] must be accompanied by default or default_code",
  286. ));
  287. }
  288. Ok(self)
  289. }
  290. pub fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
  291. match expr {
  292. // #[props(default = "...")]
  293. syn::Expr::Assign(assign) => {
  294. let name = expr_to_single_string(&assign.left)
  295. .ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
  296. match name.as_str() {
  297. "extends" => {
  298. if let syn::Expr::Path(path) = *assign.right {
  299. self.extends.push(path.path);
  300. Ok(())
  301. } else {
  302. Err(Error::new_spanned(
  303. assign.right,
  304. "Expected simple identifier",
  305. ))
  306. }
  307. }
  308. "default" => {
  309. self.default = Some(*assign.right);
  310. Ok(())
  311. }
  312. "doc" => {
  313. self.doc = Some(*assign.right);
  314. Ok(())
  315. }
  316. "default_code" => {
  317. if let syn::Expr::Lit(syn::ExprLit {
  318. lit: syn::Lit::Str(code),
  319. ..
  320. }) = *assign.right
  321. {
  322. use std::str::FromStr;
  323. let tokenized_code = TokenStream::from_str(&code.value())?;
  324. self.default = Some(
  325. syn::parse(tokenized_code.into())
  326. .map_err(|e| Error::new_spanned(code, format!("{e}")))?,
  327. );
  328. } else {
  329. return Err(Error::new_spanned(assign.right, "Expected string"));
  330. }
  331. Ok(())
  332. }
  333. _ => Err(Error::new_spanned(
  334. &assign,
  335. format!("Unknown parameter {name:?}"),
  336. )),
  337. }
  338. }
  339. // #[props(default)]
  340. syn::Expr::Path(path) => {
  341. let name = path_to_single_string(&path.path)
  342. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  343. match name.as_str() {
  344. "default" => {
  345. self.default = Some(
  346. syn::parse(quote!(::core::default::Default::default()).into())
  347. .unwrap(),
  348. );
  349. Ok(())
  350. }
  351. "optional" => {
  352. self.default = Some(
  353. syn::parse(quote!(::core::default::Default::default()).into())
  354. .unwrap(),
  355. );
  356. self.strip_option = true;
  357. Ok(())
  358. }
  359. "extend" => {
  360. self.extends.push(path.path);
  361. Ok(())
  362. }
  363. _ => {
  364. macro_rules! handle_fields {
  365. ( $( $flag:expr, $field:ident, $already:expr; )* ) => {
  366. match name.as_str() {
  367. $(
  368. $flag => {
  369. if self.$field {
  370. Err(Error::new(path.span(), concat!("Illegal setting - field is already ", $already)))
  371. } else {
  372. self.$field = true;
  373. Ok(())
  374. }
  375. }
  376. )*
  377. _ => Err(Error::new_spanned(
  378. &path,
  379. format!("Unknown setter parameter {:?}", name),
  380. ))
  381. }
  382. }
  383. }
  384. handle_fields!(
  385. "skip", skip, "skipped";
  386. "into", auto_into, "calling into() on the argument";
  387. "displayable", from_displayable, "calling to_string() on the argument";
  388. "strip_option", strip_option, "putting the argument in Some(...)";
  389. )
  390. }
  391. }
  392. }
  393. syn::Expr::Unary(syn::ExprUnary {
  394. op: syn::UnOp::Not(_),
  395. expr,
  396. ..
  397. }) => {
  398. if let syn::Expr::Path(path) = *expr {
  399. let name = path_to_single_string(&path.path)
  400. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  401. match name.as_str() {
  402. "default" => {
  403. self.default = None;
  404. Ok(())
  405. }
  406. "doc" => {
  407. self.doc = None;
  408. Ok(())
  409. }
  410. "skip" => {
  411. self.skip = false;
  412. Ok(())
  413. }
  414. "auto_into" => {
  415. self.auto_into = false;
  416. Ok(())
  417. }
  418. "displayable" => {
  419. self.from_displayable = false;
  420. Ok(())
  421. }
  422. "optional" => {
  423. self.strip_option = false;
  424. self.ignore_option = true;
  425. Ok(())
  426. }
  427. _ => Err(Error::new_spanned(path, "Unknown setting".to_owned())),
  428. }
  429. } else {
  430. Err(Error::new_spanned(
  431. expr,
  432. "Expected simple identifier".to_owned(),
  433. ))
  434. }
  435. }
  436. _ => Err(Error::new_spanned(expr, "Expected (<...>=<...>)")),
  437. }
  438. }
  439. }
  440. }
  441. fn type_from_inside_option(ty: &syn::Type, check_option_name: bool) -> Option<&syn::Type> {
  442. let path = if let syn::Type::Path(type_path) = ty {
  443. if type_path.qself.is_some() {
  444. return None;
  445. } else {
  446. &type_path.path
  447. }
  448. } else {
  449. return None;
  450. };
  451. let segment = path.segments.last()?;
  452. if check_option_name && segment.ident != "Option" {
  453. return None;
  454. }
  455. let generic_params =
  456. if let syn::PathArguments::AngleBracketed(generic_params) = &segment.arguments {
  457. generic_params
  458. } else {
  459. return None;
  460. };
  461. if let syn::GenericArgument::Type(ty) = generic_params.args.first()? {
  462. Some(ty)
  463. } else {
  464. None
  465. }
  466. }
  467. mod struct_info {
  468. use convert_case::{Case, Casing};
  469. use proc_macro2::TokenStream;
  470. use quote::quote;
  471. use syn::parse::Error;
  472. use syn::punctuated::Punctuated;
  473. use syn::spanned::Spanned;
  474. use syn::{Expr, Ident};
  475. use super::field_info::{FieldBuilderAttr, FieldInfo};
  476. use super::looks_like_signal_type;
  477. use super::util::{
  478. empty_type, empty_type_tuple, expr_to_single_string, make_punctuated_single,
  479. modify_types_generics_hack, path_to_single_string, strip_raw_ident_prefix, type_tuple,
  480. };
  481. #[derive(Debug)]
  482. pub struct StructInfo<'a> {
  483. pub vis: &'a syn::Visibility,
  484. pub name: &'a syn::Ident,
  485. pub generics: &'a syn::Generics,
  486. pub fields: Vec<FieldInfo<'a>>,
  487. pub builder_attr: TypeBuilderAttr,
  488. pub builder_name: syn::Ident,
  489. pub conversion_helper_trait_name: syn::Ident,
  490. pub core: syn::Ident,
  491. }
  492. impl<'a> StructInfo<'a> {
  493. pub fn included_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
  494. self.fields
  495. .iter()
  496. .filter(|f| !f.builder_attr.skip && f.builder_attr.extends.is_empty())
  497. }
  498. pub fn extend_fields(&self) -> impl Iterator<Item = &FieldInfo<'a>> {
  499. self.fields
  500. .iter()
  501. .filter(|f| !f.builder_attr.extends.is_empty())
  502. }
  503. pub fn new(
  504. ast: &'a syn::DeriveInput,
  505. fields: impl Iterator<Item = &'a syn::Field>,
  506. ) -> Result<StructInfo<'a>, Error> {
  507. let builder_attr = TypeBuilderAttr::new(&ast.attrs)?;
  508. let builder_name = strip_raw_ident_prefix(format!("{}Builder", ast.ident));
  509. Ok(StructInfo {
  510. vis: &ast.vis,
  511. name: &ast.ident,
  512. generics: &ast.generics,
  513. fields: fields
  514. .enumerate()
  515. .map(|(i, f)| FieldInfo::new(i, f, builder_attr.field_defaults.clone()))
  516. .collect::<Result<_, _>>()?,
  517. builder_attr,
  518. builder_name: syn::Ident::new(&builder_name, ast.ident.span()),
  519. conversion_helper_trait_name: syn::Ident::new(
  520. &format!("{builder_name}_Optional"),
  521. ast.ident.span(),
  522. ),
  523. core: syn::Ident::new(&format!("{builder_name}_core"), ast.ident.span()),
  524. })
  525. }
  526. fn modify_generics<F: FnMut(&mut syn::Generics)>(&self, mut mutator: F) -> syn::Generics {
  527. let mut generics = self.generics.clone();
  528. mutator(&mut generics);
  529. generics
  530. }
  531. fn has_signal_fields(&self) -> bool {
  532. self.fields.iter().any(|f| looks_like_signal_type(f.ty))
  533. }
  534. fn memoize_impl(&self) -> Result<TokenStream, Error> {
  535. // First check if there are any ReadOnlySignal fields, if there are not, we can just use the partialEq impl
  536. let has_signal_fields = self.has_signal_fields();
  537. if has_signal_fields {
  538. let signal_fields: Vec<_> = self
  539. .included_fields()
  540. .filter(|f| looks_like_signal_type(f.ty))
  541. .map(|f| {
  542. let name = f.name;
  543. quote!(#name)
  544. })
  545. .collect();
  546. Ok(quote! {
  547. // First check if the fields are equal
  548. let exactly_equal = self == new;
  549. if exactly_equal {
  550. return true;
  551. }
  552. // If they are not, move over the signal fields and check if they are equal
  553. #(
  554. let mut #signal_fields = self.#signal_fields;
  555. self.#signal_fields = new.#signal_fields;
  556. )*
  557. // Then check if the fields are equal again
  558. let non_signal_fields_equal = self == new;
  559. // If they are not equal, we still need to rerun the component
  560. if !non_signal_fields_equal {
  561. return false;
  562. }
  563. trait NonPartialEq: Sized {
  564. fn compare(&self, other: &Self) -> bool;
  565. }
  566. impl<T> NonPartialEq for &&T {
  567. fn compare(&self, other: &Self) -> bool {
  568. false
  569. }
  570. }
  571. trait CanPartialEq: PartialEq {
  572. fn compare(&self, other: &Self) -> bool;
  573. }
  574. impl<T: PartialEq> CanPartialEq for T {
  575. fn compare(&self, other: &Self) -> bool {
  576. self == other
  577. }
  578. }
  579. // If they are equal, we don't need to rerun the component we can just update the existing signals
  580. #(
  581. // Try to memo the signal
  582. let field_eq = {
  583. let old_value: &_ = &*#signal_fields.peek();
  584. let new_value: &_ = &*new.#signal_fields.peek();
  585. (&old_value).compare(&&new_value)
  586. };
  587. if !field_eq {
  588. (#signal_fields).__set(new.#signal_fields.__take());
  589. }
  590. // Move the old value back
  591. self.#signal_fields = #signal_fields;
  592. )*
  593. true
  594. })
  595. } else {
  596. Ok(quote! {
  597. self == new
  598. })
  599. }
  600. }
  601. pub fn builder_creation_impl(&self) -> Result<TokenStream, Error> {
  602. let StructInfo {
  603. ref vis,
  604. ref name,
  605. ref builder_name,
  606. ..
  607. } = *self;
  608. let generics = self.generics.clone();
  609. let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
  610. let (_, b_initial_generics, _) = self.generics.split_for_impl();
  611. let all_fields_param = syn::GenericParam::Type(
  612. syn::Ident::new("TypedBuilderFields", proc_macro2::Span::call_site()).into(),
  613. );
  614. let b_generics = self.modify_generics(|g| {
  615. g.params.insert(0, all_fields_param.clone());
  616. });
  617. let empties_tuple = type_tuple(self.included_fields().map(|_| empty_type()));
  618. let generics_with_empty = modify_types_generics_hack(&b_initial_generics, |args| {
  619. args.insert(0, syn::GenericArgument::Type(empties_tuple.clone().into()));
  620. });
  621. let phantom_generics = self.generics.params.iter().filter_map(|param| match param {
  622. syn::GenericParam::Lifetime(lifetime) => {
  623. let lifetime = &lifetime.lifetime;
  624. Some(quote!(::core::marker::PhantomData<&#lifetime ()>))
  625. }
  626. syn::GenericParam::Type(ty) => {
  627. let ty = &ty.ident;
  628. Some(quote!(::core::marker::PhantomData<#ty>))
  629. }
  630. syn::GenericParam::Const(_cnst) => None,
  631. });
  632. let builder_method_doc = match self.builder_attr.builder_method_doc {
  633. Some(ref doc) => quote!(#doc),
  634. None => {
  635. let doc = format!(
  636. "
  637. Create a builder for building `{name}`.
  638. On the builder, call {setters} to set the values of the fields.
  639. Finally, call `.build()` to create the instance of `{name}`.
  640. ",
  641. name = self.name,
  642. setters = {
  643. let mut result = String::new();
  644. let mut is_first = true;
  645. for field in self.included_fields() {
  646. use std::fmt::Write;
  647. if is_first {
  648. is_first = false;
  649. } else {
  650. write!(&mut result, ", ").unwrap();
  651. }
  652. write!(&mut result, "`.{}(...)`", field.name).unwrap();
  653. if field.builder_attr.default.is_some() {
  654. write!(&mut result, "(optional)").unwrap();
  655. }
  656. }
  657. result
  658. }
  659. );
  660. quote!(#doc)
  661. }
  662. };
  663. let builder_type_doc = if self.builder_attr.doc {
  664. match self.builder_attr.builder_type_doc {
  665. Some(ref doc) => quote!(#[doc = #doc]),
  666. None => {
  667. let doc = format!(
  668. "Builder for [`{name}`] instances.\n\nSee [`{name}::builder()`] for more info.",
  669. );
  670. quote!(#[doc = #doc])
  671. }
  672. }
  673. } else {
  674. quote!(#[doc(hidden)])
  675. };
  676. let (_, _, b_generics_where_extras_predicates) = b_generics.split_for_impl();
  677. let mut b_generics_where: syn::WhereClause = syn::parse2(quote! {
  678. where TypedBuilderFields: Clone
  679. })?;
  680. if let Some(predicates) = b_generics_where_extras_predicates {
  681. b_generics_where
  682. .predicates
  683. .extend(predicates.predicates.clone());
  684. }
  685. let memoize = self.memoize_impl()?;
  686. let global_fields = self
  687. .extend_fields()
  688. .map(|f| {
  689. let name = f.name;
  690. let ty = f.ty;
  691. quote!(#name: #ty)
  692. })
  693. .chain(self.has_signal_fields().then(|| quote!(owner: Owner)));
  694. let global_fields_value = self
  695. .extend_fields()
  696. .map(|f| {
  697. let name = f.name;
  698. quote!(#name: Vec::new())
  699. })
  700. .chain(
  701. self.has_signal_fields()
  702. .then(|| quote!(owner: Owner::default())),
  703. );
  704. Ok(quote! {
  705. impl #impl_generics #name #ty_generics #where_clause {
  706. #[doc = #builder_method_doc]
  707. #[allow(dead_code, clippy::type_complexity)]
  708. #vis fn builder() -> #builder_name #generics_with_empty {
  709. #builder_name {
  710. #(#global_fields_value,)*
  711. fields: #empties_tuple,
  712. _phantom: ::core::default::Default::default(),
  713. }
  714. }
  715. }
  716. #[must_use]
  717. #builder_type_doc
  718. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  719. #vis struct #builder_name #b_generics {
  720. #(#global_fields,)*
  721. fields: #all_fields_param,
  722. _phantom: (#( #phantom_generics ),*),
  723. }
  724. impl #impl_generics dioxus_core::prelude::Properties for #name #ty_generics
  725. #b_generics_where_extras_predicates
  726. {
  727. type Builder = #builder_name #generics_with_empty;
  728. fn builder() -> Self::Builder {
  729. #name::builder()
  730. }
  731. fn memoize(&mut self, new: &Self) -> bool {
  732. #memoize
  733. }
  734. }
  735. })
  736. }
  737. // TODO: once the proc-macro crate limitation is lifted, make this an util trait of this
  738. // crate.
  739. pub fn conversion_helper_impl(&self) -> Result<TokenStream, Error> {
  740. let trait_name = &self.conversion_helper_trait_name;
  741. Ok(quote! {
  742. #[doc(hidden)]
  743. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  744. pub trait #trait_name<T> {
  745. fn into_value<F: FnOnce() -> T>(self, default: F) -> T;
  746. }
  747. impl<T> #trait_name<T> for () {
  748. fn into_value<F: FnOnce() -> T>(self, default: F) -> T {
  749. default()
  750. }
  751. }
  752. impl<T> #trait_name<T> for (T,) {
  753. fn into_value<F: FnOnce() -> T>(self, _: F) -> T {
  754. self.0
  755. }
  756. }
  757. })
  758. }
  759. pub fn extends_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> {
  760. let StructInfo {
  761. ref builder_name, ..
  762. } = *self;
  763. let field_name = field.name;
  764. let descructuring = self.included_fields().map(|f| {
  765. if f.ordinal == field.ordinal {
  766. quote!(_)
  767. } else {
  768. let name = f.name;
  769. quote!(#name)
  770. }
  771. });
  772. let reconstructing = self.included_fields().map(|f| f.name);
  773. let mut ty_generics: Vec<syn::GenericArgument> = self
  774. .generics
  775. .params
  776. .iter()
  777. .map(|generic_param| match generic_param {
  778. syn::GenericParam::Type(type_param) => {
  779. let ident = type_param.ident.clone();
  780. syn::parse(quote!(#ident).into()).unwrap()
  781. }
  782. syn::GenericParam::Lifetime(lifetime_def) => {
  783. syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone())
  784. }
  785. syn::GenericParam::Const(const_param) => {
  786. let ident = const_param.ident.clone();
  787. syn::parse(quote!(#ident).into()).unwrap()
  788. }
  789. })
  790. .collect();
  791. let mut target_generics_tuple = empty_type_tuple();
  792. let mut ty_generics_tuple = empty_type_tuple();
  793. let generics = self.modify_generics(|g| {
  794. let index_after_lifetime_in_generics = g
  795. .params
  796. .iter()
  797. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  798. .count();
  799. for f in self.included_fields() {
  800. if f.ordinal == field.ordinal {
  801. ty_generics_tuple.elems.push_value(empty_type());
  802. target_generics_tuple
  803. .elems
  804. .push_value(f.tuplized_type_ty_param());
  805. } else {
  806. g.params
  807. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  808. let generic_argument: syn::Type = f.type_ident();
  809. ty_generics_tuple.elems.push_value(generic_argument.clone());
  810. target_generics_tuple.elems.push_value(generic_argument);
  811. }
  812. ty_generics_tuple.elems.push_punct(Default::default());
  813. target_generics_tuple.elems.push_punct(Default::default());
  814. }
  815. });
  816. let mut target_generics = ty_generics.clone();
  817. let index_after_lifetime_in_generics = target_generics
  818. .iter()
  819. .filter(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
  820. .count();
  821. target_generics.insert(
  822. index_after_lifetime_in_generics,
  823. syn::GenericArgument::Type(target_generics_tuple.into()),
  824. );
  825. ty_generics.insert(
  826. index_after_lifetime_in_generics,
  827. syn::GenericArgument::Type(ty_generics_tuple.into()),
  828. );
  829. let (impl_generics, _, where_clause) = generics.split_for_impl();
  830. let forward_extended_fields = self.extend_fields().map(|f| {
  831. let name = f.name;
  832. quote!(#name: self.#name)
  833. });
  834. let extends_impl = field.builder_attr.extends.iter().map(|path| {
  835. let name_str = path_to_single_string(path).unwrap();
  836. let camel_name = name_str.to_case(Case::UpperCamel);
  837. let marker_name = Ident::new(
  838. format!("{}Extension", &camel_name).as_str(),
  839. path.span(),
  840. );
  841. quote! {
  842. #[allow(dead_code, non_camel_case_types, missing_docs)]
  843. impl #impl_generics dioxus_elements::extensions::#marker_name for #builder_name < #( #ty_generics ),* > #where_clause {}
  844. }
  845. });
  846. Ok(quote! {
  847. #[allow(dead_code, non_camel_case_types, missing_docs)]
  848. impl #impl_generics dioxus_core::prelude::HasAttributes for #builder_name < #( #ty_generics ),* > #where_clause {
  849. fn push_attribute(
  850. mut self,
  851. name: &'static str,
  852. ns: Option<&'static str>,
  853. attr: impl dioxus_core::prelude::IntoAttributeValue,
  854. volatile: bool
  855. ) -> Self {
  856. let ( #(#descructuring,)* ) = self.fields;
  857. self.#field_name.push(
  858. dioxus_core::Attribute::new(
  859. name,
  860. {
  861. use dioxus_core::prelude::IntoAttributeValue;
  862. attr.into_value()
  863. },
  864. ns,
  865. volatile,
  866. )
  867. );
  868. #builder_name {
  869. #(#forward_extended_fields,)*
  870. fields: ( #(#reconstructing,)* ),
  871. _phantom: self._phantom,
  872. }
  873. }
  874. }
  875. #(#extends_impl)*
  876. })
  877. }
  878. pub fn field_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> {
  879. let FieldInfo {
  880. name: field_name, ..
  881. } = field;
  882. if *field_name == "key" {
  883. 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"));
  884. }
  885. let StructInfo {
  886. ref builder_name, ..
  887. } = *self;
  888. let descructuring = self.included_fields().map(|f| {
  889. if f.ordinal == field.ordinal {
  890. quote!(_)
  891. } else {
  892. let name = f.name;
  893. quote!(#name)
  894. }
  895. });
  896. let reconstructing = self.included_fields().map(|f| f.name);
  897. let FieldInfo {
  898. name: field_name,
  899. ty: field_type,
  900. ..
  901. } = field;
  902. // Add the bump lifetime to the generics
  903. let mut ty_generics: Vec<syn::GenericArgument> = self
  904. .generics
  905. .params
  906. .iter()
  907. .map(|generic_param| match generic_param {
  908. syn::GenericParam::Type(type_param) => {
  909. let ident = type_param.ident.clone();
  910. syn::parse(quote!(#ident).into()).unwrap()
  911. }
  912. syn::GenericParam::Lifetime(lifetime_def) => {
  913. syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone())
  914. }
  915. syn::GenericParam::Const(const_param) => {
  916. let ident = const_param.ident.clone();
  917. syn::parse(quote!(#ident).into()).unwrap()
  918. }
  919. })
  920. .collect();
  921. let mut target_generics_tuple = empty_type_tuple();
  922. let mut ty_generics_tuple = empty_type_tuple();
  923. let generics = self.modify_generics(|g| {
  924. let index_after_lifetime_in_generics = g
  925. .params
  926. .iter()
  927. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  928. .count();
  929. for f in self.included_fields() {
  930. if f.ordinal == field.ordinal {
  931. ty_generics_tuple.elems.push_value(empty_type());
  932. target_generics_tuple
  933. .elems
  934. .push_value(f.tuplized_type_ty_param());
  935. } else {
  936. g.params
  937. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  938. let generic_argument: syn::Type = f.type_ident();
  939. ty_generics_tuple.elems.push_value(generic_argument.clone());
  940. target_generics_tuple.elems.push_value(generic_argument);
  941. }
  942. ty_generics_tuple.elems.push_punct(Default::default());
  943. target_generics_tuple.elems.push_punct(Default::default());
  944. }
  945. });
  946. let mut target_generics = ty_generics.clone();
  947. let index_after_lifetime_in_generics = target_generics
  948. .iter()
  949. .filter(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
  950. .count();
  951. target_generics.insert(
  952. index_after_lifetime_in_generics,
  953. syn::GenericArgument::Type(target_generics_tuple.into()),
  954. );
  955. ty_generics.insert(
  956. index_after_lifetime_in_generics,
  957. syn::GenericArgument::Type(ty_generics_tuple.into()),
  958. );
  959. let (impl_generics, _, where_clause) = generics.split_for_impl();
  960. let doc = match field.builder_attr.doc {
  961. Some(ref doc) => quote!(#[doc = #doc]),
  962. None => quote!(),
  963. };
  964. let arg_type = field_type;
  965. // If the field is auto_into, we need to add a generic parameter to the builder for specialization
  966. let mut marker = None;
  967. let (arg_type, arg_expr) = if looks_like_signal_type(arg_type) {
  968. let marker_ident = syn::Ident::new("__Marker", proc_macro2::Span::call_site());
  969. marker = Some(marker_ident.clone());
  970. (
  971. quote!(impl dioxus_core::prelude::SuperInto<#arg_type, #marker_ident>),
  972. // If this looks like a signal type, we automatically convert it with SuperInto and use the props struct as the owner
  973. quote!(with_owner(self.owner.clone(), move || dioxus_core::prelude::SuperInto::super_into(#field_name))),
  974. )
  975. } else if field.builder_attr.auto_into || field.builder_attr.strip_option {
  976. let marker_ident = syn::Ident::new("__Marker", proc_macro2::Span::call_site());
  977. marker = Some(marker_ident.clone());
  978. (
  979. quote!(impl dioxus_core::prelude::SuperInto<#arg_type, #marker_ident>),
  980. quote!(dioxus_core::prelude::SuperInto::super_into(#field_name)),
  981. )
  982. } else if field.builder_attr.from_displayable {
  983. (
  984. quote!(impl ::core::fmt::Display),
  985. quote!(#field_name.to_string()),
  986. )
  987. } else {
  988. (quote!(#arg_type), quote!(#field_name))
  989. };
  990. let repeated_fields_error_type_name = syn::Ident::new(
  991. &format!(
  992. "{}_Error_Repeated_field_{}",
  993. builder_name,
  994. strip_raw_ident_prefix(field_name.to_string())
  995. ),
  996. builder_name.span(),
  997. );
  998. let repeated_fields_error_message = format!("Repeated field {field_name}");
  999. let forward_fields = self
  1000. .extend_fields()
  1001. .map(|f| {
  1002. let name = f.name;
  1003. quote!(#name: self.#name)
  1004. })
  1005. .chain(self.has_signal_fields().then(|| quote!(owner: self.owner)));
  1006. Ok(quote! {
  1007. #[allow(dead_code, non_camel_case_types, missing_docs)]
  1008. impl #impl_generics #builder_name < #( #ty_generics ),* > #where_clause {
  1009. #doc
  1010. #[allow(clippy::type_complexity)]
  1011. pub fn #field_name < #marker > (self, #field_name: #arg_type) -> #builder_name < #( #target_generics ),* > {
  1012. let #field_name = (#arg_expr,);
  1013. let ( #(#descructuring,)* ) = self.fields;
  1014. #builder_name {
  1015. #(#forward_fields,)*
  1016. fields: ( #(#reconstructing,)* ),
  1017. _phantom: self._phantom,
  1018. }
  1019. }
  1020. }
  1021. #[doc(hidden)]
  1022. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  1023. pub enum #repeated_fields_error_type_name {}
  1024. #[doc(hidden)]
  1025. #[allow(dead_code, non_camel_case_types, missing_docs)]
  1026. impl #impl_generics #builder_name < #( #target_generics ),* > #where_clause {
  1027. #[deprecated(
  1028. note = #repeated_fields_error_message
  1029. )]
  1030. #[allow(clippy::type_complexity)]
  1031. pub fn #field_name< #marker > (self, _: #repeated_fields_error_type_name) -> #builder_name < #( #target_generics ),* > {
  1032. self
  1033. }
  1034. }
  1035. })
  1036. }
  1037. pub fn required_field_impl(&self, field: &FieldInfo) -> Result<TokenStream, Error> {
  1038. let StructInfo {
  1039. ref name,
  1040. ref builder_name,
  1041. ..
  1042. } = self;
  1043. let FieldInfo {
  1044. name: ref field_name,
  1045. ..
  1046. } = field;
  1047. // Add a bump lifetime to the generics
  1048. let mut builder_generics: Vec<syn::GenericArgument> = self
  1049. .generics
  1050. .params
  1051. .iter()
  1052. .map(|generic_param| match generic_param {
  1053. syn::GenericParam::Type(type_param) => {
  1054. let ident = &type_param.ident;
  1055. syn::parse(quote!(#ident).into()).unwrap()
  1056. }
  1057. syn::GenericParam::Lifetime(lifetime_def) => {
  1058. syn::GenericArgument::Lifetime(lifetime_def.lifetime.clone())
  1059. }
  1060. syn::GenericParam::Const(const_param) => {
  1061. let ident = &const_param.ident;
  1062. syn::parse(quote!(#ident).into()).unwrap()
  1063. }
  1064. })
  1065. .collect();
  1066. let mut builder_generics_tuple = empty_type_tuple();
  1067. let generics = self.modify_generics(|g| {
  1068. let index_after_lifetime_in_generics = g
  1069. .params
  1070. .iter()
  1071. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  1072. .count();
  1073. for f in self.included_fields() {
  1074. if f.builder_attr.default.is_some() {
  1075. // `f` is not mandatory - it does not have it's own fake `build` method, so `field` will need
  1076. // to warn about missing `field` whether or not `f` is set.
  1077. assert!(
  1078. f.ordinal != field.ordinal,
  1079. "`required_field_impl` called for optional field {}",
  1080. field.name
  1081. );
  1082. g.params
  1083. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  1084. builder_generics_tuple.elems.push_value(f.type_ident());
  1085. } else if f.ordinal < field.ordinal {
  1086. // Only add a `build` method that warns about missing `field` if `f` is set. If `f` is not set,
  1087. // `f`'s `build` method will warn, since it appears earlier in the argument list.
  1088. builder_generics_tuple
  1089. .elems
  1090. .push_value(f.tuplized_type_ty_param());
  1091. } else if f.ordinal == field.ordinal {
  1092. builder_generics_tuple.elems.push_value(empty_type());
  1093. } else {
  1094. // `f` appears later in the argument list after `field`, so if they are both missing we will
  1095. // show a warning for `field` and not for `f` - which means this warning should appear whether
  1096. // or not `f` is set.
  1097. g.params
  1098. .insert(index_after_lifetime_in_generics, f.generic_ty_param());
  1099. builder_generics_tuple.elems.push_value(f.type_ident());
  1100. }
  1101. builder_generics_tuple.elems.push_punct(Default::default());
  1102. }
  1103. });
  1104. let index_after_lifetime_in_generics = builder_generics
  1105. .iter()
  1106. .filter(|arg| matches!(arg, syn::GenericArgument::Lifetime(_)))
  1107. .count();
  1108. builder_generics.insert(
  1109. index_after_lifetime_in_generics,
  1110. syn::GenericArgument::Type(builder_generics_tuple.into()),
  1111. );
  1112. let (impl_generics, _, where_clause) = generics.split_for_impl();
  1113. let (_, ty_generics, _) = self.generics.split_for_impl();
  1114. let early_build_error_type_name = syn::Ident::new(
  1115. &format!(
  1116. "{}_Error_Missing_required_field_{}",
  1117. builder_name,
  1118. strip_raw_ident_prefix(field_name.to_string())
  1119. ),
  1120. builder_name.span(),
  1121. );
  1122. let early_build_error_message = format!("Missing required field {field_name}");
  1123. Ok(quote! {
  1124. #[doc(hidden)]
  1125. #[allow(dead_code, non_camel_case_types, non_snake_case)]
  1126. pub enum #early_build_error_type_name {}
  1127. #[doc(hidden)]
  1128. #[allow(dead_code, non_camel_case_types, missing_docs, clippy::panic)]
  1129. impl #impl_generics #builder_name < #( #builder_generics ),* > #where_clause {
  1130. #[deprecated(
  1131. note = #early_build_error_message
  1132. )]
  1133. pub fn build(self, _: #early_build_error_type_name) -> #name #ty_generics {
  1134. panic!()
  1135. }
  1136. }
  1137. })
  1138. }
  1139. pub fn build_method_impl(&self) -> TokenStream {
  1140. let StructInfo {
  1141. ref name,
  1142. ref builder_name,
  1143. ..
  1144. } = *self;
  1145. let generics = self.modify_generics(|g| {
  1146. let index_after_lifetime_in_generics = g
  1147. .params
  1148. .iter()
  1149. .filter(|arg| matches!(arg, syn::GenericParam::Lifetime(_)))
  1150. .count();
  1151. for field in self.included_fields() {
  1152. if field.builder_attr.default.is_some() {
  1153. let trait_ref = syn::TraitBound {
  1154. paren_token: None,
  1155. lifetimes: None,
  1156. modifier: syn::TraitBoundModifier::None,
  1157. path: syn::PathSegment {
  1158. ident: self.conversion_helper_trait_name.clone(),
  1159. arguments: syn::PathArguments::AngleBracketed(
  1160. syn::AngleBracketedGenericArguments {
  1161. colon2_token: None,
  1162. lt_token: Default::default(),
  1163. args: make_punctuated_single(syn::GenericArgument::Type(
  1164. field.ty.clone(),
  1165. )),
  1166. gt_token: Default::default(),
  1167. },
  1168. ),
  1169. }
  1170. .into(),
  1171. };
  1172. let mut generic_param: syn::TypeParam = field.generic_ident.clone().into();
  1173. generic_param.bounds.push(trait_ref.into());
  1174. g.params
  1175. .insert(index_after_lifetime_in_generics, generic_param.into());
  1176. }
  1177. }
  1178. });
  1179. let (impl_generics, _, _) = generics.split_for_impl();
  1180. let (original_impl_generics, ty_generics, where_clause) =
  1181. self.generics.split_for_impl();
  1182. let modified_ty_generics = modify_types_generics_hack(&ty_generics, |args| {
  1183. args.insert(
  1184. 0,
  1185. syn::GenericArgument::Type(
  1186. type_tuple(self.included_fields().map(|field| {
  1187. if field.builder_attr.default.is_some() {
  1188. field.type_ident()
  1189. } else {
  1190. field.tuplized_type_ty_param()
  1191. }
  1192. }))
  1193. .into(),
  1194. ),
  1195. );
  1196. });
  1197. let descructuring = self.included_fields().map(|f| f.name);
  1198. let helper_trait_name = &self.conversion_helper_trait_name;
  1199. // The default of a field can refer to earlier-defined fields, which we handle by
  1200. // writing out a bunch of `let` statements first, which can each refer to earlier ones.
  1201. // This means that field ordering may actually be significant, which isn’t ideal. We could
  1202. // relax that restriction by calculating a DAG of field default dependencies and
  1203. // reordering based on that, but for now this much simpler thing is a reasonable approach.
  1204. let assignments = self.fields.iter().map(|field| {
  1205. let name = &field.name;
  1206. if !field.builder_attr.extends.is_empty() {
  1207. quote!(let #name = self.#name;)
  1208. } else if let Some(ref default) = field.builder_attr.default {
  1209. if field.builder_attr.skip {
  1210. quote!(let #name = #default;)
  1211. } else {
  1212. quote!(let #name = #helper_trait_name::into_value(#name, || #default);)
  1213. }
  1214. } else {
  1215. quote!(let #name = #name.0;)
  1216. }
  1217. });
  1218. let field_names = self.fields.iter().map(|field| field.name);
  1219. let doc = if self.builder_attr.doc {
  1220. match self.builder_attr.build_method_doc {
  1221. Some(ref doc) => quote!(#[doc = #doc]),
  1222. None => {
  1223. // I’d prefer “a” or “an” to “its”, but determining which is grammatically
  1224. // correct is roughly impossible.
  1225. let doc =
  1226. format!("Finalize the builder and create its [`{name}`] instance");
  1227. quote!(#[doc = #doc])
  1228. }
  1229. }
  1230. } else {
  1231. quote!()
  1232. };
  1233. if self.has_signal_fields() {
  1234. let name = Ident::new(&format!("{}WithOwner", name), name.span());
  1235. let original_name = &self.name;
  1236. quote! {
  1237. #[doc(hidden)]
  1238. #[allow(dead_code, non_camel_case_types, missing_docs)]
  1239. #[derive(Clone)]
  1240. struct #name #ty_generics {
  1241. inner: #original_name #ty_generics,
  1242. owner: Owner,
  1243. }
  1244. impl #original_impl_generics PartialEq for #name #ty_generics #where_clause {
  1245. fn eq(&self, other: &Self) -> bool {
  1246. self.inner.eq(&other.inner)
  1247. }
  1248. }
  1249. impl #original_impl_generics #name #ty_generics #where_clause {
  1250. /// Create a component from the props.
  1251. fn into_vcomponent<M: 'static>(
  1252. self,
  1253. render_fn: impl dioxus_core::prelude::ComponentFunction<#original_name #ty_generics, M>,
  1254. component_name: &'static str,
  1255. ) -> dioxus_core::VComponent {
  1256. use dioxus_core::prelude::ComponentFunction;
  1257. dioxus_core::VComponent::new(move |wrapper: Self| render_fn.rebuild(wrapper.inner), self, component_name)
  1258. }
  1259. }
  1260. impl #original_impl_generics dioxus_core::prelude::Properties for #name #ty_generics #where_clause {
  1261. type Builder = ();
  1262. fn builder() -> Self::Builder {
  1263. unreachable!()
  1264. }
  1265. fn memoize(&mut self, new: &Self) -> bool {
  1266. self.inner.memoize(&new.inner)
  1267. }
  1268. }
  1269. #[allow(dead_code, non_camel_case_types, missing_docs)]
  1270. impl #impl_generics #builder_name #modified_ty_generics #where_clause {
  1271. #doc
  1272. pub fn build(self) -> #name #ty_generics {
  1273. let ( #(#descructuring,)* ) = self.fields;
  1274. #( #assignments )*
  1275. #name {
  1276. inner: #original_name {
  1277. #( #field_names ),*
  1278. },
  1279. owner: self.owner,
  1280. }
  1281. }
  1282. }
  1283. }
  1284. } else {
  1285. quote!(
  1286. #[allow(dead_code, non_camel_case_types, missing_docs)]
  1287. impl #impl_generics #builder_name #modified_ty_generics #where_clause {
  1288. #doc
  1289. pub fn build(self) -> #name #ty_generics {
  1290. let ( #(#descructuring,)* ) = self.fields;
  1291. #( #assignments )*
  1292. #name {
  1293. #( #field_names ),*
  1294. }
  1295. }
  1296. }
  1297. )
  1298. }
  1299. }
  1300. }
  1301. #[derive(Debug, Default)]
  1302. pub struct TypeBuilderAttr {
  1303. /// Whether to show docs for the `TypeBuilder` type (rather than hiding them).
  1304. pub doc: bool,
  1305. /// Docs on the `Type::builder()` method.
  1306. pub builder_method_doc: Option<syn::Expr>,
  1307. /// Docs on the `TypeBuilder` type. Specifying this implies `doc`, but you can just specify
  1308. /// `doc` instead and a default value will be filled in here.
  1309. pub builder_type_doc: Option<syn::Expr>,
  1310. /// Docs on the `TypeBuilder.build()` method. Specifying this implies `doc`, but you can just
  1311. /// specify `doc` instead and a default value will be filled in here.
  1312. pub build_method_doc: Option<syn::Expr>,
  1313. pub field_defaults: FieldBuilderAttr,
  1314. }
  1315. impl TypeBuilderAttr {
  1316. pub fn new(attrs: &[syn::Attribute]) -> Result<TypeBuilderAttr, Error> {
  1317. let mut result = TypeBuilderAttr::default();
  1318. for attr in attrs {
  1319. if path_to_single_string(attr.path()).as_deref() != Some("builder") {
  1320. continue;
  1321. }
  1322. match &attr.meta {
  1323. syn::Meta::List(list) => {
  1324. if list.tokens.is_empty() {
  1325. continue;
  1326. }
  1327. }
  1328. _ => {
  1329. continue;
  1330. }
  1331. }
  1332. let as_expr = attr.parse_args_with(
  1333. Punctuated::<Expr, syn::Token![,]>::parse_separated_nonempty,
  1334. )?;
  1335. for expr in as_expr.into_iter() {
  1336. result.apply_meta(expr)?;
  1337. }
  1338. }
  1339. Ok(result)
  1340. }
  1341. fn apply_meta(&mut self, expr: syn::Expr) -> Result<(), Error> {
  1342. match expr {
  1343. syn::Expr::Assign(assign) => {
  1344. let name = expr_to_single_string(&assign.left)
  1345. .ok_or_else(|| Error::new_spanned(&assign.left, "Expected identifier"))?;
  1346. match name.as_str() {
  1347. "builder_method_doc" => {
  1348. self.builder_method_doc = Some(*assign.right);
  1349. Ok(())
  1350. }
  1351. "builder_type_doc" => {
  1352. self.builder_type_doc = Some(*assign.right);
  1353. self.doc = true;
  1354. Ok(())
  1355. }
  1356. "build_method_doc" => {
  1357. self.build_method_doc = Some(*assign.right);
  1358. self.doc = true;
  1359. Ok(())
  1360. }
  1361. _ => Err(Error::new_spanned(
  1362. &assign,
  1363. format!("Unknown parameter {name:?}"),
  1364. )),
  1365. }
  1366. }
  1367. syn::Expr::Path(path) => {
  1368. let name = path_to_single_string(&path.path)
  1369. .ok_or_else(|| Error::new_spanned(&path, "Expected identifier"))?;
  1370. match name.as_str() {
  1371. "doc" => {
  1372. self.doc = true;
  1373. Ok(())
  1374. }
  1375. _ => Err(Error::new_spanned(
  1376. &path,
  1377. format!("Unknown parameter {name:?}"),
  1378. )),
  1379. }
  1380. }
  1381. syn::Expr::Call(call) => {
  1382. let subsetting_name = if let syn::Expr::Path(path) = &*call.func {
  1383. path_to_single_string(&path.path)
  1384. } else {
  1385. None
  1386. }
  1387. .ok_or_else(|| {
  1388. let call_func = &call.func;
  1389. let call_func = quote!(#call_func);
  1390. Error::new_spanned(
  1391. &call.func,
  1392. format!("Illegal builder setting group {call_func}"),
  1393. )
  1394. })?;
  1395. match subsetting_name.as_str() {
  1396. "field_defaults" => {
  1397. for arg in call.args {
  1398. self.field_defaults.apply_meta(arg)?;
  1399. }
  1400. Ok(())
  1401. }
  1402. _ => Err(Error::new_spanned(
  1403. &call.func,
  1404. format!("Illegal builder setting group name {subsetting_name}"),
  1405. )),
  1406. }
  1407. }
  1408. _ => Err(Error::new_spanned(expr, "Expected (<...>=<...>)")),
  1409. }
  1410. }
  1411. }
  1412. }
  1413. fn looks_like_signal_type(ty: &Type) -> bool {
  1414. match ty {
  1415. Type::Path(ty) => {
  1416. if ty.qself.is_some() {
  1417. return false;
  1418. }
  1419. let path = &ty.path;
  1420. let mut path_segments_without_generics = Vec::new();
  1421. let mut generic_arg_count = 0;
  1422. for segment in &path.segments {
  1423. let mut segment = segment.clone();
  1424. match segment.arguments {
  1425. PathArguments::AngleBracketed(_) => generic_arg_count += 1,
  1426. PathArguments::Parenthesized(_) => {
  1427. return false;
  1428. }
  1429. _ => {}
  1430. }
  1431. segment.arguments = syn::PathArguments::None;
  1432. path_segments_without_generics.push(segment);
  1433. }
  1434. // If there is more than the type and the send/sync generic, it doesn't look like our signal
  1435. if generic_arg_count > 2 {
  1436. return false;
  1437. }
  1438. let path_without_generics = syn::Path {
  1439. leading_colon: None,
  1440. segments: Punctuated::from_iter(path_segments_without_generics),
  1441. };
  1442. path_without_generics == parse_quote!(dioxus_core::prelude::ReadOnlySignal)
  1443. || path_without_generics == parse_quote!(prelude::ReadOnlySignal)
  1444. || path_without_generics == parse_quote!(ReadOnlySignal)
  1445. }
  1446. _ => false,
  1447. }
  1448. }