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`
77in `[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###### interaction with `#[borsh(skip)]`
286
287`#[borsh(serialize_with = ...)]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
288
289
290*/
291#[proc_macro_derive(BorshSerialize, attributes(borsh))]
292pub fn borsh_serialize(input: TokenStream) -> TokenStream {
293    let cratename = match check_attrs_get_cratename(&input) {
294        Ok(cratename) => cratename,
295        Err(err) => {
296            return err.to_compile_error().into();
297        }
298    };
299
300    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
301        serialize::structs::process(&input, cratename)
302    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
303        serialize::enums::process(&input, cratename)
304    } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
305        serialize::unions::process(&input, cratename)
306    } else {
307        // Derive macros can only be defined on structs, enums, and unions.
308        unreachable!()
309    };
310    TokenStream::from(match res {
311        Ok(res) => res,
312        Err(err) => err.to_compile_error(),
313    })
314}
315
316/**
317# derive proc-macro for `borsh::de::BorshDeserialize` trait
318
319## Bounds
320
321Generally, `BorshDeserialize` adds `borsh::de::BorshDeserialize` bound to any type parameter
322found in item's fields and `core::default::Default` bound to any type parameter found
323in item's skipped fields.
324
325```ignore
326/// impl<U, V> borsh::de::BorshDeserialize for A<U, V>
327/// where
328///     U: borsh::de::BorshDeserialize,
329///     V: borsh::de::BorshDeserialize,
330#[derive(BorshDeserialize)]
331struct A<U, V> {
332    x: U,
333    y: V,
334}
335```
336
337```ignore
338/// impl<U, V> borsh::de::BorshDeserialize for A<U, V>
339/// where
340///     U: borsh::de::BorshDeserialize,
341///     V: core::default::Default,
342#[derive(BorshDeserialize)]
343struct A<U, V> {
344    x: U,
345    #[borsh(skip)]
346    y: V,
347}
348```
349
350
351## Attributes
352
353### 1. `#[borsh(crate = "path::to::borsh")]` (item level attribute)
354
355###### syntax
356
357Attribute takes literal string value, which is the syn's [Path] to `borsh` crate used.
358
359###### usage
360
361Attribute is optional.
362
3631. If the attribute is not provided, [crate_name](proc_macro_crate::crate_name) is used to find a version of `borsh`
364in `[dependencies]` of the relevant `Cargo.toml`. If there is no match, a compilation error, similar to the following, is raised:
365
366```bash
367 1  error: proc-macro derive panicked
368   --> path/to/file.rs:27:10
369    |
370 27 | #[derive(BorshDeserialize, BorshSerialize)]
371    |          ^^^^^^^^^^^^^^^^
372    |
373    = help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/path/to/Cargo.toml" }
374```
375
3762. If the attribute is provided, the check for `borsh` in `[dependencies]` of the relevant `Cargo.toml` is skipped.
377
378Examples of usage:
379
380```ignore
381use reexporter::borsh::BorshDeserialize;
382
383// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
384#[derive(BorshDeserialize)]
385#[borsh(crate = "reexporter::borsh")]
386struct B {
387    x: u64,
388    y: i32,
389    c: String,
390}
391```
392
393```ignore
394use reexporter::borsh::{self, BorshDeserialize};
395
396// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
397#[derive(BorshDeserialize)]
398#[borsh(crate = "borsh")]
399struct B {
400    x: u64,
401    y: i32,
402    c: String,
403}
404```
405
406### 2. `#[borsh(init=...)]` (item level attribute)
407
408###### syntax
409
410Attribute's value is syn's [Path]-s, passed to borsh top level meta attribute as value of `init` argument.
411
412###### usage
413
414`#[borsh(init=...)]` allows to automatically run an initialization function right after deserialization.
415This adds a lot of convenience for objects that are architectured to be used as strictly immutable.
416
417```ignore
418#[derive(BorshDeserialize)]
419#[borsh(init=init)]
420struct Message {
421    message: String,
422    timestamp: u64,
423    public_key: CryptoKey,
424    signature: CryptoSignature,
425    hash: CryptoHash,
426}
427
428impl Message {
429    pub fn init(&mut self) {
430        self.hash = CryptoHash::new().write_string(self.message).write_u64(self.timestamp);
431        self.signature.verify(self.hash, self.public_key);
432    }
433}
434```
435
436### 3. `borsh(use_discriminant=<bool>)` (item level attribute)
437
438This attribute is only applicable to enums.
439`use_discriminant` allows to override the default behavior of serialization of enums with explicit discriminant.
440`use_discriminant` is `false` behaves like version of borsh of 0.10.3.
441It's useful for backward compatibility and you can set this value to `false` to deserialise data serialised by older version of `borsh`.
442You must specify `use_discriminant` for all enums with explicit discriminants in your project.
443
444This is equivalent of borsh version 0.10.3 (explicit discriminant is ignored and this enum is equivalent to `A` without explicit discriminant):
445```ignore
446#[derive(BorshDeserialize)]
447#[borsh(use_discriminant = false)]
448enum A {
449    A
450    B = 10,
451}
452```
453
454To have explicit discriminant value serialized as is, you must specify `borsh(use_discriminant=true)` for enum.
455```ignore
456#[derive(BorshDeserialize)]
457#[borsh(use_discriminant = true)]
458enum B {
459    A
460    B = 10,
461}
462```
463
464
465###### borsh, expressions, evaluating to `isize`, as discriminant
466This case is not supported:
467```ignore
468const fn discrim() -> isize {
469    0x14
470}
471
472#[derive(BorshDeserialize)]
473#[borsh(use_discriminant = true)]
474enum X {
475    A,
476    B = discrim(), // expressions, evaluating to `isize`, which are allowed outside of `borsh` context
477    C,
478    D,
479    E = 10,
480    F,
481}
482```
483
484
485###### borsh explicit discriminant does not support literal values outside of u8 range.
486This is not supported:
487```ignore
488#[derive(BorshDeserialize)]
489#[borsh(use_discriminant = true)]
490enum X {
491    A,
492    B = 0x100, // literal values outside of `u8` range
493    C,
494    D,
495    E = 10,
496    F,
497}
498```
499
500
501### 4. `#[borsh(skip)]` (field level attribute)
502
503`#[borsh(skip)]` makes derive skip deserializing annotated field.
504
505`#[borsh(skip)]` makes derive skip adding any type parameters, present in the field, to parameters bound by `borsh::de::BorshDeserialize`.
506
507It adds `core::default::Default` bound to any
508parameters encountered in annotated field.
509
510
511```ignore
512#[derive(BorshDeserialize)]
513struct A {
514    x: u64,
515    #[borsh(skip)]
516    y: f32,
517}
518```
519
520
521### 5. `#[borsh(bound(deserialize = ...))]` (field level attribute)
522
523###### syntax
524
525Attribute takes literal string value, which is a comma-separated list of syn's [WherePredicate](syn::WherePredicate)-s, which may be empty.
526
527
528###### usage
529
530Attribute adds possibility to override bounds for `BorshDeserialize` in order to enable:
531
5321. removal of bounds on type parameters from struct/enum definition itself and moving them to the trait's implementation block.
5332. fixing complex cases, when derive hasn't figured out the right bounds on type parameters automatically.
534
535```ignore
536/// additional bounds `T: Ord + Hash + Eq` (required by `HashMap`) are injected into
537/// derived trait implementation via attribute to avoid adding the bounds on the struct itself
538#[derive(BorshDeserialize)]
539struct A<T, U> {
540    a: String,
541    #[borsh(bound(
542        deserialize =
543        "T: Ord + Hash + Eq + borsh::de::BorshDeserialize,
544         U: borsh::de::BorshDeserialize"
545    ))]
546    b: HashMap<T, U>,
547}
548```
549
550
551```ignore
552// derive here figures the bound erroneously as `T: borsh::de::BorshDeserialize,`
553#[derive(BorshDeserialize)]
554struct A<T, V>
555where
556    T: TraitName,
557{
558    #[borsh(bound(deserialize = "<T as TraitName>::Associated: borsh::de::BorshDeserialize"))]
559    field: <T as TraitName>::Associated,
560    another: V,
561}
562```
563
564###### interaction with `#[borsh(skip)]`
565
566`#[borsh(bound(deserialize = ...))]` replaces bounds, which are derived automatically,
567irrelevant of whether `#[borsh(skip)]` attribute is present.
568
569```ignore
570/// implicit derived `core::default::Default` bounds on `K` and `V` type parameters are removed by
571/// empty bound specified, as `HashMap` has its own `Default` implementation
572#[derive(BorshDeserialize)]
573struct A<K, V, U>(
574    #[borsh(skip, bound(deserialize = ""))]
575    HashMap<K, V>,
576    U,
577);
578```
579
580### 6. `#[borsh(deserialize_with = ...)]` (field level attribute)
581
582###### syntax
583
584Attribute takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
585
586###### usage
587
588Attribute adds possibility to specify full path of function, optionally qualified with generics,
589with which to deserialize the annotated field.
590
591It may be used when `BorshDeserialize` cannot be implemented for field's type, if it's from foreign crate.
592
593It may be used to override the implementation of deserialization for some other reason.
594
595```ignore
596use indexmap::IndexMap;
597
598mod index_map_impl {
599    use super::IndexMap;
600    use core::hash::Hash;
601
602    pub fn deserialize_index_map<
603        R: borsh::io::Read,
604        K: borsh::de::BorshDeserialize + Hash + Eq,
605        V: borsh::de::BorshDeserialize,
606    >(
607        reader: &mut R,
608    ) -> ::core::result::Result<IndexMap<K, V>, borsh::io::Error> {
609        let vec: Vec<(K, V)> = borsh::BorshDeserialize::deserialize_reader(reader)?;
610        let result: IndexMap<K, V> = vec.into_iter().collect();
611        Ok(result)
612    }
613}
614
615#[derive(BorshDeserialize)]
616struct B<K: Hash + Eq, V> {
617    #[borsh(
618        deserialize_with = "index_map_impl::deserialize_index_map",
619    )]
620    x: IndexMap<K, V>,
621    y: String,
622}
623```
624
625###### interaction with `#[borsh(skip)]`
626
627`#[borsh(deserialize_with = ...)]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
628
629*/
630#[proc_macro_derive(BorshDeserialize, attributes(borsh))]
631pub fn borsh_deserialize(input: TokenStream) -> TokenStream {
632    let cratename = match check_attrs_get_cratename(&input) {
633        Ok(cratename) => cratename,
634        Err(err) => {
635            return err.to_compile_error().into();
636        }
637    };
638
639    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
640        deserialize::structs::process(&input, cratename)
641    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
642        deserialize::enums::process(&input, cratename)
643    } else if let Ok(input) = syn::parse::<ItemUnion>(input) {
644        deserialize::unions::process(&input, cratename)
645    } else {
646        // Derive macros can only be defined on structs, enums, and unions.
647        unreachable!()
648    };
649    TokenStream::from(match res {
650        Ok(res) => res,
651        Err(err) => err.to_compile_error(),
652    })
653}
654
655/**
656# derive proc-macro for `borsh::BorshSchema` trait
657
658## Bounds
659
660Generally, `BorshSchema` adds `borsh::BorshSchema` bound to any type parameter
661found in item's fields.
662
663```ignore
664/// impl<U, V> borsh::BorshSchema for A<U, V>
665/// where
666///     U: borsh::BorshSchema,
667///     V: borsh::BorshSchema,
668#[derive(BorshSchema)]
669struct A<U, V> {
670    x: U,
671    y: V,
672}
673```
674
675```ignore
676/// impl<U, V> borsh::BorshSchema for A<U, V>
677/// where
678///     U: borsh::BorshSchema,
679#[derive(BorshSchema)]
680struct A<U, V> {
681    x: U,
682    #[borsh(skip)]
683    y: V,
684}
685```
686
687## Attributes
688
689### 1. `#[borsh(crate = "path::to::borsh")]` (item level attribute)
690
691###### syntax
692
693Attribute takes literal string value, which is the syn's [Path] to `borsh` crate used.
694
695###### usage
696
697Attribute is optional.
698
6991. If the attribute is not provided, [crate_name](proc_macro_crate::crate_name) is used to find a version of `borsh`
700in `[dependencies]` of the relevant `Cargo.toml`. If there is no match, a compilation error, similar to the following, is raised:
701
702```bash
703 1  error: proc-macro derive panicked
704   --> path/to/file.rs:27:10
705    |
706 27 | #[derive(BorshSchema, BorshSerialize)]
707    |          ^^^^^^^^^^^
708    |
709    = help: message: called `Result::unwrap()` on an `Err` value: CrateNotFound { crate_name: "borsh", path: "/path/to/Cargo.toml" }
710```
711
7122. If the attribute is provided, the check for `borsh` in `[dependencies]` of the relevant `Cargo.toml` is skipped.
713
714Examples of usage:
715
716```ignore
717use reexporter::borsh::BorshSchema;
718
719// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
720#[derive(BorshSchema)]
721#[borsh(crate = "reexporter::borsh")]
722struct B {
723    x: u64,
724    y: i32,
725    c: String,
726}
727```
728
729```ignore
730use reexporter::borsh::{self, BorshSchema};
731
732// specifying the attribute removes need for a direct import of `borsh` into `[dependencies]`
733#[derive(BorshSchema)]
734#[borsh(crate = "borsh")]
735struct B {
736    x: u64,
737    y: i32,
738    c: String,
739}
740```
741
742### 2. `borsh(use_discriminant=<bool>)` (item level attribute)
743This attribute is only applicable to enums.
744`use_discriminant` allows to override the default behavior of serialization of enums with explicit discriminant.
745`use_discriminant` is `false` behaves like version of borsh of 0.10.3.
746You must specify `use_discriminant` for all enums with explicit discriminants in your project.
747
748This is equivalent of borsh version 0.10.3 (explicit discriminant is ignored and this enum is equivalent to `A` without explicit discriminant):
749```ignore
750#[derive(BorshSchema)]
751#[borsh(use_discriminant = false)]
752enum A {
753    A
754    B = 10,
755}
756```
757
758To have explicit discriminant value serialized as is, you must specify `borsh(use_discriminant=true)` for enum.
759```ignore
760#[derive(BorshSchema)]
761#[borsh(use_discriminant = true)]
762enum B {
763    A
764    B = 10,
765}
766```
767
768###### borsh, expressions, evaluating to `isize`, as discriminant
769This case is not supported:
770```ignore
771const fn discrim() -> isize {
772    0x14
773}
774
775#[derive(BorshSchema)]
776#[borsh(use_discriminant = true)]
777enum X {
778    A,
779    B = discrim(), // expressions, evaluating to `isize`, which are allowed outside of `borsh` context
780    C,
781    D,
782    E = 10,
783    F,
784}
785```
786
787###### borsh explicit discriminant does not support literal values outside of u8 range
788This is not supported:
789```ignore
790#[derive(BorshSchema)]
791#[borsh(use_discriminant = true)]
792enum X {
793    A,
794    B = 0x100, // literal values outside of `u8` range
795    C,
796    D,
797    E = 10,
798    F,
799}
800```
801
802### 3. `#[borsh(skip)]` (field level attribute)
803
804`#[borsh(skip)]` makes derive skip including schema from annotated field into schema's implementation.
805
806`#[borsh(skip)]` makes derive skip adding any type parameters, present in the field, to parameters bound by `borsh::BorshSchema`.
807
808```ignore
809#[derive(BorshSchema)]
810struct A {
811    x: u64,
812    #[borsh(skip)]
813    y: f32,
814}
815```
816
817### 4. `#[borsh(schema(params = ...))]` (field level attribute)
818
819###### syntax
820
821Attribute takes literal string value, which is a comma-separated list of `ParameterOverride`-s, which may be empty.
822
823###### usage
824It may be used in order to:
825
8261. fix complex cases, when derive hasn't figured out the right bounds on type parameters and
827declaration parameters automatically.
8282. remove parameters, which do not take part in serialization/deserialization, from bounded ones and from declaration parameters.
829
830`ParameterOverride` describes an entry like `order_param => override_type`,
831
832e.g. `K => <K as TraitName>::Associated`.
833
834Such an entry instructs `BorshSchema` derive to:
835
8361. add `override_type` to types, bounded by `borsh::BorshSchema` in implementation block.
8372. add `<override_type>::declaration()` to parameters vector in `fn declaration()` method of `BorshSchema` trait that is being derived.
8383. 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.
8394. entries, specified for a field, together replace whatever would've been derived automatically for 1. and 2. .
840
841
842```ignore
843// derive here figures the bound erroneously as `T: borsh::BorshSchema` .
844// attribute replaces it with <T as TraitName>::Associated: borsh::BorshSchema`
845#[derive(BorshSchema)]
846struct A<V, T>
847where
848    T: TraitName,
849{
850    #[borsh(schema(params = "T => <T as TraitName>::Associated"))]
851    field: <T as TraitName>::Associated,
852    another: V,
853}
854```
855
856```ignore
857// K in PrimaryMap isn't stored during serialization / read during deserialization.
858// thus, it's not a parameter, relevant for `BorshSchema`
859// ...
860// impl<K: EntityRef, V> borsh::BorshSchema for A<K, V>
861// where
862//     V: borsh::BorshSchema,
863#[derive(BorshSchema)]
864struct A<K: EntityRef, V> {
865    #[borsh(
866        schema(
867            params = "V => V"
868        )
869    )]
870    x: PrimaryMap<K, V>,
871    y: String,
872}
873
874#[derive(BorshSchema)]
875pub struct PrimaryMap<K, V>
876where
877    K: EntityRef,
878{
879    elems: Vec<V>,
880    unused: PhantomData<K>,
881}
882```
883
884###### interaction with `#[borsh(skip)]`
885
886`#[borsh(schema(params = ...))]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
887
888### 5. `#[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]` (field level attribute)
889
890###### syntax
891
892Each of `declaration` and `definitions` nested sub-attributes takes literal string value, which is a syn's [ExprPath](syn::ExprPath).
893
894Currently both `declaration` and `definitions` are required to be specified at the same time.
895
896###### usage
897
898Attribute adds possibility to specify full path of 2 functions, optionally qualified with generics,
899with which to generate borsh schema for annotated field.
900
901It may be used when `BorshSchema` cannot be implemented for field's type, if it's from foreign crate.
902
903It may be used to override the implementation of schema for some other reason.
904
905```ignore
906use indexmap::IndexMap;
907
908mod index_map_impl {
909    pub mod schema {
910        use std::collections::BTreeMap;
911
912        use borsh::{
913            schema::{Declaration, Definition},
914            BorshSchema,
915        };
916
917        pub fn declaration<K: borsh::BorshSchema, V: borsh::BorshSchema>() -> Declaration {
918            let params = vec![<K>::declaration(), <V>::declaration()];
919            format!(r#"{}<{}>"#, "IndexMap", params.join(", "))
920        }
921
922        pub fn add_definitions_recursively<K: borsh::BorshSchema, V: borsh::BorshSchema>(
923            definitions: &mut BTreeMap<Declaration, Definition>,
924        ) {
925            let definition = Definition::Sequence {
926                elements: <(K, V)>::declaration(),
927            };
928            let no_recursion_flag = definitions.get(&declaration::<K, V>()).is_none();
929            <() as BorshSchema>::add_definition(declaration::<K, V>(), definition, definitions);
930            if no_recursion_flag {
931                <(K, V)>::add_definitions_recursively(definitions);
932            }
933        }
934    }
935}
936
937#[derive(BorshSchema)]
938struct B<K, V> {
939    #[borsh(
940        schema(
941            with_funcs(
942                declaration = "index_map_impl::schema::declaration::<K, V>",
943                definitions = "index_map_impl::schema::add_definitions_recursively::<K, V>"
944            ),
945        )
946    )]
947    x: IndexMap<K, V>,
948    y: String,
949}
950```
951
952###### interaction with `#[borsh(skip)]`
953
954`#[borsh(schema(with_funcs(declaration = ..., definitions = ...)))]` is not allowed to be used simultaneously with `#[borsh(skip)]`.
955
956*/
957#[cfg(feature = "schema")]
958#[proc_macro_derive(BorshSchema, attributes(borsh))]
959pub fn borsh_schema(input: TokenStream) -> TokenStream {
960    let cratename = match check_attrs_get_cratename(&input) {
961        Ok(cratename) => cratename,
962        Err(err) => {
963            return err.to_compile_error().into();
964        }
965    };
966
967    let res = if let Ok(input) = syn::parse::<ItemStruct>(input.clone()) {
968        schema::structs::process(&input, cratename)
969    } else if let Ok(input) = syn::parse::<ItemEnum>(input.clone()) {
970        schema::enums::process(&input, cratename)
971    } else if syn::parse::<ItemUnion>(input).is_ok() {
972        Err(syn::Error::new(
973            Span::call_site(),
974            "Borsh schema does not support unions yet.",
975        ))
976    } else {
977        // Derive macros can only be defined on structs, enums, and unions.
978        unreachable!()
979    };
980    TokenStream::from(match res {
981        Ok(res) => res,
982        Err(err) => err.to_compile_error(),
983    })
984}