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 | |
5 | use crate::utils::{self, FieldInfo}; |
6 | use proc_macro2::Span; |
7 | use proc_macro2::TokenStream as TokenStream2; |
8 | use quote::{quote, ToTokens}; |
9 | use syn::spanned::Spanned; |
10 | use syn::{ |
11 | parse_quote, Data, DeriveInput, Error, Field, Fields, GenericArgument, Ident, Lifetime, |
12 | PathArguments, Type, TypePath, |
13 | }; |
14 | |
15 | pub 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 | Some(self.cmp(other)) |
177 | } |
178 | } |
179 | |
180 | impl core::cmp::Ord for #ule_name { |
181 | fn cmp(&self, other: &Self) -> core::cmp::Ordering { |
182 | let this = #zerofrom_fq_path::zero_from(self); |
183 | let other = #zerofrom_fq_path::zero_from(other); |
184 | <#name as core::cmp::Ord>::cmp(&this, &other) |
185 | } |
186 | } |
187 | ) |
188 | }; |
189 | |
190 | let maybe_debug = if attrs.debug { |
191 | quote!( |
192 | impl core::fmt::Debug for #ule_name { |
193 | fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { |
194 | let this = #zerofrom_fq_path::zero_from(self); |
195 | <#name as core::fmt::Debug>::fmt(&this, f) |
196 | } |
197 | } |
198 | ) |
199 | } else { |
200 | quote!() |
201 | }; |
202 | |
203 | let zmkv = if attrs.skip_kv { |
204 | quote!() |
205 | } else { |
206 | quote!( |
207 | impl<'a> zerovec::maps::ZeroMapKV<'a> for #ule_name { |
208 | type Container = zerovec::VarZeroVec<'a, #ule_name>; |
209 | type Slice = zerovec::VarZeroSlice<#ule_name>; |
210 | type GetType = #ule_name; |
211 | type OwnedType = zerovec::__zerovec_internal_reexport::boxed::Box<#ule_name>; |
212 | } |
213 | ) |
214 | }; |
215 | |
216 | let serde_path = quote!(zerovec::__zerovec_internal_reexport::serde); |
217 | |
218 | let maybe_ser = if attrs.serialize { |
219 | quote!( |
220 | impl #serde_path::Serialize for #ule_name { |
221 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: #serde_path::Serializer { |
222 | let this = #zerofrom_fq_path::zero_from(self); |
223 | <#name as #serde_path::Serialize>::serialize(&this, serializer) |
224 | } |
225 | } |
226 | ) |
227 | } else { |
228 | quote!() |
229 | }; |
230 | |
231 | let maybe_de = if attrs.deserialize { |
232 | quote!( |
233 | impl<'de> #serde_path::Deserialize<'de> for zerovec::__zerovec_internal_reexport::boxed::Box<#ule_name> { |
234 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: #serde_path::Deserializer<'de> { |
235 | let this = <#name as #serde_path::Deserialize>::deserialize(deserializer)?; |
236 | Ok(zerovec::ule::encode_varule_to_box(&this)) |
237 | } |
238 | } |
239 | ) |
240 | } else { |
241 | quote!() |
242 | }; |
243 | |
244 | let maybe_hash = if attrs.hash { |
245 | quote!( |
246 | #[allow(clippy::derive_hash_xor_eq)] |
247 | impl core::hash::Hash for #ule_name { |
248 | fn hash<H>(&self, state: &mut H) where H: core::hash::Hasher { |
249 | state.write(<#ule_name as zerovec::ule::VarULE>::as_byte_slice(&self)); |
250 | } |
251 | } |
252 | ) |
253 | } else { |
254 | quote!() |
255 | }; |
256 | |
257 | let maybe_multi_getters = if let Some(getters) = unsized_field_info.maybe_multi_getters() { |
258 | quote! { |
259 | impl #ule_name { |
260 | #getters |
261 | } |
262 | } |
263 | } else { |
264 | quote!() |
265 | }; |
266 | |
267 | quote!( |
268 | #input |
269 | |
270 | #varule_struct |
271 | |
272 | #maybe_multi_getters |
273 | |
274 | #encode_impl |
275 | |
276 | #zf_impl |
277 | |
278 | #derived |
279 | |
280 | #maybe_ord_impls |
281 | |
282 | #eq_impl |
283 | |
284 | #zmkv |
285 | |
286 | #maybe_ser |
287 | |
288 | #maybe_de |
289 | |
290 | #maybe_debug |
291 | |
292 | #maybe_hash |
293 | ) |
294 | } |
295 | |
296 | fn make_zf_impl( |
297 | sized_fields: &[FieldInfo], |
298 | unsized_field_info: &UnsizedFields, |
299 | fields: &Fields, |
300 | name: &Ident, |
301 | ule_name: &Ident, |
302 | maybe_lt: Option<&Lifetime>, |
303 | span: Span, |
304 | ) -> TokenStream2 { |
305 | if !unsized_field_info.has_zf() { |
306 | return quote!(); |
307 | } |
308 | |
309 | let lt = if let Some(ref lt) = maybe_lt { |
310 | lt |
311 | } else { |
312 | return Error::new( |
313 | span, |
314 | "Can only generate ZeroFrom impls for types with lifetimes" , |
315 | ) |
316 | .to_compile_error(); |
317 | }; |
318 | |
319 | let mut field_inits = sized_fields |
320 | .iter() |
321 | .map(|f| { |
322 | let ty = &f.field.ty; |
323 | let accessor = &f.accessor; |
324 | let setter = f.setter(); |
325 | quote!(#setter <#ty as zerovec::ule::AsULE>::from_unaligned(other.#accessor)) |
326 | }) |
327 | .collect::<Vec<_>>(); |
328 | |
329 | unsized_field_info.push_zf_setters(lt, &mut field_inits); |
330 | |
331 | let field_inits = utils::wrap_field_inits(&field_inits, fields); |
332 | let zerofrom_trait = quote!(zerovec::__zerovec_internal_reexport::ZeroFrom); |
333 | quote!( |
334 | impl <#lt> #zerofrom_trait <#lt, #ule_name> for #name <#lt> { |
335 | fn zero_from(other: &#lt #ule_name) -> Self { |
336 | Self #field_inits |
337 | } |
338 | } |
339 | ) |
340 | } |
341 | |
342 | fn make_encode_impl( |
343 | sized_fields: &[FieldInfo], |
344 | unsized_field_info: &UnsizedFields, |
345 | name: &Ident, |
346 | ule_name: &Ident, |
347 | maybe_lt_bound: &Option<TokenStream2>, |
348 | ) -> TokenStream2 { |
349 | let mut lengths = vec![]; |
350 | |
351 | for field in sized_fields { |
352 | let ty = &field.field.ty; |
353 | lengths.push(quote!(::core::mem::size_of::<<#ty as zerovec::ule::AsULE>::ULE>())); |
354 | } |
355 | |
356 | let (encoders, remaining_offset) = utils::generate_per_field_offsets( |
357 | sized_fields, |
358 | true, |
359 | |field, prev_offset_ident, size_ident| { |
360 | let ty = &field.field.ty; |
361 | let accessor = &field.accessor; |
362 | quote!( |
363 | #[allow(clippy::indexing_slicing)] // generate_per_field_offsets produces valid indices |
364 | let out = &mut dst[#prev_offset_ident .. #prev_offset_ident + #size_ident]; |
365 | let unaligned = zerovec::ule::AsULE::to_unaligned(self.#accessor); |
366 | let unaligned_slice = &[unaligned]; |
367 | let src = <<#ty as zerovec::ule::AsULE>::ULE as zerovec::ule::ULE>::as_byte_slice(unaligned_slice); |
368 | out.copy_from_slice(src); |
369 | ) |
370 | }, |
371 | ); |
372 | |
373 | let last_encode_len = unsized_field_info.encode_len(); |
374 | let last_encode_write = unsized_field_info.encode_write(quote!(out)); |
375 | quote!( |
376 | unsafe impl #maybe_lt_bound zerovec::ule::EncodeAsVarULE<#ule_name> for #name #maybe_lt_bound { |
377 | // Safety: unimplemented as the other two are implemented |
378 | fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { |
379 | unreachable!("other two methods implemented" ) |
380 | } |
381 | |
382 | // Safety: returns the total length of the ULE form by adding up the lengths of each element's ULE forms |
383 | fn encode_var_ule_len(&self) -> usize { |
384 | #(#lengths +)* #last_encode_len |
385 | } |
386 | |
387 | // Safety: converts each element to ULE form and writes them in sequence |
388 | fn encode_var_ule_write(&self, mut dst: &mut [u8]) { |
389 | debug_assert_eq!(self.encode_var_ule_len(), dst.len()); |
390 | #encoders |
391 | |
392 | #[allow(clippy::indexing_slicing)] // generate_per_field_offsets produces valid remainder |
393 | let out = &mut dst[#remaining_offset..]; |
394 | #last_encode_write |
395 | } |
396 | } |
397 | |
398 | // This second impl exists to allow for using EncodeAsVarULE without cloning |
399 | // |
400 | // A blanket impl cannot exist without coherence issues |
401 | unsafe impl #maybe_lt_bound zerovec::ule::EncodeAsVarULE<#ule_name> for &'_ #name #maybe_lt_bound { |
402 | // Safety: unimplemented as the other two are implemented |
403 | fn encode_var_ule_as_slices<R>(&self, cb: impl FnOnce(&[&[u8]]) -> R) -> R { |
404 | unreachable!("other two methods implemented" ) |
405 | } |
406 | |
407 | // Safety: returns the total length of the ULE form by adding up the lengths of each element's ULE forms |
408 | fn encode_var_ule_len(&self) -> usize { |
409 | (**self).encode_var_ule_len() |
410 | } |
411 | |
412 | // Safety: converts each element to ULE form and writes them in sequence |
413 | fn encode_var_ule_write(&self, mut dst: &mut [u8]) { |
414 | (**self).encode_var_ule_write(dst) |
415 | } |
416 | } |
417 | ) |
418 | } |
419 | |
420 | /// Represents a VarULE-compatible type that would typically |
421 | /// be found behind a `Cow<'a, _>` in the last field, and is represented |
422 | /// roughly the same in owned and borrowed versions |
423 | #[derive (Copy, Clone, Debug)] |
424 | enum OwnULETy<'a> { |
425 | /// [T] where T: AsULE<ULE = Self> |
426 | Slice(&'a Type), |
427 | /// str |
428 | Str, |
429 | } |
430 | |
431 | /// Represents the type of the last field of the struct |
432 | #[derive (Clone, Debug)] |
433 | enum UnsizedFieldKind<'a> { |
434 | Cow(OwnULETy<'a>), |
435 | ZeroVec(&'a Type), |
436 | VarZeroVec(&'a Type), |
437 | /// Custom VarULE type, and the identifier corresponding to the VarULE type |
438 | Custom(&'a TypePath, Ident), |
439 | |
440 | // Generally you should be using the above ones for maximum zero-copy, but these will still work |
441 | Growable(OwnULETy<'a>), |
442 | Boxed(OwnULETy<'a>), |
443 | Ref(OwnULETy<'a>), |
444 | } |
445 | |
446 | #[derive (Clone, Debug)] |
447 | struct UnsizedField<'a> { |
448 | kind: UnsizedFieldKind<'a>, |
449 | field: FieldInfo<'a>, |
450 | } |
451 | |
452 | struct UnsizedFields<'a> { |
453 | fields: Vec<UnsizedField<'a>>, |
454 | } |
455 | |
456 | impl<'a> UnsizedFields<'a> { |
457 | fn new(fields: Vec<UnsizedField<'a>>) -> Self { |
458 | assert!(!fields.is_empty(), "Must have at least one unsized field" ); |
459 | Self { fields } |
460 | } |
461 | |
462 | // Get the corresponding VarULE type that can store all of these |
463 | fn varule_ty(&self) -> TokenStream2 { |
464 | if self.fields.len() == 1 { |
465 | self.fields[0].kind.varule_ty() |
466 | } else { |
467 | quote!(zerovec::ule::MultiFieldsULE) |
468 | } |
469 | } |
470 | |
471 | // Get the accessor field name in the VarULE type |
472 | fn varule_accessor(&self) -> TokenStream2 { |
473 | if self.fields.len() == 1 { |
474 | self.fields[0].field.accessor.clone() |
475 | } else if self.fields[0].field.field.ident.is_some() { |
476 | quote!(unsized_fields) |
477 | } else { |
478 | // first unsized field |
479 | self.fields[0].field.accessor.clone() |
480 | } |
481 | } |
482 | |
483 | // Get the setter for this type for use in struct definition/creation syntax |
484 | fn varule_setter(&self) -> TokenStream2 { |
485 | if self.fields.len() == 1 { |
486 | self.fields[0].field.setter() |
487 | } else if self.fields[0].field.field.ident.is_some() { |
488 | quote!(unsized_fields: ) |
489 | } else { |
490 | quote!() |
491 | } |
492 | } |
493 | |
494 | fn varule_vis(&self) -> TokenStream2 { |
495 | if self.fields.len() == 1 { |
496 | self.fields[0].field.field.vis.to_token_stream() |
497 | } else { |
498 | // Always private |
499 | quote!() |
500 | } |
501 | } |
502 | |
503 | // Check if the type has a ZeroFrom impl |
504 | fn has_zf(&self) -> bool { |
505 | self.fields.iter().all(|f| f.kind.has_zf()) |
506 | } |
507 | |
508 | // Takes all unsized fields on self and encodes them into a byte slice `out` |
509 | fn encode_write(&self, out: TokenStream2) -> TokenStream2 { |
510 | if self.fields.len() == 1 { |
511 | self.fields[0].encode_func(quote!(encode_var_ule_write), quote!(#out)) |
512 | } else { |
513 | let mut lengths = vec![]; |
514 | let mut writers = vec![]; |
515 | for (i, field) in self.fields.iter().enumerate() { |
516 | lengths.push(field.encode_func(quote!(encode_var_ule_len), quote!())); |
517 | let (encodeable_ty, encodeable) = field.encodeable_tokens(); |
518 | let varule_ty = field.kind.varule_ty(); |
519 | writers |
520 | .push(quote!(multi.set_field_at::<#varule_ty, #encodeable_ty>(#i, #encodeable))) |
521 | } |
522 | |
523 | quote!( |
524 | let lengths = [#(#lengths),*]; |
525 | let mut multi = zerovec::ule::MultiFieldsULE::new_from_lengths_partially_initialized(&lengths, #out); |
526 | unsafe { |
527 | #(#writers;)* |
528 | } |
529 | ) |
530 | } |
531 | } |
532 | |
533 | // Takes all unsized fields on self and returns the length needed for encoding into a byte slice |
534 | fn encode_len(&self) -> TokenStream2 { |
535 | if self.fields.len() == 1 { |
536 | self.fields[0].encode_func(quote!(encode_var_ule_len), quote!()) |
537 | } else { |
538 | let mut lengths = vec![]; |
539 | for field in self.fields.iter() { |
540 | lengths.push(field.encode_func(quote!(encode_var_ule_len), quote!())); |
541 | } |
542 | quote!(zerovec::ule::MultiFieldsULE::compute_encoded_len_for(&[#(#lengths),*])) |
543 | } |
544 | } |
545 | |
546 | /// Constructs ZeroFrom setters for each field of the stack type |
547 | fn push_zf_setters(&self, lt: &Lifetime, field_inits: &mut Vec<TokenStream2>) { |
548 | let zerofrom_trait = quote!(zerovec::__zerovec_internal_reexport::ZeroFrom); |
549 | if self.fields.len() == 1 { |
550 | let accessor = self.fields[0].field.accessor.clone(); |
551 | let setter = self.fields[0].field.setter(); |
552 | let last_field_ty = &self.fields[0].field.field.ty; |
553 | let last_field_ule_ty = self.fields[0].kind.varule_ty(); |
554 | field_inits.push(quote!(#setter <#last_field_ty as #zerofrom_trait <#lt, #last_field_ule_ty>>::zero_from(&other.#accessor) )); |
555 | } else { |
556 | for field in self.fields.iter() { |
557 | let setter = field.field.setter(); |
558 | let getter = field.field.getter(); |
559 | let field_ty = &field.field.field.ty; |
560 | let field_ule_ty = field.kind.varule_ty(); |
561 | |
562 | field_inits.push(quote!(#setter |
563 | <#field_ty as #zerofrom_trait <#lt, #field_ule_ty>>::zero_from(&other.#getter()) |
564 | )); |
565 | } |
566 | } |
567 | } |
568 | |
569 | fn maybe_multi_getters(&self) -> Option<TokenStream2> { |
570 | if self.fields.len() == 1 { |
571 | None |
572 | } else { |
573 | let multi_accessor = self.varule_accessor(); |
574 | let field_getters = self.fields.iter().enumerate().map(|(i, field)| { |
575 | let getter = field.field.getter(); |
576 | |
577 | let field_ule_ty = field.kind.varule_ty(); |
578 | let doc_name = field.field.getter_doc_name(); |
579 | let doc = format!("Access the VarULE type behind {doc_name}" ); |
580 | quote!( |
581 | #[doc = #doc] |
582 | pub fn #getter<'a>(&'a self) -> &'a #field_ule_ty { |
583 | unsafe { |
584 | self.#multi_accessor.get_field::<#field_ule_ty>(#i) |
585 | } |
586 | } |
587 | ) |
588 | }); |
589 | |
590 | Some(quote!(#(#field_getters)*)) |
591 | } |
592 | } |
593 | |
594 | /// In case this needs custom validation code, return it |
595 | /// |
596 | /// The code will validate a variable known as `last_field_bytes` |
597 | fn varule_validator(&self) -> Option<TokenStream2> { |
598 | if self.fields.len() == 1 { |
599 | None |
600 | } else { |
601 | let mut validators = vec![]; |
602 | for (i, field) in self.fields.iter().enumerate() { |
603 | let varule_ty = field.kind.varule_ty(); |
604 | validators.push(quote!(multi.validate_field::<#varule_ty>(#i)?;)); |
605 | } |
606 | |
607 | Some(quote!( |
608 | let multi = zerovec::ule::MultiFieldsULE::parse_byte_slice(last_field_bytes)?; |
609 | unsafe { |
610 | #(#validators)* |
611 | } |
612 | )) |
613 | } |
614 | } |
615 | } |
616 | |
617 | impl<'a> UnsizedField<'a> { |
618 | fn new( |
619 | field: &'a Field, |
620 | index: usize, |
621 | custom_varule_ident: Option<Ident>, |
622 | ) -> Result<Self, String> { |
623 | Ok(UnsizedField { |
624 | kind: UnsizedFieldKind::new(&field.ty, custom_varule_ident)?, |
625 | field: FieldInfo::new_for_field(field, index), |
626 | }) |
627 | } |
628 | |
629 | /// Call `<Self as EncodeAsVarULE<V>>::#method(self.accessor #additional_args)` after adjusting |
630 | /// Self and self.accessor to be the right types |
631 | fn encode_func(&self, method: TokenStream2, additional_args: TokenStream2) -> TokenStream2 { |
632 | let encodeas_trait = quote!(zerovec::ule::EncodeAsVarULE); |
633 | let (encodeable_ty, encodeable) = self.encodeable_tokens(); |
634 | let varule_ty = self.kind.varule_ty(); |
635 | quote!(<#encodeable_ty as #encodeas_trait<#varule_ty>>::#method(#encodeable, #additional_args)) |
636 | } |
637 | |
638 | /// Returns (encodeable_ty, encodeable) |
639 | fn encodeable_tokens(&self) -> (TokenStream2, TokenStream2) { |
640 | let accessor = self.field.accessor.clone(); |
641 | let value = quote!(self.#accessor); |
642 | let encodeable = self.kind.encodeable_value(value); |
643 | let encodeable_ty = self.kind.encodeable_ty(); |
644 | (encodeable_ty, encodeable) |
645 | } |
646 | } |
647 | |
648 | impl<'a> UnsizedFieldKind<'a> { |
649 | /// Construct a UnsizedFieldKind for the type of a UnsizedFieldKind if possible |
650 | fn new( |
651 | ty: &'a Type, |
652 | custom_varule_ident: Option<Ident>, |
653 | ) -> Result<UnsizedFieldKind<'a>, String> { |
654 | static PATH_TYPE_IDENTITY_ERROR: &str = |
655 | "Can only automatically detect corresponding VarULE types for path types \ |
656 | that are Cow, ZeroVec, VarZeroVec, Box, String, or Vec" ; |
657 | static PATH_TYPE_GENERICS_ERROR: &str = |
658 | "Can only automatically detect corresponding VarULE types for path \ |
659 | types with at most one lifetime and at most one generic parameter. VarZeroVecFormat |
660 | types are not currently supported" ; |
661 | match *ty { |
662 | Type::Reference(ref tyref) => OwnULETy::new(&tyref.elem, "reference" ).map(UnsizedFieldKind::Ref), |
663 | Type::Path(ref typath) => { |
664 | if let Some(custom_varule_ident) = custom_varule_ident { |
665 | return Ok(UnsizedFieldKind::Custom(typath, custom_varule_ident)); |
666 | } |
667 | if typath.path.segments.len() != 1 { |
668 | return Err("Can only automatically detect corresponding VarULE types for \ |
669 | path types with a single path segment" .into()); |
670 | } |
671 | let segment = typath.path.segments.first().unwrap(); |
672 | match segment.arguments { |
673 | PathArguments::None => { |
674 | if segment.ident == "String" { |
675 | Ok(UnsizedFieldKind::Growable(OwnULETy::Str)) |
676 | } else { |
677 | Err(PATH_TYPE_IDENTITY_ERROR.into()) |
678 | } |
679 | } |
680 | PathArguments::AngleBracketed(ref params) => { |
681 | // At most one lifetime and exactly one generic parameter |
682 | let mut lifetime = None; |
683 | let mut generic = None; |
684 | for param in ¶ms.args { |
685 | match param { |
686 | GenericArgument::Lifetime(ref lt) if lifetime.is_none() => { |
687 | lifetime = Some(lt) |
688 | } |
689 | GenericArgument::Type(ref ty) if generic.is_none() => { |
690 | generic = Some(ty) |
691 | } |
692 | _ => return Err(PATH_TYPE_GENERICS_ERROR.into()), |
693 | } |
694 | } |
695 | |
696 | // Must be exactly one generic parameter |
697 | // (we've handled the zero generics case already) |
698 | let generic = if let Some(g) = generic { |
699 | g |
700 | } else { |
701 | return Err(PATH_TYPE_GENERICS_ERROR.into()); |
702 | }; |
703 | |
704 | let ident = segment.ident.to_string(); |
705 | |
706 | if lifetime.is_some() { |
707 | match &*ident { |
708 | "ZeroVec" => Ok(UnsizedFieldKind::ZeroVec(generic)), |
709 | "VarZeroVec" => Ok(UnsizedFieldKind::VarZeroVec(generic)), |
710 | "Cow" => OwnULETy::new(generic, "Cow" ).map(UnsizedFieldKind::Cow), |
711 | _ => Err(PATH_TYPE_IDENTITY_ERROR.into()), |
712 | } |
713 | } else { |
714 | match &*ident { |
715 | "Vec" => Ok(UnsizedFieldKind::Growable(OwnULETy::Slice(generic))), |
716 | "Box" => OwnULETy::new(generic, "Box" ).map(UnsizedFieldKind::Boxed), |
717 | _ => Err(PATH_TYPE_IDENTITY_ERROR.into()), |
718 | } |
719 | } |
720 | } |
721 | _ => Err("Can only automatically detect corresponding VarULE types for path types \ |
722 | with none or angle bracketed generics" .into()), |
723 | } |
724 | } |
725 | _ => Err("Can only automatically detect corresponding VarULE types for path and reference types" .into()), |
726 | } |
727 | } |
728 | /// Get the tokens for the corresponding VarULE type |
729 | fn varule_ty(&self) -> TokenStream2 { |
730 | match *self { |
731 | Self::Ref(ref inner) |
732 | | Self::Cow(ref inner) |
733 | | Self::Boxed(ref inner) |
734 | | Self::Growable(ref inner) => { |
735 | let inner_ule = inner.varule_ty(); |
736 | quote!(#inner_ule) |
737 | } |
738 | Self::Custom(_, ref name) => quote!(#name), |
739 | Self::ZeroVec(ref inner) => quote!(zerovec::ZeroSlice<#inner>), |
740 | Self::VarZeroVec(ref inner) => quote!(zerovec::VarZeroSlice<#inner>), |
741 | } |
742 | } |
743 | |
744 | // Takes expr `value` and returns it as a value that can be encoded via EncodeAsVarULE |
745 | fn encodeable_value(&self, value: TokenStream2) -> TokenStream2 { |
746 | match *self { |
747 | Self::Ref(_) | Self::Cow(_) | Self::Growable(_) | Self::Boxed(_) => quote!(&*#value), |
748 | |
749 | Self::Custom(..) => quote!(&#value), |
750 | Self::ZeroVec(_) | Self::VarZeroVec(_) => quote!(&*#value), |
751 | } |
752 | } |
753 | |
754 | /// Returns the EncodeAsVarULE type this can be represented as, the same returned by encodeable_value() |
755 | fn encodeable_ty(&self) -> TokenStream2 { |
756 | match *self { |
757 | Self::Ref(ref inner) |
758 | | Self::Cow(ref inner) |
759 | | Self::Growable(ref inner) |
760 | | Self::Boxed(ref inner) => inner.varule_ty(), |
761 | |
762 | Self::Custom(ref path, _) => quote!(#path), |
763 | Self::ZeroVec(ref ty) => quote!(zerovec::ZeroSlice<#ty>), |
764 | Self::VarZeroVec(ref ty) => quote!(zerovec::VarZeroSlice<#ty>), |
765 | } |
766 | } |
767 | |
768 | fn has_zf(&self) -> bool { |
769 | matches!( |
770 | *self, |
771 | Self::Ref(_) | Self::Cow(_) | Self::ZeroVec(_) | Self::VarZeroVec(_) | Self::Custom(..) |
772 | ) |
773 | } |
774 | } |
775 | |
776 | impl<'a> OwnULETy<'a> { |
777 | fn new(ty: &'a Type, context: &str) -> Result<Self, String> { |
778 | match *ty { |
779 | Type::Slice(ref slice: &TypeSlice) => Ok(OwnULETy::Slice(&slice.elem)), |
780 | Type::Path(ref typath: &TypePath) => { |
781 | if typath.path.is_ident("str" ) { |
782 | Ok(OwnULETy::Str) |
783 | } else { |
784 | Err(format!("Cannot automatically detect corresponding VarULE type for non-str path type inside a {context}" )) |
785 | } |
786 | } |
787 | _ => Err(format!("Cannot automatically detect corresponding VarULE type for non-slice/path type inside a {context}" )), |
788 | } |
789 | } |
790 | |
791 | /// Get the tokens for the corresponding VarULE type |
792 | fn varule_ty(&self) -> TokenStream2 { |
793 | match *self { |
794 | OwnULETy::Slice(s: &Type) => quote!([#s]), |
795 | OwnULETy::Str => quote!(str), |
796 | } |
797 | } |
798 | } |
799 | |