concordium_contracts_common_derive/lib.rs
1// #![no_std]
2extern crate proc_macro;
3extern crate syn;
4#[macro_use]
5extern crate quote;
6
7use proc_macro::TokenStream;
8use syn::parse_macro_input;
9
10mod attribute;
11mod derive;
12
13/// A helper to report meaningful compilation errors
14/// - If applied to an Ok value they simply return the underlying value.
15/// - If applied to `Err(e)` then `e` is turned into a compiler error.
16fn unwrap_or_report(v: syn::Result<TokenStream>) -> TokenStream {
17 match v {
18 Ok(ts) => ts,
19 Err(e) => e.to_compile_error().into(),
20 }
21}
22
23/// Derive the Deserial trait. See the documentation of
24/// [`derive(Serial)`](./derive.Serial.html) for details and limitations.
25///
26/// In addition to the attributes supported by
27/// [`derive(Serial)`](./derive.Serial.html), this derivation macro supports the
28/// `ensure_ordered` attribute. If applied to a field the of type `BTreeMap` or
29/// `BTreeSet` deserialization will additionally ensure that the keys are in
30/// strictly increasing order. By default deserialization only ensures
31/// uniqueness.
32///
33/// # Example
34/// ``` ignore
35/// #[derive(Deserial)]
36/// struct Foo {
37/// #[concordium(size_length = 1, ensure_ordered)]
38/// bar: BTreeSet<u8>,
39/// }
40/// ```
41#[proc_macro_derive(Deserial, attributes(concordium))]
42pub fn deserial_derive(input: TokenStream) -> TokenStream {
43 let ast = parse_macro_input!(input);
44 unwrap_or_report(derive::impl_deserial(&ast))
45}
46
47/// Derive the [`Serial`] trait for the type.
48///
49/// If the type is a struct all fields must implement the [`Serial`] trait. If
50/// the type is an enum then all fields of each of the variants must implement
51/// the [`Serial`] trait.
52///
53/// Fields of structs are serialized in the order they appear in the code.
54///
55/// ## Enums
56///
57/// Enums can have no more than 65536 variants. They are serialized by using a
58/// tag to indicate the variant, and by default they are enumerated in the order
59/// they are written in the source code. If the number of variants is less than
60/// or to equal 256 then a single byte is used to encode it. Otherwise two bytes
61/// are used for the tag, encoded in little endian.
62///
63/// ### Specifying the tag byte size using `#[concordium(repr(..))]`
64///
65/// Optionally, an enum type can be annotated with a `#[concordium(repr(x))]`
66/// attribute, where `x` is either `u8` or `u16`. This specifies the number of
67/// bytes to use when serializing the tag in little endian.
68///
69/// A type annotated with `#[concordium(repr(u8))]` can only have up to 256
70/// variants and `#[concordium(repr(u16))]` can have up to 65536 variants.
71///
72/// #### Example
73///
74/// Example of an enum which uses two bytes for encoding the tag. Here the
75/// variant `A` is tagged using `0u16` and `B` is tagged using `1u16`.
76///
77/// ```ignore
78/// #[derive(Serial)]
79/// #[concordium(repr(u16))]
80/// enum MyEnum {
81/// A,
82/// B
83/// }
84/// ```
85///
86/// ### Specifying the tag value for a variant using `#[concordium(tag = ..)]`
87///
88/// For each enum variant the tag can be explicitly set using `#[concordium(tag
89/// = n)]` where `n` is the integer literal to use for the tag.
90/// When using the 'tag' attribute it is required to have the
91/// `#[concordium(repr(..))]` set as well. The tag must have a value
92/// representable by the type set by `#[concordium(repr(..))]`.
93///
94/// <i>Note that `SchemaType` currently only supports using a single byte
95/// `#([concordium(repr(u8))]`) when using `#[concordium(tag = ..)]`.</i>
96///
97/// ### Nesting enums with a flat serialization using `#[concordium(forward = ...)]`
98///
99/// Often it is desired to have a single type representing a parameter or the
100/// events. A general pattern for enums is to nest them, however deriving
101/// serialization for a nested enum introduces an additional tag for the variant
102/// of the top-level enum. The solution is to use the attribute
103/// `#[concordium(forward = ...)]` on the variant with a nested enum.
104/// This attribute takes a tag or a list of tags which changes the serialization
105/// to skip the variant tag and deserialization to match the variant with these
106/// tags and forward the deserialization to the nested enum.
107///
108/// ```ignore
109/// #[derive(Serial, Deserial)]
110/// #[concordium(repr(u8))]
111/// enum Event {
112/// SomeEvent(MyEvent),
113/// #[concordium(forward = [42, 43, 44, 45])]
114/// OtherEvent(NestedEvent),
115/// }
116/// ```
117///
118/// For convenience the attribute also supports the values `cis2_events`,
119/// `cis3_events` and `cis4_events` which are unfolded to the list of tags used
120/// for events in CIS-2, CIS-3 and CIS-4 respectively.
121///
122/// ```ignore
123/// #[derive(Serial, Deserial)]
124/// #[concordium(repr(u8))]
125/// enum Event {
126/// SomeEvent(MyEvent),
127/// #[concordium(forward = cis2_events)]
128/// Cis2(Cis2Event),
129/// }
130/// ```
131///
132/// Setting `#[concordium(forward = n)]` on a variant will produce an error if:
133/// - The type does _not_ have a `#[concordium(repr(u*))]` attribute.
134/// - If any of the forwarded tags `n` cannot be represented by the
135/// `#[concordium(repr(u*))]`.
136/// - Any of the forwarded tags `n` overlap with a tag of another variant.
137/// - `n` contains a predefined set and the value of `#[concordium(repr(u*))]`
138/// is incompatible.
139/// - If the variant does _not_ have exactly one field.
140///
141/// Note that the derive macro does _not_ check forwarded tags matches the tags
142/// of the inner type.
143///
144/// #### Example
145///
146/// Example of enum specifying the tag of the variant `A` to the value `42u8`.
147/// The variant `B` is tagged using `1u8`.
148///
149/// ```ignore
150/// #[derive(Serial)]
151/// #[concordium(repr(u8))]
152/// enum MyEnum {
153/// #[concordium(tag = 42)]
154/// A,
155/// B
156/// }
157/// ```
158///
159/// ## Generic type bounds
160///
161/// By default a trait bound is added on each generic type for implementing
162/// [`Serial`]. However, if this is not desirable, the default bound can be
163/// replaced by using the `bound` attribute on the type and providing the
164/// replacement.
165///
166/// Bounds present in the type declaration will still be present in
167/// the implementation, even when a bound is provided:
168///
169/// ### Example
170///
171/// ```ignore
172/// #[derive(Serial)]
173/// #[concordium(bound(serial = "A: SomeOtherTrait"))]
174/// struct Foo<A: SomeTrait> {
175/// bar: A,
176/// }
177///
178/// // Derived implementation:
179/// impl <A: SomeTrait> Serial for Foo<A> where A: SomeOtherTrait { .. }
180/// ```
181///
182/// ## Collections
183///
184/// Collections (Vec, BTreeMap, BTreeSet) and strings (String, str) are by
185/// default serialized by prepending the number of elements as 4 bytes
186/// little-endian. If this is too much or too little, fields of the above types
187/// can be annotated with `size_length`.
188///
189/// The value of this field is the number of bytes that will be used for
190/// encoding the number of elements. Supported values are `1`, `2`, `4`, `8`.
191///
192/// For BTreeMap and BTreeSet the serialize method will serialize values in
193/// increasing order of keys.
194///
195/// ### Example
196/// ```ignore
197/// #[derive(Serial)]
198/// struct Foo {
199/// #[concordium(size_length = 1)]
200/// bar: BTreeSet<u8>,
201/// }
202/// ```
203#[proc_macro_derive(Serial, attributes(concordium))]
204pub fn serial_derive(input: TokenStream) -> TokenStream {
205 let ast = parse_macro_input!(input);
206 unwrap_or_report(derive::impl_serial(&ast))
207}
208
209/// A helper macro to derive both the Serial and Deserial traits.
210/// `[derive(Serialize)]` is equivalent to `[derive(Serial, Deserial)]`, see
211/// documentation of the latter two for details and options:
212/// [`derive(Serial)`](./derive.Serial.html),
213/// [`derive(Deserial)`](./derive.Deserial.html).
214#[proc_macro_derive(Serialize, attributes(concordium))]
215pub fn serialize_derive(input: TokenStream) -> TokenStream {
216 unwrap_or_report(serialize_derive_worker(input))
217}
218
219fn serialize_derive_worker(input: TokenStream) -> syn::Result<TokenStream> {
220 let ast = syn::parse(input)?;
221 let mut tokens = derive::impl_deserial(&ast)?;
222 tokens.extend(derive::impl_serial(&ast)?);
223 Ok(tokens)
224}
225
226/// Derive the DeserialWithState trait. See the documentation of
227/// [`derive(Deserial)`](./derive.Deserial.html) for details and limitations.
228///
229/// This trait should be derived for `struct`s or `enum`s that have fields with
230/// [`StateBox`](../concordium_std/struct.StateBox.html),
231/// [`StateSet`](../concordium_std/struct.StateSet.html), or
232/// [`StateMap`](../concordium_std/struct.StateMap.html).
233///
234/// Please note that it is necessary to specify the generic parameter name for
235/// the [`HasStateApi`](../concordium_std/trait.HasStateApi.html) generic
236/// parameter. To do so, use the `#[concordium(state_parameter =
237/// "NameOfGenericParameter")]` attribute on the type you are deriving
238/// `DeserialWithState` for.
239///
240/// # Example
241/// ``` ignore
242/// #[derive(DeserialWithState)]
243/// #[concordium(state_parameter = "S")]
244/// struct Foo<S = StateApi, T> {
245/// a: StateMap<u8, u8, S>,
246/// #[concordium(size_length = 1)]
247/// b: String,
248/// c: Vec<T>,
249/// }
250/// ```
251#[proc_macro_derive(DeserialWithState, attributes(concordium))]
252pub fn deserial_with_state_derive(input: TokenStream) -> TokenStream {
253 let ast = parse_macro_input!(input);
254 unwrap_or_report(derive::impl_deserial_with_state(&ast))
255}
256
257/// Derive the [`SchemaType`] trait for a type with a `schema::Type` matching
258/// the implementation when deriving [`Serial`].
259///
260/// Can be used for enums and structs.
261/// If the type is a struct all fields must implement the [`SchemaType`] trait.
262/// If the type is an enum then all fields of each of the variants must
263/// implement the [`SchemaType`] trait.
264///
265/// ## Specifying the tag value for an enum variant
266///
267/// When deriving `Serial`, `Deserial` and `DeserialWithState` the
268/// discriminating tag can be set explicitly using `#[concordium(tag = n)]`
269/// where `n` is a unsigned integer literal. This require annotating the enum
270/// with `#[concordium(repr(..))]`, see [`Serial`] for more on this attribute.
271/// The current version of the contract schema cannot express tags encoded with
272/// more than one byte, meaning only the annotation of `#[concordium(repr(u8))]`
273/// can be used, when deriving the `SchemaType`.
274///
275/// ### Nesting enums with a flat serialization using `#[concordium(forward = ...)]`
276///
277/// Often it is desired to have a single type representing a parameter or the
278/// events. A general pattern for enums is to nest them, however deriving
279/// the schema type for enums with nested enums exposes this. The solution is to
280/// use the attribute `#[concordium(forward = ...)]` on the variant with a
281/// nested enum. This attribute takes a tag or a list of tags and changes the
282/// (de)serialization to hide the nesting. The `SchemaType` produced is a
283/// flatten enum hiding the nested enum.
284/// Note that the schema can only be built when the nested type is an enum
285/// implementing `SchemaType`.
286/// Incorrect use will **not** be caught when compiling the contract itself but
287/// it will be caught when attempting to build the schema using
288/// `cargo-concordium`.
289///
290/// ```ignore
291/// #[derive(SchemaType)]
292/// #[concordium(repr(u8))]
293/// enum Event {
294/// SomeEvent(MyEvent),
295/// #[concordium(forward = [42, 43, 44, 45])]
296/// OtherEvent(NestedEvent),
297/// }
298/// ```
299///
300/// For convenience the attribute also supports the values `cis2_events`,
301/// `cis3_events` and `cis4_events` which are unfolded to the list of tags used
302/// for events in CIS-2, CIS-3 and CIS-4 respectively.
303///
304/// ```ignore
305/// #[derive(SchemaType)]
306/// #[concordium(repr(u8))]
307/// enum Event {
308/// SomeEvent(MyEvent),
309/// #[concordium(forward = cis2_events)]
310/// Cis2(Cis2Event),
311/// }
312/// ```
313///
314/// Setting `#[concordium(forward = n)]` on a variant will produce an error if:
315/// - The type does _not_ have a `#[concordium(repr(u*))]` attribute.
316/// - If any of the forwarded tags `n` cannot be represented by the
317/// `#[concordium(repr(u*))]`.
318/// - Any of the forwarded tags `n` overlap with a tag of another variant.
319/// - `n` contains a predefined set and the value of `#[concordium(repr(u*))]`
320/// is incompatible.
321/// - If the variant does _not_ have exactly one field.
322///
323/// Note that the derive macro does _not_ check forwarded tags matches the tags
324/// of the inner type.
325///
326/// ## Generic type bounds
327///
328/// By default a trait bound is added on each generic type for implementing
329/// [`SchemaType`]. However, if this is not desirable, the default bound can be
330/// replaced by using the `bound` attribute on the type and providing the
331/// replacement.
332///
333/// Bounds present in the type declaration will still be present in
334/// the implementation, even when a bound is provided:
335///
336/// ### Example
337///
338/// ```ignore
339/// #[derive(SchemaType)]
340/// #[concordium(bound(schema_type = "A: SomeOtherTrait"))]
341/// struct Foo<A: SomeTrait> {
342/// bar: A,
343/// }
344///
345/// // Derived implementation:
346/// impl <A: SomeTrait> SchemaType for Foo<A> where A: SomeOtherTrait { .. }
347/// ```
348///
349/// ## Collections
350///
351/// Collections (Vec, BTreeMap, BTreeSet) and strings (String, str) can be
352/// annotated with `size_length` which is the number of bytes used for encoding
353/// the number of elements, see derive macro ['Serial'] for more on this.
354///
355/// The value of this field is the number of bytes that will be used for
356/// encoding the number of elements. Supported values are `1`, `2`, `4`, `8`.
357///
358/// ### Example
359/// ```ignore
360/// #[derive(SchemaType)]
361/// struct Foo {
362/// #[concordium(size_length = 1)]
363/// bar: BTreeSet<u8>,
364/// }
365/// ```
366///
367/// ## Transparent
368///
369/// Deriving [`SchemaType`] for structs using the newtype design pattern exposes
370/// the wrapping struct which is often not desirable. The attribute
371/// `#[concordium(transparent)]` can be added above the struct which changes the
372/// implementation of [`SchemaType`] to schema type of the field.
373///
374/// The `#[concordium(transparent)]` attribute can only be used for structs with
375/// a single field, and the type of this field must implement `SchemaType`.
376///
377/// ### Example
378///
379/// ```ignore
380/// #[derive(SchemaType)]
381/// #[concordium(transparent)]
382/// struct Foo {
383/// bar: u32,
384/// }
385/// ```
386///
387/// ### Example
388///
389/// The 'transparent' attribute will still take account for field attributes
390/// such as `size_length` for collections.
391/// ```ignore
392/// #[derive(SchemaType)]
393/// #[concordium(transparent)]
394/// struct Foo {
395/// #[concordium(size_length = 1)]
396/// bar: Vec<u32>,
397/// }
398/// ```
399#[proc_macro_derive(SchemaType, attributes(concordium))]
400pub fn schema_type_derive(input: TokenStream) -> TokenStream {
401 unwrap_or_report(derive::schema_type_derive_worker(input))
402}
403
404/// Derive the conversion of enums that represent error types into the Reject
405/// struct which can be used as the error type of init and receive functions.
406/// Creating custom enums for error types can provide meaningful error messages
407/// to the user of the smart contract.
408///
409/// When a contract function rejects, the enum is serialized and returned along
410/// with the error code. The serialization means that the enum *must* implement
411/// [`Serial`](../concordium_contracts_common/trait.Serial.html) if [`Reject`]
412/// is to be derived.
413///
414/// The conversion will map the first variant to error code -1, second to -2,
415/// etc.
416///
417/// ### Example
418/// ```ignore
419/// #[derive(Reject, Serial)]
420/// enum MyError {
421/// IllegalState, // receives error code -1
422/// WrongSender, // receives error code -2
423/// TimeExpired(time: Timestamp), // receives error code -3
424/// ...
425/// }
426/// ```
427/// ```ignore
428/// #[receive(contract = "my_contract", name = "some_receive")]
429/// fn receive(ctx: &ReceiveContext, host: &Host<MyState>)
430/// -> Result<A, MyError> {...}
431/// ```
432#[proc_macro_derive(Reject, attributes(from))]
433pub fn reject_derive(input: TokenStream) -> TokenStream {
434 unwrap_or_report(derive::reject_derive_worker(input))
435}
436
437/// Derive the Deletable trait.
438/// See the documentation of
439/// [`derive(Deletable)`](./derive.Deletable.html) for details and limitations.
440///
441/// The trait should be derived for types which have not implemented the
442/// `Serialize` trait. That is, Deletable should be derived for types with a
443/// non-trivial state.
444/// Non-trivial state here means when you have a type `MyState` which has one or
445/// more fields comprised of
446/// [`StateBox`](../concordium_std/struct.StateBox.html),
447/// [`StateSet`](../concordium_std/struct.StateSet.html), or
448/// [`StateMap`](../concordium_std/struct.StateMap.html).
449///
450/// Please note that it is
451/// necessary to specify the generic parameter name for the
452/// [`HasStateApi`](../concordium_std/trait.HasStateApi.html) generic parameter.
453/// To do so, use the `#[concordium(state_parameter =
454/// "NameOfGenericParameter")]` attribute on the type you are deriving
455/// `Deletable` for.
456///
457/// # Example
458/// ``` ignore
459/// #[derive(Serial, DeserialWithState, Deletable)]
460/// #[concordium(state_parameter = "S")]
461/// struct MyState<S = StateApi> {
462/// my_state_map: StateMap<SomeType, SomeOtherType, S>,
463/// }
464/// ```
465#[proc_macro_derive(Deletable, attributes(concordium))]
466pub fn deletable_derive(input: TokenStream) -> TokenStream {
467 let ast = parse_macro_input!(input);
468 unwrap_or_report(derive::impl_deletable(&ast))
469}
470
471/// Derive the appropriate export for an annotated init function.
472///
473/// This macro requires the following items to be present
474/// - `contract="<name>"` where *\<name\>* is the name of the smart contract and
475/// the generated function is exported as this name prefixed with *init_*. The
476/// name should be unique in the module, as a contract can only have one
477/// init-function.
478///
479/// The annotated function must be of a specific type, which depends on the
480/// enabled attributes. *Without* any of the optional attributes the function
481/// must have a signature of
482///
483/// ```ignore
484/// #[init(contract = "my_contract")]
485/// fn some_init(ctx: &InitContext, state_builder: &mut StateBuilder) -> InitResult<MyState> {...}
486/// ```
487///
488/// Where `InitContext`, `InitResult`, and `StateBuilder` are exposed from
489/// `concordium-std` and `MyState` is a user-defined type.
490///
491/// # Optional attributes
492///
493/// ## `payable`: Make function accept an amount of CCD
494/// Without setting the `payable` attribute, the generated function will reject
495/// any non-zero amount of CCD supplied with the transaction. This means we are
496/// required to explicitly mark our functions as `payable`, if they are to
497/// accept CCD.
498///
499/// Setting the `payable` attribute changes the required signature to include an
500/// extra argument of type `Amount`, allowing the function to access the amount
501/// of CCD supplied with the transaction.
502///
503/// ### Example
504/// ```ignore
505/// #[init(contract = "my_contract", payable)]
506/// fn some_init(ctx: &InitContext, state_builder: StateBuilder, amount: Amount) -> InitResult<MyState> {...}
507/// ```
508///
509/// ## `enable_logger`: Function can access event logging
510/// Setting the `enable_logger` attribute changes the required signature to
511/// include an extra argument `&mut Logger`, allowing the function to
512/// log events.
513///
514///
515/// ### Example
516/// ```ignore
517/// #[init(contract = "my_contract", enable_logger)]
518/// fn some_init(ctx: &InitContext, state_builder: StateBuilder, logger: &mut Logger) -> InitResult<MyState> {...}
519/// ```
520///
521/// ## `low_level`: Manually deal with the low-level state.
522/// Setting the `low_level` attribute disables the generated code for
523/// serializing the contract state.
524///
525/// If `low_level` is set, the `&mut StateBuilder` in the signature is
526/// replaced by `&mut StateApi` found in `concordium-std`, which gives
527/// access to manipulating the low-level contract state directly. This means
528/// there is no need to return the contract state and the return type becomes
529/// `InitResult<()>`.
530///
531/// ### Example
532/// ```ignore
533/// #[init(contract = "my_contract", low_level)]
534/// fn some_init(ctx: &InitContext, state: &mut StateApi) -> InitResult<()> {...}
535/// ```
536///
537/// ## `parameter="<Param>"`: Generate schema for parameter
538/// To make schema generation include the parameter for this function, add
539/// the attribute `parameter` and set it equal to a string literal containing
540/// the name of the type used for the parameter. The parameter type must
541/// implement the SchemaType trait, which for most cases can be derived
542/// automatically.
543///
544/// ### Example
545/// ```ignore
546/// #[derive(SchemaType)]
547/// struct MyParam { ... }
548///
549/// #[init(contract = "my_contract", parameter = "MyParam")]
550/// ```
551///
552/// ## `error="<Error>"`: Generate schema for error
553/// To make schema generation include the error for this function, add
554/// the attribute `error` and set it equal to a string literal containing
555/// the name of the type used for the error. The error type must
556/// implement the SchemaType trait, which for most cases can be derived
557/// automatically.
558///
559/// ### Example
560/// ```ignore
561/// #[derive(SchemaType)]
562/// enum MyError { ... }
563///
564/// #[init(contract = "my_contract", error = "MyError")]
565/// fn some_init(ctx: &impl InitContext, state: &mut StateApi) -> Result<(), MyError> {...}
566/// ```
567///
568/// ## `crypto_primitives`: Function can access cryptographic primitives
569/// Setting the `crypto_primitives` attribute changes the required signature to
570/// include an extra argument `&CryptoPrimitives`, which provides
571/// cryptographic primitives such as verifying signatures and hashing data.
572///
573/// ### Example
574/// ```ignore
575/// #[init(contract = "my_contract", crypto_primitives)]
576/// fn some_init(
577/// ctx: &InitContext,
578/// state_build: StateBuilder,
579/// crypto_primitives: &CryptoPrimitives,
580/// ) -> InitResult<MyState> {...}
581/// ```
582#[proc_macro_attribute]
583pub fn init(attr: TokenStream, item: TokenStream) -> TokenStream {
584 unwrap_or_report(attribute::init_worker(attr, item))
585}
586
587/// Derive the appropriate export for an annotated receive function.
588///
589/// This macro requires the following items to be present
590/// - `contract = "<contract-name>"` where *\<contract-name\>* is the name of
591/// the smart contract.
592/// - `name = "<receive-name>"` where *\<receive-name\>* is the name of the
593/// receive function, **or** the `fallback` option. The generated function is
594/// exported as `<contract-name>.<receive-name>`, or if `fallback` is given,
595/// as `<contract-name>.`.Contract name and receive name is required to be
596/// unique in the module. In particular, a contract may have only a single
597/// fallback method.
598///
599/// The annotated function must be of a specific type, which depends on the
600/// enabled attributes. *Without* any of the optional attributes the function
601/// must have a signature of
602///
603/// ```ignore
604/// #[receive(contract = "my_contract", name = "some_receive")]
605/// fn contract_receive(
606/// ctx: &ReceiveContext,
607/// host: &Host<MyState>
608/// ) -> ReceiveResult<MyReturnValue> {...}
609/// ```
610///
611/// Where the `ReceiveContext`, `Host`, and `ReceiveResult`
612/// are from `concordium-std` and `MyState` and `MyReturnValue` are user-defined
613/// types.
614///
615/// # Optional attributes
616///
617/// ## `payable`: Make function accept an amount of CCD
618/// Without setting the `payable` attribute, the function will reject any
619/// non-zero amount of CCD, supplied with the transaction. This means we are
620/// required to explicitly mark our functions as `payable`, if they are to
621/// accept CCD.
622///
623/// Setting the `payable` attribute changes the required signature to include an
624/// extra argument of type `Amount`, allowing the function to access the amount
625/// of CCD supplied with the transaction.
626///
627/// ### Example
628/// ```ignore
629/// #[receive(contract = "my_contract", name = "some_receive", payable)]
630/// fn contract_receive(
631/// ctx: &ReceiveContext,
632/// host: &Host<MyState>,
633/// amount: Amount
634/// ) -> ReceiveResult<MyReturnValue> {...}
635/// ```
636///
637/// ## `mutable`: Function can mutate the state
638/// Setting the `mutable` attribute changes the required signature so the host
639/// becomes a mutable reference.
640///
641/// **When a receive method is mutable, the state, e.g. `MyState`, is serialized
642/// and stored after each invocation. This means that even if the state does
643/// not change semantically, it will be considered as modified by callers.**
644/// Thus the `mutable` option should only be used when absolutely necessary.
645///
646/// ### Example
647/// ```ignore
648/// #[receive(contract = "my_contract", name = "some_receive", mutable)]
649/// fn contract_receive(
650/// ctx: &ReceiveContext,
651/// host: &mut Host<MyState>,
652/// ) -> ReceiveResult<MyReturnValue> {...}
653/// ```
654///
655/// ## `enable_logger`: Function can access event logging
656/// Setting the `enable_logger` attribute changes the required signature to
657/// include an extra argument `&mut Logger`, allowing the function to
658/// log events.
659///
660/// ### Example
661/// ```ignore
662/// #[receive(contract = "my_contract", name = "some_receive", enable_logger)]
663/// fn contract_receive(
664/// ctx: &ReceiveContext,
665/// host: &Host<MyState>,
666/// logger: &mut Logger,
667/// ) -> ReceiveResult<MyReturnValue> {...}
668/// ```
669///
670/// ## `low_level`: Manually deal with the low-level state including writing
671/// bytes Setting the `low_level` attribute disables the generated code for
672/// serializing the contract state. However, the return value is still
673/// serialized automatically.
674///
675/// If `low_level` is set, the `&Host<State>` in the signature is
676/// replaced by `&mut LowLevelHost` found in `concordium-std`, which gives
677/// access to manipulating the low-level contract state directly via the methods
678/// `state()` and `state_mut()`.
679///
680/// ### Example
681/// ```ignore
682/// #[receive(contract = "my_contract", name = "some_receive", low_level)]
683/// fn contract_receive(
684/// ctx: &ReceiveContext,
685/// state: &mut LowLevelHost,
686/// ) -> ReceiveResult<MyReturnValue> {...}
687/// ```
688///
689/// ## `parameter="<Param>"`: Generate schema for parameter
690/// To make schema generation include the parameter for this function, add
691/// the attribute `parameter` and set it equal to a string literal containing
692/// the type used for the parameter. The parameter type must
693/// implement the SchemaType trait, which for most cases can be derived
694/// automatically.
695///
696/// ### Example
697/// ```ignore
698/// #[derive(SchemaType)]
699/// struct MyParam { ... }
700///
701/// #[receive(contract = "my_contract", name = "some_receive", parameter = "MyParam")]
702/// fn contract_receive(
703/// ctx: &ReceiveContext,
704/// host: &Host<MyState>,
705/// ) -> ReceiveResult<A> {...}
706/// ```
707///
708/// ## `return_value="<ReturnValue>"`: Generate schema for the return value.
709/// To make schema generation include the return value for this function, add
710/// the attribute `return_value` and set it equal to a string literal containing
711/// the type used for the parameter. The parameter type must
712/// implement the SchemaType trait, which for most cases can be derived
713/// automatically.
714///
715/// ### Example
716///
717/// ```ignore
718/// #[derive(SchemaType)]
719/// struct MyReturnValue { ... }
720///
721/// #[receive(contract = "my_contract", name = "some_receive", return_value = "MyReturnValue")]
722/// fn contract_receive(
723/// ctx: &ReceiveContext,
724/// host: &Host<MyState>,
725/// ) -> ReceiveResult<MyReturnValue> {...}
726/// ```
727///
728/// ## `error="<Error>"`: Generate schema for error
729/// To make schema generation include the error for this function, add
730/// the attribute `error` and set it equal to a string literal containing
731/// the type used for the error. The error type must
732/// implement the SchemaType trait, which for most cases can be derived
733/// automatically.
734///
735/// ### Example
736/// ```ignore
737/// #[derive(SchemaType)]
738/// enum MyError { ... }
739///
740/// #[receive(contract = "my_contract", name = "some_receive", error = "MyError")]
741/// fn contract_receive(
742/// ctx: &ReceiveContext,
743/// host: &Host<MyState>,
744/// ) -> Result<A, MyError> {...}
745/// ```
746///
747/// ## `fallback`: Create a fallback entrypoint.
748/// A contract can have a *single* fallback entrypoint defined.
749/// If defined, invocations on missing entrypoint will be redirected to the
750/// fallback entrypoint. For fallback entrypoints, the `name` attribute is not
751/// allowed. This is because fallback entrypoints always have the empty string
752/// as their name.
753///
754/// To get the name of the entrypoint used for invocation, use
755/// `ctx.named_entrypoint()`. The method is available in all receive methods,
756/// but is only useful on fallback entrypoints.
757///
758/// ### Example
759/// ```ignore
760/// #[receive(contract = "my_contract", fallback)]
761/// fn contract_receive(
762/// ctx: &ReceiveContext,
763/// host: &Host<MyState>,
764/// ) -> ReceiveResult<MyReturnValue> {
765/// let named_entrypoint = ctx.named_entrypoint();
766/// // ...
767/// }
768/// ```
769/// ## `crypto_primitives`: Function can access cryptographic primitives
770/// Setting the `crypto_primitives` attribute changes the required signature to
771/// include an extra argument `&CryptoPrimitives`, which provides
772/// cryptographic primitives such as verifying signatures and hashing data.
773///
774/// ### Example
775/// ```ignore
776/// #[receive(contract = "my_contract", name = "some_receive", crypto_primitives)]
777/// fn some_receive(
778/// ctx: &ReceiveContext,
779/// host: &Host<MyState>,
780/// crypto_primitives: &CryptoPrimitives,
781/// ) -> ReceiveResult<MyReturnValue> {...}
782/// ```
783#[proc_macro_attribute]
784pub fn receive(attr: TokenStream, item: TokenStream) -> TokenStream {
785 unwrap_or_report(attribute::receive_worker(attr, item))
786}
787
788#[proc_macro_attribute]
789/// Derive the appropriate export for an annotated test function, when feature
790/// "wasm-test" is enabled, otherwise behaves like `#[test]`.
791pub fn concordium_test(attr: TokenStream, item: TokenStream) -> TokenStream {
792 unwrap_or_report(attribute::concordium_test_worker(attr, item))
793}
794
795/// Sets the cfg for testing targeting either Wasm and native.
796#[cfg(feature = "wasm-test")]
797#[proc_macro_attribute]
798pub fn concordium_cfg_test(_attr: TokenStream, item: TokenStream) -> TokenStream { item }
799
800/// Sets the cfg for testing targeting either Wasm and native.
801#[cfg(not(feature = "wasm-test"))]
802#[proc_macro_attribute]
803pub fn concordium_cfg_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
804 let item = proc_macro2::TokenStream::from(item);
805 let out = quote! {
806 #[cfg(test)]
807 #item
808 };
809 out.into()
810}
811
812/// If `wasm-test` feature of `concordium-std` is enabled ignore the item,
813/// this usually happens when executing tests with `cargo-concordium` utility.
814/// Otherwise this is equivalent to `#[cfg(not(test))]`. Use as a dual to
815/// `#[concordium_cfg_test]`.
816#[cfg(feature = "wasm-test")]
817#[proc_macro_attribute]
818pub fn concordium_cfg_not_test(_attr: TokenStream, _item: TokenStream) -> TokenStream {
819 TokenStream::new()
820}
821
822/// If `wasm-test` feature of `concordium-std` is enabled ignore the item,
823/// this usually happens when executing tests with `cargo-concordium` utility.
824/// Otherwise this is equivalent to `#[cfg(not(test))]`. Use as a dual to
825/// `#[concordium_cfg_test]`.
826#[cfg(not(feature = "wasm-test"))]
827#[proc_macro_attribute]
828pub fn concordium_cfg_not_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
829 let item = proc_macro2::TokenStream::from(item);
830 let out = quote! {
831 #[cfg(not(test))]
832 #item
833 };
834 out.into()
835}
836
837// Supported attributes for `concordium-quickcheck`
838
839#[cfg(feature = "concordium-quickcheck")]
840#[proc_macro_attribute]
841/// Derive the appropriate export for an annotated QuickCheck function by
842/// exposing it as `#[concordium_test]`. The macro is similar to `#[quickcheck]`
843/// but uses a customized test runner
844/// instead of the standard `QuickCheck`'s `quickcheck`
845///
846/// The macro optionally takes a `num_tests` attribute that specifies how many
847/// tests to run: `#[concordium_quickcheck(tests = 1000)]`. If no `tests` is
848/// provided, 100 is used.
849///
850/// Note that the maximum number of tests is limited to 1_000_000.
851// QUICKCHECK_MAX_PASSED_TESTS defines the limit.
852pub fn concordium_quickcheck(attr: TokenStream, input: TokenStream) -> TokenStream {
853 use syn::{
854 parse::{Parse, Parser},
855 spanned::Spanned,
856 };
857
858 let input = proc_macro2::TokenStream::from(input);
859 let span = input.span();
860 syn::Item::parse
861 .parse2(input)
862 .and_then(|item| match item {
863 syn::Item::Fn(mut item_fn) => {
864 attribute::quickcheck::wrap_quickcheck_test(attr, &mut item_fn)
865 }
866 _ => Err(syn::Error::new(
867 span,
868 "#[concordium_quickcheck] can only be applied to functions.",
869 )),
870 })
871 .unwrap_or_else(|e| e.to_compile_error())
872 .into()
873}