1// This file is part of ICU4X. For terms of use, please see the file
2// called LICENSE at the top level of the ICU4X source tree
3// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
4
5use crate::utils::{self, FieldInfo};
6use proc_macro2::Span;
7use proc_macro2::TokenStream as TokenStream2;
8use quote::{quote, ToTokens};
9use syn::spanned::Spanned;
10use syn::{
11 parse_quote, Data, DeriveInput, Error, Field, Fields, GenericArgument, Ident, Lifetime,
12 PathArguments, Type, TypePath,
13};
14
15pub fn make_varule_impl(ule_name: Ident, mut input: DeriveInput) -> TokenStream2 {
16 if input.generics.type_params().next().is_some()
17 || input.generics.const_params().next().is_some()
18 || input.generics.lifetimes().count() > 1
19 {
20 return Error::new(
21 input.generics.span(),
22 "#[make_varule] must be applied to a struct without any type or const parameters and at most one lifetime",
23 )
24 .to_compile_error();
25 }
26
27 let sp = input.span();
28 let attrs = match utils::extract_attributes_common(&mut input.attrs, sp, true) {
29 Ok(val) => val,
30 Err(e) => return e.to_compile_error(),
31 };
32
33 let lt = input.generics.lifetimes().next();
34
35 if let Some(lt) = lt {
36 if lt.colon_token.is_some() || !lt.bounds.is_empty() {
37 return Error::new(
38 input.generics.span(),
39 "#[make_varule] must be applied to a struct without lifetime bounds",
40 )
41 .to_compile_error();
42 }
43 }
44
45 let lt = lt.map(|l| &l.lifetime);
46
47 let name = &input.ident;
48 let input_span = input.span();
49
50 let fields = match input.data {
51 Data::Struct(ref mut s) => &mut s.fields,
52 _ => {
53 return Error::new(input.span(), "#[make_varule] must be applied to a struct")
54 .to_compile_error();
55 }
56 };
57
58 if fields.is_empty() {
59 return Error::new(
60 input.span(),
61 "#[make_varule] must be applied to a struct with at least one field",
62 )
63 .to_compile_error();
64 }
65
66 let mut sized_fields = vec![];
67 let mut unsized_fields = vec![];
68
69 let mut custom_varule_idents = vec![];
70
71 for field in fields.iter_mut() {
72 match utils::extract_field_attributes(&mut field.attrs) {
73 Ok(i) => custom_varule_idents.push(i),
74 Err(e) => return e.to_compile_error(),
75 }
76 }
77
78 for (i, field) in fields.iter().enumerate() {
79 match UnsizedField::new(field, i, custom_varule_idents[i].clone()) {
80 Ok(o) => unsized_fields.push(o),
81 Err(_) => sized_fields.push(FieldInfo::new_for_field(field, i)),
82 }
83 }
84
85 if unsized_fields.is_empty() {
86 let last_field_index = fields.len() - 1;
87 let last_field = fields.iter().next_back().unwrap();
88
89 let e = UnsizedField::new(
90 last_field,
91 last_field_index,
92 custom_varule_idents[last_field_index].clone(),
93 )
94 .unwrap_err();
95 return Error::new(last_field.span(), e).to_compile_error();
96 }
97
98 if unsized_fields[0].field.index != fields.len() - unsized_fields.len()
99 && unsized_fields[0].field.field.ident.is_none()
100 {
101 return Error::new(
102 unsized_fields.first().unwrap().field.field.span(),
103 "#[make_varule] requires its unsized fields to be at the end for tuple structs",
104 )
105 .to_compile_error();
106 }
107
108 let unsized_field_info = UnsizedFields::new(unsized_fields);
109
110 let mut field_inits = crate::ule::make_ule_fields(&sized_fields);
111 let last_field_ule = unsized_field_info.varule_ty();
112
113 let setter = unsized_field_info.varule_setter();
114 let vis = &unsized_field_info.varule_vis();
115 field_inits.push(quote!(#vis #setter #last_field_ule));
116
117 let semi = utils::semi_for(fields);
118 let repr_attr = utils::repr_for(fields);
119 let field_inits = utils::wrap_field_inits(&field_inits, fields);
120 let vis = &input.vis;
121
122 let doc = format!(
123 "[`VarULE`](zerovec::ule::VarULE) type for [`{name}`]. See [`{name}`] for documentation."
124 );
125 let varule_struct: DeriveInput = parse_quote!(
126 #[repr(#repr_attr)]
127 #[doc = #doc]
128 #[allow(missing_docs)]
129 #vis struct #ule_name #field_inits #semi
130 );
131
132 let derived = crate::varule::derive_impl(&varule_struct, unsized_field_info.varule_validator());
133
134 let maybe_lt_bound = lt.as_ref().map(|lt| quote!(<#lt>));
135
136 let encode_impl = make_encode_impl(
137 &sized_fields,
138 &unsized_field_info,
139 name,
140 &ule_name,
141 &maybe_lt_bound,
142 );
143
144 let zf_impl = make_zf_impl(
145 &sized_fields,
146 &unsized_field_info,
147 fields,
148 name,
149 &ule_name,
150 lt,
151 input_span,
152 );
153
154 let eq_impl = quote!(
155 impl core::cmp::PartialEq for #ule_name {
156 fn eq(&self, other: &Self) -> bool {
157 // The VarULE invariants allow us to assume that equality is byte equality
158 // in non-safety-critical contexts
159 <Self as zerovec::ule::VarULE>::as_byte_slice(&self)
160 == <Self as zerovec::ule::VarULE>::as_byte_slice(&other)
161 }
162 }
163
164 impl core::cmp::Eq for #ule_name {}
165 );
166
167 let zerofrom_fq_path =
168 quote!(<#name as zerovec::__zerovec_internal_reexport::ZeroFrom<#ule_name>>);
169
170 let maybe_ord_impls = if attrs.skip_ord {
171 quote!()
172 } else {
173 quote!(
174 impl core::cmp::PartialOrd for #ule_name {
175 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
176 let this = #zerofrom_fq_path::zero_from(self);
177 let other = #zerofrom_fq_path::zero_from(other);
178 <#name as core::cmp::PartialOrd>::partial_cmp(&this, &other)
179 }
180 }
181
182 impl core::cmp::Ord for #ule_name {
183 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
184 let this = #zerofrom_fq_path::zero_from(self);
185 let other = #zerofrom_fq_path::zero_from(other);
186 <#name as core::cmp::Ord>::cmp(&this, &other)
187 }
188 }
189 )
190 };
191
192 let maybe_debug = if attrs.debug {
193 quote!(
194 impl core::fmt::Debug for #ule_name {
195 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
196 let this = #zerofrom_fq_path::zero_from(self);
197 <#name as core::fmt::Debug>::fmt(&this, f)
198 }
199 }
200 )
201 } else {
202 quote!()
203 };
204
205 let zmkv = if attrs.skip_kv {
206 quote!()
207 } else {
208 quote!(
209 impl<'a> zerovec::maps::ZeroMapKV<'a> for #ule_name {
210 type Container = zerovec::VarZeroVec<'a, #ule_name>;
211 type Slice = zerovec::VarZeroSlice<#ule_name>;
212 type GetType = #ule_name;
213 type OwnedType = zerovec::__zerovec_internal_reexport::boxed::Box<#ule_name>;
214 }
215 )
216 };
217
218 let serde_path = quote!(zerovec::__zerovec_internal_reexport::serde);
219
220 let maybe_ser = if attrs.serialize {
221 quote!(
222 impl #serde_path::Serialize for #ule_name {
223 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: #serde_path::Serializer {
224 let this = #zerofrom_fq_path::zero_from(self);
225 <#name as #serde_path::Serialize>::serialize(&this, serializer)
226 }
227 }
228 )
229 } else {
230 quote!()
231 };
232
233 let maybe_de = if attrs.deserialize {
234 quote!(
235 impl<'de> #serde_path::Deserialize<'de> for zerovec::__zerovec_internal_reexport::boxed::Box<#ule_name> {
236 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: #serde_path::Deserializer<'de> {
237 let this = <#name as #serde_path::Deserialize>::deserialize(deserializer)?;
238 Ok(zerovec::ule::encode_varule_to_box(&this))
239 }
240 }
241 )
242 } else {
243 quote!()
244 };
245
246 let maybe_hash = if attrs.hash {
247 quote!(
248 #[allow(clippy::derive_hash_xor_eq)]
249 impl core::hash::Hash for #ule_name {
250 fn hash<H>(&self, state: &mut H) where H: core::hash::Hasher {
251 state.write(<#ule_name as zerovec::ule::VarULE>::as_byte_slice(&self));
252 }
253 }
254 )
255 } else {
256 quote!()
257 };
258
259 quote!(
260 #input
261
262 #varule_struct
263
264 #encode_impl
265
266 #zf_impl
267
268 #derived
269
270 #maybe_ord_impls
271
272 #eq_impl
273
274 #zmkv
275
276 #maybe_ser
277
278 #maybe_de
279
280 #maybe_debug
281
282 #maybe_hash
283 )
284}
285
286fn make_zf_impl(
287 sized_fields: &[FieldInfo],
288 unsized_field_info: &UnsizedFields,
289 fields: &Fields,
290 name: &Ident,
291 ule_name: &Ident,
292 maybe_lt: Option<&Lifetime>,
293 span: Span,
294) -> TokenStream2 {
295 if !unsized_field_info.has_zf() {
296 return quote!();
297 }
298
299 let lt = if let Some(ref lt) = maybe_lt {
300 lt
301 } else {
302 return Error::new(
303 span,
304 "Can only generate ZeroFrom impls for types with lifetimes",
305 )
306 .to_compile_error();
307 };
308
309 let mut field_inits = sized_fields
310 .iter()
311 .map(|f| {
312 let ty = &f.field.ty;
313 let accessor = &f.accessor;
314 let setter = f.setter();
315 quote!(#setter <#ty as zerovec::ule::AsULE>::from_unaligned(other.#accessor))
316 })
317 .collect::<Vec<_>>();
318
319 unsized_field_info.push_zf_setters(lt, &mut field_inits);
320
321 let field_inits = utils::wrap_field_inits(&field_inits, fields);
322 let zerofrom_trait = quote!(zerovec::__zerovec_internal_reexport::ZeroFrom);
323 quote!(
324 impl <#lt> #zerofrom_trait <#lt, #ule_name> for #name <#lt> {
325 fn zero_from(other: &#lt #ule_name) -> Self {
326 Self #field_inits
327 }
328 }
329 )
330}
331
332fn make_encode_impl(
333 sized_fields: &[FieldInfo],
334 unsized_field_info: &UnsizedFields,
335 name: &Ident,
336 ule_name: &Ident,
337 maybe_lt_bound: &Option<TokenStream2>,
338) -> TokenStream2 {
339 let mut lengths = vec![];
340
341 for field in sized_fields {
342 let ty = &field.field.ty;
343 lengths.push(quote!(::core::mem::size_of::<<#ty as zerovec::ule::AsULE>::ULE>()));
344 }
345
346 let (encoders, remaining_offset) = utils::generate_per_field_offsets(
347 sized_fields,
348 true,
349 |field, prev_offset_ident, size_ident| {
350 let ty = &field.field.ty;
351 let accessor = &field.accessor;
352 quote!(
353 #[allow(clippy::indexing_slicing)] // generate_per_field_offsets produces valid indices
354 let out = &mut dst[#prev_offset_ident .. #prev_offset_ident + #size_ident];
355 let unaligned = zerovec::ule::AsULE::to_unaligned(self.#accessor);
356 let unaligned_slice = &[unaligned];
357 let src = <<#ty as zerovec::ule::AsULE>::ULE as zerovec::ule::ULE>::as_byte_slice(unaligned_slice);
358 out.copy_from_slice(src);
359 )
360 },
361 );
362
363 let last_encode_len = unsized_field_info.encode_len();
364 let last_encode_write = unsized_field_info.encode_write(quote!(out));
365 quote!(
366 unsafe impl #maybe_lt_bound zerovec::ule::EncodeAsVarULE<#ule_name> for #name #maybe_lt_bound {
367 // Safety: unimplemented as the other two are implemented
368 fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R {
369 unreachable!("other two methods implemented")
370 }
371
372 // Safety: returns the total length of the ULE form by adding up the lengths of each element's ULE forms
373 fn encode_var_ule_len(&self) -> usize {
374 #(#lengths +)* #last_encode_len
375 }
376
377 // Safety: converts each element to ULE form and writes them in sequence
378 fn encode_var_ule_write(&self, mut dst: &mut [u8]) {
379 debug_assert_eq!(self.encode_var_ule_len(), dst.len());
380 #encoders
381
382 #[allow(clippy::indexing_slicing)] // generate_per_field_offsets produces valid remainder
383 let out = &mut dst[#remaining_offset..];
384 #last_encode_write
385 }
386 }
387
388 // This second impl exists to allow for using EncodeAsVarULE without cloning
389 //
390 // A blanket impl cannot exist without coherence issues
391 unsafe impl #maybe_lt_bound zerovec::ule::EncodeAsVarULE<#ule_name> for &'_ #name #maybe_lt_bound {
392 // Safety: unimplemented as the other two are implemented
393 fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R {
394 unreachable!("other two methods implemented")
395 }
396
397 // Safety: returns the total length of the ULE form by adding up the lengths of each element's ULE forms
398 fn encode_var_ule_len(&self) -> usize {
399 (**self).encode_var_ule_len()
400 }
401
402 // Safety: converts each element to ULE form and writes them in sequence
403 fn encode_var_ule_write(&self, mut dst: &mut [u8]) {
404 (**self).encode_var_ule_write(dst)
405 }
406 }
407 )
408}
409
410/// Represents a VarULE-compatible type that would typically
411/// be found behind a `Cow<'a, _>` in the last field, and is represented
412/// roughly the same in owned and borrowed versions
413#[derive(Copy, Clone, Debug)]
414enum OwnULETy<'a> {
415 /// [T] where T: AsULE<ULE = Self>
416 Slice(&'a Type),
417 /// str
418 Str,
419}
420
421/// Represents the type of the last field of the struct
422#[derive(Clone, Debug)]
423enum UnsizedFieldKind<'a> {
424 Cow(OwnULETy<'a>),
425 ZeroVec(&'a Type),
426 VarZeroVec(&'a Type),
427 /// Custom VarULE type, and the identifier corresponding to the VarULE type
428 Custom(&'a TypePath, Ident),
429
430 // Generally you should be using the above ones for maximum zero-copy, but these will still work
431 Growable(OwnULETy<'a>),
432 Boxed(OwnULETy<'a>),
433 Ref(OwnULETy<'a>),
434}
435
436#[derive(Clone, Debug)]
437struct UnsizedField<'a> {
438 kind: UnsizedFieldKind<'a>,
439 field: FieldInfo<'a>,
440}
441
442struct UnsizedFields<'a> {
443 fields: Vec<UnsizedField<'a>>,
444}
445
446impl<'a> UnsizedFields<'a> {
447 fn new(fields: Vec<UnsizedField<'a>>) -> Self {
448 assert!(!fields.is_empty(), "Must have at least one unsized field");
449 Self { fields }
450 }
451
452 // Get the corresponding VarULE type that can store all of these
453 fn varule_ty(&self) -> TokenStream2 {
454 if self.fields.len() == 1 {
455 self.fields[0].kind.varule_ty()
456 } else {
457 quote!(zerovec::ule::MultiFieldsULE)
458 }
459 }
460
461 // Get the accessor field name in the VarULE type
462 fn varule_accessor(&self) -> TokenStream2 {
463 if self.fields.len() == 1 {
464 self.fields[0].field.accessor.clone()
465 } else if self.fields[0].field.field.ident.is_some() {
466 quote!(unsized_fields)
467 } else {
468 // first unsized field
469 self.fields[0].field.accessor.clone()
470 }
471 }
472
473 // Get the setter for this type for use in struct definition/creation syntax
474 fn varule_setter(&self) -> TokenStream2 {
475 if self.fields.len() == 1 {
476 self.fields[0].field.setter()
477 } else if self.fields[0].field.field.ident.is_some() {
478 quote!(unsized_fields: )
479 } else {
480 quote!()
481 }
482 }
483
484 fn varule_vis(&self) -> TokenStream2 {
485 if self.fields.len() == 1 {
486 self.fields[0].field.field.vis.to_token_stream()
487 } else {
488 // Always private
489 quote!()
490 }
491 }
492
493 // Check if the type has a ZeroFrom impl
494 fn has_zf(&self) -> bool {
495 self.fields.iter().all(|f| f.kind.has_zf())
496 }
497
498 // Takes all unsized fields on self and encodes them into a byte slice `out`
499 fn encode_write(&self, out: TokenStream2) -> TokenStream2 {
500 if self.fields.len() == 1 {
501 self.fields[0].encode_func(quote!(encode_var_ule_write), quote!(#out))
502 } else {
503 let mut lengths = vec![];
504 let mut writers = vec![];
505 for (i, field) in self.fields.iter().enumerate() {
506 lengths.push(field.encode_func(quote!(encode_var_ule_len), quote!()));
507 let (encodeable_ty, encodeable) = field.encodeable_tokens();
508 let varule_ty = field.kind.varule_ty();
509 writers
510 .push(quote!(multi.set_field_at::<#varule_ty, #encodeable_ty>(#i, #encodeable)))
511 }
512
513 quote!(
514 let lengths = [#(#lengths),*];
515 let mut multi = zerovec::ule::MultiFieldsULE::new_from_lengths_partially_initialized(&lengths, #out);
516 unsafe {
517 #(#writers;)*
518 }
519 )
520 }
521 }
522
523 // Takes all unsized fields on self and returns the length needed for encoding into a byte slice
524 fn encode_len(&self) -> TokenStream2 {
525 if self.fields.len() == 1 {
526 self.fields[0].encode_func(quote!(encode_var_ule_len), quote!())
527 } else {
528 let mut lengths = vec![];
529 for field in self.fields.iter() {
530 lengths.push(field.encode_func(quote!(encode_var_ule_len), quote!()));
531 }
532 quote!(zerovec::ule::MultiFieldsULE::compute_encoded_len_for(&[#(#lengths),*]))
533 }
534 }
535
536 /// Constructs ZeroFrom setters for each field of the stack type
537 fn push_zf_setters(&self, lt: &Lifetime, field_inits: &mut Vec<TokenStream2>) {
538 let zerofrom_trait = quote!(zerovec::__zerovec_internal_reexport::ZeroFrom);
539 if self.fields.len() == 1 {
540 let accessor = self.fields[0].field.accessor.clone();
541 let setter = self.fields[0].field.setter();
542 let last_field_ty = &self.fields[0].field.field.ty;
543 let last_field_ule_ty = self.fields[0].kind.varule_ty();
544 field_inits.push(quote!(#setter <#last_field_ty as #zerofrom_trait <#lt, #last_field_ule_ty>>::zero_from(&other.#accessor) ));
545 } else {
546 let multi_accessor = self.varule_accessor();
547 for (i, field) in self.fields.iter().enumerate() {
548 let setter = field.field.setter();
549 let field_ty = &field.field.field.ty;
550 let field_ule_ty = field.kind.varule_ty();
551
552 field_inits.push(quote!(#setter unsafe {
553 <#field_ty as #zerofrom_trait <#lt, #field_ule_ty>>::zero_from(&other.#multi_accessor.get_field::<#field_ule_ty>(#i))
554 }));
555 }
556 }
557 }
558
559 /// In case this needs custom validation code, return it
560 ///
561 /// The code will validate a variable known as `last_field_bytes`
562 fn varule_validator(&self) -> Option<TokenStream2> {
563 if self.fields.len() == 1 {
564 None
565 } else {
566 let mut validators = vec![];
567 for (i, field) in self.fields.iter().enumerate() {
568 let varule_ty = field.kind.varule_ty();
569 validators.push(quote!(multi.validate_field::<#varule_ty>(#i)?;));
570 }
571
572 Some(quote!(
573 let multi = zerovec::ule::MultiFieldsULE::parse_byte_slice(last_field_bytes)?;
574 unsafe {
575 #(#validators)*
576 }
577 ))
578 }
579 }
580}
581
582impl<'a> UnsizedField<'a> {
583 fn new(
584 field: &'a Field,
585 index: usize,
586 custom_varule_ident: Option<Ident>,
587 ) -> Result<Self, String> {
588 Ok(UnsizedField {
589 kind: UnsizedFieldKind::new(&field.ty, custom_varule_ident)?,
590 field: FieldInfo::new_for_field(field, index),
591 })
592 }
593
594 /// Call `<Self as EncodeAsVarULE<V>>::#method(self.accessor #additional_args)` after adjusting
595 /// Self and self.accessor to be the right types
596 fn encode_func(&self, method: TokenStream2, additional_args: TokenStream2) -> TokenStream2 {
597 let encodeas_trait = quote!(zerovec::ule::EncodeAsVarULE);
598 let (encodeable_ty, encodeable) = self.encodeable_tokens();
599 let varule_ty = self.kind.varule_ty();
600 quote!(<#encodeable_ty as #encodeas_trait<#varule_ty>>::#method(#encodeable, #additional_args))
601 }
602
603 /// Returns (encodeable_ty, encodeable)
604 fn encodeable_tokens(&self) -> (TokenStream2, TokenStream2) {
605 let accessor = self.field.accessor.clone();
606 let value = quote!(self.#accessor);
607 let encodeable = self.kind.encodeable_value(value);
608 let encodeable_ty = self.kind.encodeable_ty();
609 (encodeable_ty, encodeable)
610 }
611}
612
613impl<'a> UnsizedFieldKind<'a> {
614 /// Construct a UnsizedFieldKind for the type of a UnsizedFieldKind if possible
615 fn new(
616 ty: &'a Type,
617 custom_varule_ident: Option<Ident>,
618 ) -> Result<UnsizedFieldKind<'a>, String> {
619 static PATH_TYPE_IDENTITY_ERROR: &str =
620 "Can only automatically detect corresponding VarULE types for path types \
621 that are Cow, ZeroVec, VarZeroVec, Box, String, or Vec";
622 static PATH_TYPE_GENERICS_ERROR: &str =
623 "Can only automatically detect corresponding VarULE types for path \
624 types with at most one lifetime and at most one generic parameter. VarZeroVecFormat
625 types are not currently supported";
626 match *ty {
627 Type::Reference(ref tyref) => OwnULETy::new(&tyref.elem, "reference").map(UnsizedFieldKind::Ref),
628 Type::Path(ref typath) => {
629 if let Some(custom_varule_ident) = custom_varule_ident {
630 return Ok(UnsizedFieldKind::Custom(typath, custom_varule_ident));
631 }
632 if typath.path.segments.len() != 1 {
633 return Err("Can only automatically detect corresponding VarULE types for \
634 path types with a single path segment".into());
635 }
636 let segment = typath.path.segments.first().unwrap();
637 match segment.arguments {
638 PathArguments::None => {
639 if segment.ident == "String" {
640 Ok(UnsizedFieldKind::Growable(OwnULETy::Str))
641 } else {
642 Err(PATH_TYPE_IDENTITY_ERROR.into())
643 }
644 }
645 PathArguments::AngleBracketed(ref params) => {
646 // At most one lifetime and exactly one generic parameter
647 let mut lifetime = None;
648 let mut generic = None;
649 for param in &params.args {
650 match param {
651 GenericArgument::Lifetime(ref lt) if lifetime.is_none() => {
652 lifetime = Some(lt)
653 }
654 GenericArgument::Type(ref ty) if generic.is_none() => {
655 generic = Some(ty)
656 }
657 _ => return Err(PATH_TYPE_GENERICS_ERROR.into()),
658 }
659 }
660
661 // Must be exactly one generic parameter
662 // (we've handled the zero generics case already)
663 let generic = if let Some(g) = generic {
664 g
665 } else {
666 return Err(PATH_TYPE_GENERICS_ERROR.into());
667 };
668
669 let ident = segment.ident.to_string();
670
671 if lifetime.is_some() {
672 match &*ident {
673 "ZeroVec" => Ok(UnsizedFieldKind::ZeroVec(generic)),
674 "VarZeroVec" => Ok(UnsizedFieldKind::VarZeroVec(generic)),
675 "Cow" => OwnULETy::new(generic, "Cow").map(UnsizedFieldKind::Cow),
676 _ => Err(PATH_TYPE_IDENTITY_ERROR.into()),
677 }
678 } else {
679 match &*ident {
680 "Vec" => Ok(UnsizedFieldKind::Growable(OwnULETy::Slice(generic))),
681 "Box" => OwnULETy::new(generic, "Box").map(UnsizedFieldKind::Boxed),
682 _ => Err(PATH_TYPE_IDENTITY_ERROR.into()),
683 }
684 }
685 }
686 _ => Err("Can only automatically detect corresponding VarULE types for path types \
687 with none or angle bracketed generics".into()),
688 }
689 }
690 _ => Err("Can only automatically detect corresponding VarULE types for path and reference types".into()),
691 }
692 }
693 /// Get the tokens for the corresponding VarULE type
694 fn varule_ty(&self) -> TokenStream2 {
695 match *self {
696 Self::Ref(ref inner)
697 | Self::Cow(ref inner)
698 | Self::Boxed(ref inner)
699 | Self::Growable(ref inner) => {
700 let inner_ule = inner.varule_ty();
701 quote!(#inner_ule)
702 }
703 Self::Custom(_, ref name) => quote!(#name),
704 Self::ZeroVec(ref inner) => quote!(zerovec::ZeroSlice<#inner>),
705 Self::VarZeroVec(ref inner) => quote!(zerovec::VarZeroSlice<#inner>),
706 }
707 }
708
709 // Takes expr `value` and returns it as a value that can be encoded via EncodeAsVarULE
710 fn encodeable_value(&self, value: TokenStream2) -> TokenStream2 {
711 match *self {
712 Self::Ref(_) | Self::Cow(_) | Self::Growable(_) | Self::Boxed(_) => quote!(&*#value),
713
714 Self::Custom(..) => quote!(&#value),
715 Self::ZeroVec(_) | Self::VarZeroVec(_) => quote!(&*#value),
716 }
717 }
718
719 /// Returns the EncodeAsVarULE type this can be represented as, the same returned by encodeable_value()
720 fn encodeable_ty(&self) -> TokenStream2 {
721 match *self {
722 Self::Ref(ref inner)
723 | Self::Cow(ref inner)
724 | Self::Growable(ref inner)
725 | Self::Boxed(ref inner) => inner.varule_ty(),
726
727 Self::Custom(ref path, _) => quote!(#path),
728 Self::ZeroVec(ref ty) => quote!(zerovec::ZeroSlice<#ty>),
729 Self::VarZeroVec(ref ty) => quote!(zerovec::VarZeroSlice<#ty>),
730 }
731 }
732
733 fn has_zf(&self) -> bool {
734 matches!(
735 *self,
736 Self::Ref(_) | Self::Cow(_) | Self::ZeroVec(_) | Self::VarZeroVec(_) | Self::Custom(..)
737 )
738 }
739}
740
741impl<'a> OwnULETy<'a> {
742 fn new(ty: &'a Type, context: &str) -> Result<Self, String> {
743 match *ty {
744 Type::Slice(ref slice: &TypeSlice) => Ok(OwnULETy::Slice(&slice.elem)),
745 Type::Path(ref typath: &TypePath) => {
746 if typath.path.is_ident("str") {
747 Ok(OwnULETy::Str)
748 } else {
749 Err(format!("Cannot automatically detect corresponding VarULE type for non-str path type inside a {context}"))
750 }
751 }
752 _ => Err(format!("Cannot automatically detect corresponding VarULE type for non-slice/path type inside a {context}")),
753 }
754 }
755
756 /// Get the tokens for the corresponding VarULE type
757 fn varule_ty(&self) -> TokenStream2 {
758 match *self {
759 OwnULETy::Slice(s: &Type) => quote!([#s]),
760 OwnULETy::Str => quote!(str),
761 }
762 }
763}
764