borsh_derive/
lib.rs

1#![recursion_limit = "128"]
2#![cfg_attr(
3    feature = "force_exhaustive_checks",
4    feature(non_exhaustive_omitted_patterns_lint)
5)]
6
7extern crate proc_macro;
8use proc_macro::TokenStream;
9#[cfg(feature = "schema")]
10use proc_macro2::Span;
11use syn::{DeriveInput, Error, ItemEnum, ItemStruct, ItemUnion, Path};
12
13///  by convention, local to borsh-derive crate, imports from proc_macro (1) are not allowed in `internals` module or in any of its submodules.
14mod internals;
15
16use crate::internals::attributes::item;
17
18#[cfg(feature = "schema")]
19use internals::schema;
20use internals::{cratename, deserialize, serialize};
21
22fn check_attrs_get_cratename(input: &TokenStream) -> Result<Path, Error> {
23    let input = input.clone();
24
25    let derive_input = syn::parse::<DeriveInput>(input)?;
26
27    item::check_attributes(&derive_input)?;
28
29    cratename::get(&derive_input.attrs)
30}
31
32/**
33# derive proc-macro for `borsh::ser::BorshSerialize` trait
34
35## Bounds
36
37Generally, `BorshSerialize` adds `borsh::ser::BorshSerialize` bound to any type parameter
38found in item's fields.
39
40```ignore
41/// impl<U, V> borsh::ser::BorshSerialize for A<U, V>
42/// where
43///     U: borsh::ser::BorshSerialize,
44///     V: borsh::ser::BorshSerialize,
45#[derive(BorshSerialize)]
46struct A<U, V> {
47    x: U,
48    y: V,
49}
50```
51
52```ignore
53/// impl<U, V> borsh::ser::BorshSerialize for A<U, V>
54/// where
55///     U: borsh::ser::BorshSerialize,
56#[derive(BorshSerialize)]
57struct A<U, V> {
58    x: U,
59    #[borsh(skip)]
60    y: V,
61}
62```
63
64## Attributes
65
66### 1. `#[borsh(crate = "path::to::borsh")]` (item level attribute)
67
68###### syntax
69
70Attribute takes literal string value, which is the syn's [Path] to `borsh` crate used.
71
72###### usage
73
74Attribute is optional.
75
761. If the attribute is not provided, [crate_name](proc_macro_crate::crate_name) is used to find a version of `borsh`
77   in `[dependencies]` of the relevant `Cargo.toml`. If there is no match, a compilation error, similar to the following, is raised:
78
79```bash
80 1  error: proc-macro derive panicked
81   --> path/to/file.rs:27:10
82    |
83 27 | #[derive(BorshSerialize, BorshDeserialize)]
84    |          ^^^^^^^^^^^^^^
85    |
86    = help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/path/to/Cargo.toml" }
87```
88
892. If the attribute is provided, the check for `borsh` in `[dependencies]` of the relevant `Cargo.toml` is skipped.
90
91Examples of usage:
92
93```ignore
94use reexporter::borsh::BorshSerialize;
95
96// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
97#[derive(BorshSerialize)]
98#[borsh(crate = "reexporter::borsh")]
99struct B {
100    x: u64,
101    y: i32,
102    c: String,
103}
104```
105
106```ignore
107use reexporter::borsh::{self, BorshSerialize};
108
109// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
110#[derive(BorshSerialize)]
111#[borsh(crate = "borsh")]
112struct B {
113    x: u64,
114    y: i32,
115    c: String,
116}
117```
118
119### 2. `borsh(use_discriminant=<bool>)` (item level attribute)
120This attribute is only applicable to enums.
121`use_discriminant` allows to override the default behavior of serialization of enums with explicit discriminant.
122`use_discriminant` is `false` behaves like version of borsh of 0.10.3.
123You must specify `use_discriminant` for all enums with explicit discriminants in your project.
124
125This is equivalent of borsh version 0.10.3 (explicit discriminant is ignored and this enum is equivalent to `A` without explicit discriminant):
126```ignore
127#[derive(BorshSerialize)]
128#[borsh(use_discriminant = false)]
129enum A {
130    A
131    B = 10,
132}
133```
134
135To have explicit discriminant value serialized as is, you must specify `borsh(use_discriminant=true)` for enum.
136```ignore
137#[derive(BorshSerialize)]
138#[borsh(use_discriminant = true)]
139enum B {
140    A
141    B = 10,
142}
143```
144
145###### borsh, expressions, evaluating to `isize`, as discriminant
146This case is not supported:
147```ignore
148const fn discrim() -> isize {
149    0x14
150}
151
152#[derive(BorshSerialize)]
153#[borsh(use_discriminant = true)]
154enum X {
155    A,
156    B = discrim(), // expressions, evaluating to `isize`, which are allowed outside of `borsh` context
157    C,
158    D,
159    E = 10,
160    F,
161}
162```
163
164###### borsh explicit discriminant does not support literal values outside of u8 range
165This is not supported:
166```ignore
167#[derive(BorshSerialize)]
168#[borsh(use_discriminant = true)]
169enum X {
170    A,
171    B = 0x100, // literal values outside of `u8` range
172    C,
173    D,
174    E = 10,
175    F,
176}
177```
178
179### 3. `#[borsh(skip)]` (field level attribute)
180
181`#[borsh(skip)]` makes derive skip serializing annotated field.
182
183`#[borsh(skip)]` makes derive skip adding any type parameters, present in the field, to parameters bound by `borsh::ser::BorshSerialize`.
184
185```ignore
186#[derive(BorshSerialize)]
187struct A {
188    x: u64,
189    #[borsh(skip)]
190    y: f32,
191}
192```
193
194### 4. `#[borsh(bound(serialize = ...))]` (field level attribute)
195
196###### syntax
197
198Attribute takes literal string value, which is a comma-separated list of syn's [WherePredicate](syn::WherePredicate)-s, which may be empty.
199
200###### usage
201
202Attribute adds possibility to override bounds for `BorshSerialize` in order to enable:
203
2041. removal of bounds on type parameters from struct/enum definition itself and moving them to the trait's implementation block.
2052. fixing complex cases, when derive hasn't figured out the right bounds on type parameters automatically.
206
207```ignore
208/// additional bound `T: Ord` (required by `HashMap`) is injected into
209/// derived trait implementation via attribute to avoid adding the bounds on the struct itself
210#[derive(BorshSerialize)]
211struct A<T, U> {
212    a: String,
213    #[borsh(bound(serialize =
214        "T: borsh::ser::BorshSerialize + Ord,
215         U: borsh::ser::BorshSerialize"))]
216    b: HashMap<T, U>,
217}
218```
219
220
221```ignore
222/// derive here figures the bound erroneously as `T: borsh::ser::BorshSerialize`
223#[derive(BorshSerialize)]
224struct A<T, V>
225where
226    T: TraitName,
227{
228    #[borsh(bound(serialize = "<T as TraitName>::Associated: borsh::ser::BorshSerialize"))]
229    field: <T as TraitName>::Associated,
230    another: V,
231}
232```
233
234###### interaction with `#[borsh(skip)]`
235
236`#[borsh(bound(serialize = ...))]` replaces bounds, which are derived automatically,
237irrelevant of whether `#[borsh(skip)]` attribute is present.
238
239### 5. `#[borsh(serialize_with = ...)]` (field level attribute)
240
241###### syntax
242
243Attribute takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
244
245###### usage
246
247Attribute adds possibility to specify full path of function, optionally qualified with generics,
248with which to serialize the annotated field.
249
250It may be used when `BorshSerialize` cannot be implemented for field's type, if it's from foreign crate.
251
252It may be used to override the implementation of serialization for some other reason.
253
254```ignore
255use indexmap::IndexMap;
256
257mod index_map_impl {
258    use super::IndexMap;
259    use core::hash::Hash;
260
261    pub fn serialize_index_map<
262        K: borsh::ser::BorshSerialize,
263        V: borsh::ser::BorshSerialize,
264        W: borsh::io::Write,
265    >(
266        obj: &IndexMap<K, V>,
267        writer: &mut W,
268    ) -> ::core::result::Result<(), borsh::io::Error> {
269        let key_value_tuples = obj.iter().collect::<Vec<_>>();
270        borsh::BorshSerialize::serialize(&key_value_tuples, writer)?;
271        Ok(())
272    }
273}
274
275#[derive(BorshSerialize)]
276struct B<K, V> {
277    #[borsh(
278        serialize_with = "index_map_impl::serialize_index_map",
279    )]
280    x: IndexMap<K, V>,
281    y: String,
282}
283```
284
285###### usage (comprehensive example)
286
287[borsh/examples/serde_json_value.rs](https://github.com/near/borsh-rs/blob/master/borsh/examples/serde_json_value.rs) is
288a more complex example of how the attribute may be used.
289
290###### interaction with `#[borsh(skip)]`
291
292`#[borsh(serialize_with = ...)]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
293
294*/
295#[proc_macro_derive(BorshSerialize, attributes(borsh))]
296pub fn borsh_serialize(input: TokenStream) -> TokenStream {
297    let cratename = match check_attrs_get_cratename(&input) {
298        Ok(cratename) => cratename,
299        Err(err) => {
300            return err.to_compile_error().into();
301        }
302    };
303
304    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
305        serialize::structs::process(&input, cratename)
306    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
307        serialize::enums::process(&input, cratename)
308    } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
309        serialize::unions::process(&input, cratename)
310    } else {
311        // Derive macros can only be defined on structs, enums, and unions.
312        unreachable!()
313    };
314    TokenStream::from(match res {
315        Ok(res) => res,
316        Err(err) => err.to_compile_error(),
317    })
318}
319
320/**
321# derive proc-macro for `borsh::de::BorshDeserialize` trait
322
323## Bounds
324
325Generally, `BorshDeserialize` adds `borsh::de::BorshDeserialize` bound to any type parameter
326found in item's fields and `core::default::Default` bound to any type parameter found
327in item's skipped fields.
328
329```ignore
330/// impl<U, V> borsh::de::BorshDeserialize for A<U, V>
331/// where
332///     U: borsh::de::BorshDeserialize,
333///     V: borsh::de::BorshDeserialize,
334#[derive(BorshDeserialize)]
335struct A<U, V> {
336    x: U,
337    y: V,
338}
339```
340
341```ignore
342/// impl<U, V> borsh::de::BorshDeserialize for A<U, V>
343/// where
344///     U: borsh::de::BorshDeserialize,
345///     V: core::default::Default,
346#[derive(BorshDeserialize)]
347struct A<U, V> {
348    x: U,
349    #[borsh(skip)]
350    y: V,
351}
352```
353
354
355## Attributes
356
357### 1. `#[borsh(crate = "path::to::borsh")]` (item level attribute)
358
359###### syntax
360
361Attribute takes literal string value, which is the syn's [Path] to `borsh` crate used.
362
363###### usage
364
365Attribute is optional.
366
3671. If the attribute is not provided, [crate_name](proc_macro_crate::crate_name) is used to find a version of `borsh`
368   in `[dependencies]` of the relevant `Cargo.toml`. If there is no match, a compilation error, similar to the following, is raised:
369
370```bash
371 1  error: proc-macro derive panicked
372   --> path/to/file.rs:27:10
373    |
374 27 | #[derive(BorshDeserialize, BorshSerialize)]
375    |          ^^^^^^^^^^^^^^^^
376    |
377    = help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/path/to/Cargo.toml" }
378```
379
3802. If the attribute is provided, the check for `borsh` in `[dependencies]` of the relevant `Cargo.toml` is skipped.
381
382Examples of usage:
383
384```ignore
385use reexporter::borsh::BorshDeserialize;
386
387// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
388#[derive(BorshDeserialize)]
389#[borsh(crate = "reexporter::borsh")]
390struct B {
391    x: u64,
392    y: i32,
393    c: String,
394}
395```
396
397```ignore
398use reexporter::borsh::{self, BorshDeserialize};
399
400// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
401#[derive(BorshDeserialize)]
402#[borsh(crate = "borsh")]
403struct B {
404    x: u64,
405    y: i32,
406    c: String,
407}
408```
409
410### 2. `#[borsh(init=...)]` (item level attribute)
411
412###### syntax
413
414Attribute's value is syn's [Path]-s, passed to borsh top level meta attribute as value of `init` argument.
415
416###### usage
417
418`#[borsh(init=...)]` allows to automatically run an initialization function right after deserialization.
419This adds a lot of convenience for objects that are architectured to be used as strictly immutable.
420
421```ignore
422#[derive(BorshDeserialize)]
423#[borsh(init=init)]
424struct Message {
425    message: String,
426    timestamp: u64,
427    public_key: CryptoKey,
428    signature: CryptoSignature,
429    hash: CryptoHash,
430}
431
432impl Message {
433    pub fn init(&mut self) {
434        self.hash = CryptoHash::new().write_string(self.message).write_u64(self.timestamp);
435        self.signature.verify(self.hash, self.public_key);
436    }
437}
438```
439
440### 3. `borsh(use_discriminant=<bool>)` (item level attribute)
441
442This attribute is only applicable to enums.
443`use_discriminant` allows to override the default behavior of serialization of enums with explicit discriminant.
444`use_discriminant` is `false` behaves like version of borsh of 0.10.3.
445It's useful for backward compatibility and you can set this value to `false` to deserialise data serialised by older version of `borsh`.
446You must specify `use_discriminant` for all enums with explicit discriminants in your project.
447
448This is equivalent of borsh version 0.10.3 (explicit discriminant is ignored and this enum is equivalent to `A` without explicit discriminant):
449```ignore
450#[derive(BorshDeserialize)]
451#[borsh(use_discriminant = false)]
452enum A {
453    A
454    B = 10,
455}
456```
457
458To have explicit discriminant value serialized as is, you must specify `borsh(use_discriminant=true)` for enum.
459```ignore
460#[derive(BorshDeserialize)]
461#[borsh(use_discriminant = true)]
462enum B {
463    A
464    B = 10,
465}
466```
467
468
469###### borsh, expressions, evaluating to `isize`, as discriminant
470This case is not supported:
471```ignore
472const fn discrim() -> isize {
473    0x14
474}
475
476#[derive(BorshDeserialize)]
477#[borsh(use_discriminant = true)]
478enum X {
479    A,
480    B = discrim(), // expressions, evaluating to `isize`, which are allowed outside of `borsh` context
481    C,
482    D,
483    E = 10,
484    F,
485}
486```
487
488
489###### borsh explicit discriminant does not support literal values outside of u8 range.
490This is not supported:
491```ignore
492#[derive(BorshDeserialize)]
493#[borsh(use_discriminant = true)]
494enum X {
495    A,
496    B = 0x100, // literal values outside of `u8` range
497    C,
498    D,
499    E = 10,
500    F,
501}
502```
503
504
505### 4. `#[borsh(skip)]` (field level attribute)
506
507`#[borsh(skip)]` makes derive skip deserializing annotated field.
508
509`#[borsh(skip)]` makes derive skip adding any type parameters, present in the field, to parameters bound by `borsh::de::BorshDeserialize`.
510
511It adds `core::default::Default` bound to any
512parameters encountered in annotated field.
513
514
515```ignore
516#[derive(BorshDeserialize)]
517struct A {
518    x: u64,
519    #[borsh(skip)]
520    y: f32,
521}
522```
523
524
525### 5. `#[borsh(bound(deserialize = ...))]` (field level attribute)
526
527###### syntax
528
529Attribute takes literal string value, which is a comma-separated list of syn's [WherePredicate](syn::WherePredicate)-s, which may be empty.
530
531
532###### usage
533
534Attribute adds possibility to override bounds for `BorshDeserialize` in order to enable:
535
5361. removal of bounds on type parameters from struct/enum definition itself and moving them to the trait's implementation block.
5372. fixing complex cases, when derive hasn't figured out the right bounds on type parameters automatically.
538
539```ignore
540/// additional bounds `T: Ord + Hash + Eq` (required by `HashMap`) are injected into
541/// derived trait implementation via attribute to avoid adding the bounds on the struct itself
542#[derive(BorshDeserialize)]
543struct A<T, U> {
544    a: String,
545    #[borsh(bound(
546        deserialize =
547        "T: Ord + Hash + Eq + borsh::de::BorshDeserialize,
548         U: borsh::de::BorshDeserialize"
549    ))]
550    b: HashMap<T, U>,
551}
552```
553
554
555```ignore
556// derive here figures the bound erroneously as `T: borsh::de::BorshDeserialize,`
557#[derive(BorshDeserialize)]
558struct A<T, V>
559where
560    T: TraitName,
561{
562    #[borsh(bound(deserialize = "<T as TraitName>::Associated: borsh::de::BorshDeserialize"))]
563    field: <T as TraitName>::Associated,
564    another: V,
565}
566```
567
568###### interaction with `#[borsh(skip)]`
569
570`#[borsh(bound(deserialize = ...))]` replaces bounds, which are derived automatically,
571irrelevant of whether `#[borsh(skip)]` attribute is present.
572
573```ignore
574/// implicit derived `core::default::Default` bounds on `K` and `V` type parameters are removed by
575/// empty bound specified, as `HashMap` has its own `Default` implementation
576#[derive(BorshDeserialize)]
577struct A<K, V, U>(
578    #[borsh(skip, bound(deserialize = ""))]
579    HashMap<K, V>,
580    U,
581);
582```
583
584### 6. `#[borsh(deserialize_with = ...)]` (field level attribute)
585
586###### syntax
587
588Attribute takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
589
590###### usage
591
592Attribute adds possibility to specify full path of function, optionally qualified with generics,
593with which to deserialize the annotated field.
594
595It may be used when `BorshDeserialize` cannot be implemented for field's type, if it's from foreign crate.
596
597It may be used to override the implementation of deserialization for some other reason.
598
599```ignore
600use indexmap::IndexMap;
601
602mod index_map_impl {
603    use super::IndexMap;
604    use core::hash::Hash;
605
606    pub fn deserialize_index_map<
607        R: borsh::io::Read,
608        K: borsh::de::BorshDeserialize + Hash + Eq,
609        V: borsh::de::BorshDeserialize,
610    >(
611        reader: &mut R,
612    ) -> ::core::result::Result<IndexMap<K, V>, borsh::io::Error> {
613        let vec: Vec<(K, V)> = borsh::BorshDeserialize::deserialize_reader(reader)?;
614        let result: IndexMap<K, V> = vec.into_iter().collect();
615        Ok(result)
616    }
617}
618
619#[derive(BorshDeserialize)]
620struct B<K: Hash + Eq, V> {
621    #[borsh(
622        deserialize_with = "index_map_impl::deserialize_index_map",
623    )]
624    x: IndexMap<K, V>,
625    y: String,
626}
627```
628
629###### usage (comprehensive example)
630
631[borsh/examples/serde_json_value.rs](https://github.com/near/borsh-rs/blob/master/borsh/examples/serde_json_value.rs) is
632a more complex example of how the attribute may be used.
633
634###### interaction with `#[borsh(skip)]`
635
636`#[borsh(deserialize_with = ...)]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
637
638*/
639#[proc_macro_derive(BorshDeserialize, attributes(borsh))]
640pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
641    let cratename = match check_attrs_get_cratename(&input) {
642        Ok(cratename) => cratename,
643        Err(err) => {
644            return err.to_compile_error().into();
645        }
646    };
647
648    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
649        deserialize::structs::process(&input, cratename)
650    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
651        deserialize::enums::process(&input, cratename)
652    } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
653        deserialize::unions::process(&input, cratename)
654    } else {
655        // Derive macros can only be defined on structs, enums, and unions.
656        unreachable!()
657    };
658    TokenStream::from(match res {
659        Ok(res) => res,
660        Err(err) => err.to_compile_error(),
661    })
662}
663
664/**
665# derive proc-macro for `borsh::BorshSchema` trait
666
667## Bounds
668
669Generally, `BorshSchema` adds `borsh::BorshSchema` bound to any type parameter
670found in item's fields.
671
672```ignore
673/// impl<U, V> borsh::BorshSchema for A<U, V>
674/// where
675///     U: borsh::BorshSchema,
676///     V: borsh::BorshSchema,
677#[derive(BorshSchema)]
678struct A<U, V> {
679    x: U,
680    y: V,
681}
682```
683
684```ignore
685/// impl<U, V> borsh::BorshSchema for A<U, V>
686/// where
687///     U: borsh::BorshSchema,
688#[derive(BorshSchema)]
689struct A<U, V> {
690    x: U,
691    #[borsh(skip)]
692    y: V,
693}
694```
695
696## Attributes
697
698### 1. `#[borsh(crate = "path::to::borsh")]` (item level attribute)
699
700###### syntax
701
702Attribute takes literal string value, which is the syn's [Path] to `borsh` crate used.
703
704###### usage
705
706Attribute is optional.
707
7081. If the attribute is not provided, [crate_name](proc_macro_crate::crate_name) is used to find a version of `borsh`
709   in `[dependencies]` of the relevant `Cargo.toml`. If there is no match, a compilation error, similar to the following, is raised:
710
711```bash
712 1  error: proc-macro derive panicked
713   --> path/to/file.rs:27:10
714    |
715 27 | #[derive(BorshSchema, BorshSerialize)]
716    |          ^^^^^^^^^^^
717    |
718    = help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/path/to/Cargo.toml" }
719```
720
7212. If the attribute is provided, the check for `borsh` in `[dependencies]` of the relevant `Cargo.toml` is skipped.
722
723Examples of usage:
724
725```ignore
726use reexporter::borsh::BorshSchema;
727
728// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
729#[derive(BorshSchema)]
730#[borsh(crate = "reexporter::borsh")]
731struct B {
732    x: u64,
733    y: i32,
734    c: String,
735}
736```
737
738```ignore
739use reexporter::borsh::{self, BorshSchema};
740
741// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
742#[derive(BorshSchema)]
743#[borsh(crate = "borsh")]
744struct B {
745    x: u64,
746    y: i32,
747    c: String,
748}
749```
750
751### 2. `borsh(use_discriminant=<bool>)` (item level attribute)
752This attribute is only applicable to enums.
753`use_discriminant` allows to override the default behavior of serialization of enums with explicit discriminant.
754`use_discriminant` is `false` behaves like version of borsh of 0.10.3.
755You must specify `use_discriminant` for all enums with explicit discriminants in your project.
756
757This is equivalent of borsh version 0.10.3 (explicit discriminant is ignored and this enum is equivalent to `A` without explicit discriminant):
758```ignore
759#[derive(BorshSchema)]
760#[borsh(use_discriminant = false)]
761enum A {
762    A
763    B = 10,
764}
765```
766
767To have explicit discriminant value serialized as is, you must specify `borsh(use_discriminant=true)` for enum.
768```ignore
769#[derive(BorshSchema)]
770#[borsh(use_discriminant = true)]
771enum B {
772    A
773    B = 10,
774}
775```
776
777###### borsh, expressions, evaluating to `isize`, as discriminant
778This case is not supported:
779```ignore
780const fn discrim() -> isize {
781    0x14
782}
783
784#[derive(BorshSchema)]
785#[borsh(use_discriminant = true)]
786enum X {
787    A,
788    B = discrim(), // expressions, evaluating to `isize`, which are allowed outside of `borsh` context
789    C,
790    D,
791    E = 10,
792    F,
793}
794```
795
796###### borsh explicit discriminant does not support literal values outside of u8 range
797This is not supported:
798```ignore
799#[derive(BorshSchema)]
800#[borsh(use_discriminant = true)]
801enum X {
802    A,
803    B = 0x100, // literal values outside of `u8` range
804    C,
805    D,
806    E = 10,
807    F,
808}
809```
810
811### 3. `#[borsh(skip)]` (field level attribute)
812
813`#[borsh(skip)]` makes derive skip including schema from annotated field into schema's implementation.
814
815`#[borsh(skip)]` makes derive skip adding any type parameters, present in the field, to parameters bound by `borsh::BorshSchema`.
816
817```ignore
818#[derive(BorshSchema)]
819struct A {
820    x: u64,
821    #[borsh(skip)]
822    y: f32,
823}
824```
825
826### 4. `#[borsh(schema(params = ...))]` (field level attribute)
827
828###### syntax
829
830Attribute takes literal string value, which is a comma-separated list of `ParameterOverride`-s, which may be empty.
831
832###### usage
833It may be used in order to:
834
8351. fix complex cases, when derive hasn't figured out the right bounds on type parameters and
836   declaration parameters automatically.
8372. remove parameters, which do not take part in serialization/deserialization, from bounded ones and from declaration parameters.
838
839`ParameterOverride` describes an entry like `order_param => override_type`,
840
841e.g. `K => <K as TraitName>::Associated`.
842
843Such an entry instructs `BorshSchema` derive to:
844
8451. add `override_type` to types, bounded by `borsh::BorshSchema` in implementation block.
8462. add `<override_type>::declaration()` to parameters vector in `fn declaration()` method of `BorshSchema` trait that is being derived.
8473. the `order_param` is required to establish the same order in parameters vector (2.) as that of type parameters in generics of type, that `BorshSchema` is derived for.
8484. entries, specified for a field, together replace whatever would've been derived automatically for 1. and 2. .
849
850
851```ignore
852// derive here figures the bound erroneously as `T: borsh::BorshSchema` .
853// attribute replaces it with <T as TraitName>::Associated: borsh::BorshSchema`
854#[derive(BorshSchema)]
855struct A<V, T>
856where
857    T: TraitName,
858{
859    #[borsh(schema(params = "T => <T as TraitName>::Associated"))]
860    field: <T as TraitName>::Associated,
861    another: V,
862}
863```
864
865```ignore
866// K in PrimaryMap isn't stored during serialization / read during deserialization.
867// thus, it's not a parameter, relevant for `BorshSchema`
868// ...
869// impl<K: EntityRef, V> borsh::BorshSchema for A<K, V>
870// where
871//     V: borsh::BorshSchema,
872#[derive(BorshSchema)]
873struct A<K: EntityRef, V> {
874    #[borsh(
875        schema(
876            params = "V => V"
877        )
878    )]
879    x: PrimaryMap<K, V>,
880    y: String,
881}
882
883#[derive(BorshSchema)]
884pub struct PrimaryMap<K, V>
885where
886    K: EntityRef,
887{
888    elems: Vec<V>,
889    unused: PhantomData<K>,
890}
891```
892
893###### interaction with `#[borsh(skip)]`
894
895`#[borsh(schema(params = ...))]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
896
897### 5. `#[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]` (field level attribute)
898
899###### syntax
900
901Each of `declaration` and `definitions` nested sub-attributes takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
902
903Currently both `declaration` and `definitions` are required to be specified at the same time.
904
905###### usage
906
907Attribute adds possibility to specify full path of 2 functions, optionally qualified with generics,
908with which to generate borsh schema for annotated field.
909
910It may be used when `BorshSchema` cannot be implemented for field's type, if it's from foreign crate.
911
912It may be used to override the implementation of schema for some other reason.
913
914```ignore
915use indexmap::IndexMap;
916
917mod index_map_impl {
918    pub mod schema {
919        use std::collections::BTreeMap;
920
921        use borsh::{
922            schema::{Declaration, Definition},
923            BorshSchema,
924        };
925
926        pub fn declaration<K: borsh::BorshSchema, V: borsh::BorshSchema>() -> Declaration {
927            let params = vec![<K>::declaration(), <V>::declaration()];
928            format!(r#"{}<{}>"#, "IndexMap", params.join(", "))
929        }
930
931        pub fn add_definitions_recursively<K: borsh::BorshSchema, V: borsh::BorshSchema>(
932            definitions: &mut BTreeMap<Declaration, Definition>,
933        ) {
934            let definition = Definition::Sequence {
935                elements: <(K, V)>::declaration(),
936            };
937            let no_recursion_flag = definitions.get(&declaration::<K, V>()).is_none();
938            <() as BorshSchema>::add_definition(declaration::<K, V>(), definition, definitions);
939            if no_recursion_flag {
940                <(K, V)>::add_definitions_recursively(definitions);
941            }
942        }
943    }
944}
945
946#[derive(BorshSchema)]
947struct B<K, V> {
948    #[borsh(
949        schema(
950            with_funcs(
951                declaration = "index_map_impl::schema::declaration::<K, V>",
952                definitions = "index_map_impl::schema::add_definitions_recursively::<K, V>"
953            ),
954        )
955    )]
956    x: IndexMap<K, V>,
957    y: String,
958}
959```
960
961###### interaction with `#[borsh(skip)]`
962
963`#[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
964
965*/
966#[cfg(feature = "schema")]
967#[proc_macro_derive(BorshSchema, attributes(borsh))]
968pub fn borsh_schema(input: TokenStream) -> TokenStream {
969    let cratename = match check_attrs_get_cratename(&input) {
970        Ok(cratename) => cratename,
971        Err(err) => {
972            return err.to_compile_error().into();
973        }
974    };
975
976    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
977        schema::structs::process(&input, cratename)
978    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
979        schema::enums::process(&input, cratename)
980    } else if syn::parse::<ItemUnion>(input).is_ok() {
981        Err(syn::Error::new(
982            Span::call_site(),
983            "Borsh schema does not support unions yet.",
984        ))
985    } else {
986        // Derive macros can only be defined on structs, enums, and unions.
987        unreachable!()
988    };
989    TokenStream::from(match res {
990        Ok(res) => res,
991        Err(err) => err.to_compile_error(),
992    })
993}