daml_derive/lib.rs
1//! Procedural macros for generating Rust types and conversions from Daml types and Archives.
2//!
3//! # Overview
4//!
5//! Two mechanisms are provided for representing Daml types in Rust:
6//! * Custom attributes which can be applied to Rust structures which generate Daml type converters.
7//! * A procedural macro code generator which takes a Daml `dar` file as input and generates Rust types annotated with
8//! the custom attributes.
9//!
10//! # Custom Attributes
11//!
12//! This section explains how to use the provided custom attributes to annotate Rust types to generate the Daml ledger
13//! API data conversion code required to be able to use them with a Daml ledger.
14//!
15//! ### Mapping Daml Structures to Rust
16//!
17//! Daml structures are modelled using various Rust language constructs in conjunction with custom attributes
18//! procedural macros as shown in the following table:
19//!
20//! | Daml Concept | Rust Construct | Custom Attribute |
21//! |-------------------------|----------------|------------------------|
22//! | [Daml Template] | `struct` | [`macro@DamlTemplate`] |
23//! | [Daml Template Choices] | `impl` block | [`macro@DamlChoices`] |
24//! | [Daml Data (Record)] | `struct` | [`macro@DamlData`] |
25//! | [Daml Data (Variant)] | `enum` | [`macro@DamlVariant`] |
26//! | [Daml Enum] | `enum` | [`macro@DamlEnum`] |
27//!
28//! ### Mapping Daml Data Types to Rust
29//!
30//! The following table lists the mappings between
31//! [Daml build-in primitive types](https://docs.daml.com/daml/reference/data-types.html#built-in-types) and Rust type
32//! aliases:
33//!
34//! | Daml Type | Rust Type Alias | Concrete Rust Type | Notes |
35//! |-------------------|----------------------|---------------------------------------|------------------------------------------------|
36//! | `Int` | [`DamlInt64`] | `i64` | |
37//! | `Numeric n` | [`DamlNumeric`] | `bigdecimal::BigDecimal` | |
38//! | `Text` | [`DamlText`] | `String` | |
39//! | `Bool` | [`DamlBool`] | `bool` | |
40//! | `Party` | [`DamlParty`] | newtype around `String` | |
41//! | `Date` | [`DamlDate`] | `chrono::NaiveDate` | |
42//! | `Time` | [`DamlTimestamp`] | `chrono::DateTime<Utc>` | |
43//! | `()` | [`DamlUnit`] | `()` | |
44//! | `ContractId a` | [`DamlContractId`] | newtype around `String` | |
45//! | `List a` or `[a]` | [`DamlList<T>`] | `Vec<T>` | type `T` must be another Rust type alias |
46//! | `TextMap a` | [`DamlTextMap<V>`] | newtype around `HashMap<String, V>` | type `V` must be another Rust type alias |
47//! | `GenMap a b` | [`DamlGenMap<K, V>`] | `BTreeMap<K, V>` | types `K`, `V` must be Rust type aliases; `K: Ord` |
48//! | `Optional a` | [`DamlOptional<T>`] | `Option<T>` | type `T` must be another Rust type alias |
49//!
50//!
51//! Note that the concrete Rust types are shown here as a convenience only, in all cases the Rust type alias _must_ be
52//! used when representing Daml constructs so that the Daml types can be determined.
53//!
54//! ### Parameterized Types
55//!
56//! The parameterized types (`List<T>`, `TextMap<T>` and `Optional<T>`) may be freely nested to an arbitrary depth and
57//! may be used in all context a type is expected such as templates & data fields as well as choice parameters.
58//!
59//! For example these are examples of valid types:
60//!
61//! ```no_run
62//! # use daml::prelude::*;
63//! # pub struct MyData {}
64//! let int: DamlInt64;
65//! let party: DamlParty;
66//! let opt_numeric: DamlOptional<DamlNumeric10>;
67//! let list_of_int: DamlList<DamlInt64>;
68//! let list_of_opt_int: DamlList<DamlOptional<DamlInt64>>;
69//! let list_of_opt_map_party: DamlList<DamlOptional<DamlTextMap<DamlParty>>>;
70//! let opt_list_data: DamlOptional<DamlList<MyData>>;
71//! ```
72//!
73//! ### Recursive Data Types
74//!
75//! Daml Data (both Records and Variants) may be recursive. For example:
76//!
77//! ```daml
78//! data Foo = Foo
79//! with
80//! bar : Optional Text
81//! foo : Foo
82//! ```
83//!
84//! Both [`macro@DamlData`] and [`macro@DamlVariant`] types may therefore be defined recursively. However modelling
85//! such structures in Rust requires that any recursively defined items be held via an indirection, typically
86//! via a heap allocation smart pointer such as `Box<T>`, to ensure a non-infinite size for the `struct` or `enum`
87//! (see [here](https://doc.rust-lang.org/error-index.html#E0072) for details).
88//!
89//! The above example can therefore be represented as follows:
90//!
91//! ```no_run
92//! # use daml::prelude::*;
93//! #[DamlData]
94//! pub struct Foo {
95//! bar: DamlOptional<DamlText>,
96//! foo: Box<Foo>,
97//! }
98//! ```
99//!
100//! Note that `Box<T>` is the only form of indirection currently supported and it may be used anywhere `T` is used.
101//!
102//! ### Prelude
103//!
104//! All of the above Rust type aliases are defined in the [`prelude`](https://docs.rs/daml/0.3.0/daml/prelude/index.html) module of
105//! the [`daml`](../daml/index.html) crate and can included by using `daml::prelude::*`.
106//!
107//! ### Modules
108//!
109//! Rust `struct` and `enum` types annotated with the custom attributes provided by this crate are
110//! _not_ required to be nested in Rust `modules` that mirror the Daml `module` hierarchy. All of the standard Rust
111//! name resolution and visibility rules apply and therefore it is recommend to mirror the Daml hierarchy where
112//! possible to avoid namespace collisions.
113//!
114//! For example, the `MyData` data type defined in the `Fuji.MyModule.MySubModule` Daml module would likely be declared
115//! as follows:
116//!
117//! ```no_run
118//! mod fuji {
119//! mod my_module {
120//! mod my_sub_module {
121//! use daml::prelude::*;
122//! #[DamlData]
123//! pub struct MyData {}
124//! }
125//! }
126//! }
127//! ```
128//!
129//! ### Example
130//!
131//! Given the following Daml template declared in the `Fuji.PingPong` module of a given package:
132//!
133//! ```daml
134//! template Ping
135//! with
136//! sender: Party
137//! receiver: Party
138//! count: Int
139//! where
140//! signatory sender
141//! observer receiver
142//!
143//! controller receiver can
144//! ResetCount : ()
145//! with
146//! new_count: Int
147//! do
148//! create Pong with sender; receiver; count = new_count
149//! return ()
150//! ```
151//!
152//! This can be represented in Rust by using the [`macro@DamlTemplate`] and [`macro@DamlChoices`] custom attributes:
153//!
154//! ```no_run
155//! use daml::prelude::*;
156//!
157//! #[DamlTemplate(package_id = r"...package id hash omitted...", module_name = "Fuji.PingPong")]
158//! pub struct Ping {
159//! pub sender: DamlParty,
160//! pub receiver: DamlParty,
161//! pub count: DamlInt64,
162//! }
163//!
164//! #[DamlChoices]
165//! impl Ping {
166//! #[ResetCount]
167//! fn reset_count(&self, new_count: DamlInt64) {}
168//! }
169//! ```
170//!
171//! A new `Ping` can then be created as follows:
172//!
173//! ```no_run
174//! # use daml::prelude::*;
175//! # #[DamlTemplate(package_id = r"", module_name = "Fuji.PingPong")]
176//! # pub struct Ping {
177//! # pub sender: DamlParty,
178//! # pub receiver: DamlParty,
179//! # pub count: DamlInt64,
180//! # }
181//! let ping = Ping::new("Alice", "Bob", 0);
182//! ```
183//!
184//! To create an instance of the `Ping` template on a Daml ledger a [`DamlCreateCommand`] specific to our `ping` data
185//! needs to be constructed. This can be done as follows:
186//!
187//! ```no_run
188//! # use daml::prelude::*;
189//! # #[DamlTemplate(package_id = r"", module_name = "Fuji.PingPong")]
190//! # pub struct Ping {
191//! # pub sender: DamlParty,
192//! # pub receiver: DamlParty,
193//! # pub count: DamlInt64,
194//! # }
195//! # let ping = Ping::new("Alice", "Bob", 0);
196//! let create_ping_command = ping.create_command();
197//! ```
198//!
199//! The generated [`DamlCreateCommand`] can then be submitted to the Daml ledger via the [`DamlCommandService`] or
200//! [`DamlCommandSubmissionService`] as usual.
201//!
202//! Once the contract instance has been created on the Daml ledger and the corresponding [`DamlCreatedEvent`] has been
203//! received then it can be converted into a Rust type as follows:
204//!
205//! ```no_run
206//! # use daml::prelude::*;
207//! # use std::convert::TryInto;
208//! # #[DamlTemplate(package_name = "MyApp", module_name = "Fuji.PingPong")]
209//! # pub struct Ping {
210//! # pub sender: DamlParty,
211//! # pub receiver: DamlParty,
212//! # pub count: DamlInt64,
213//! # }
214//! # fn main() -> DamlResult<()> {
215//! # let created_event: DamlCreatedEvent = unimplemented!("delivered by the participant");
216//! let ping_contract: PingContract = created_event.try_into()?;
217//! # Ok::<(), DamlError>(())
218//! }
219//! ```
220//!
221//! Note that the [`DamlCreatedEvent`] returned by the Daml ledger is converted into a `PingContract` rather than a
222//! plain `Ping`. The `PingContract` type is a `struct` and provides methods `data() -> Ping` and
223//! `id() -> &PingContractId` to access the `Ping` data and contract id respectively:
224//!
225//! ```no_run
226//! # use daml::prelude::*;
227//! # use std::convert::TryInto;
228//! # #[DamlTemplate(package_name = "MyApp", module_name = "Fuji.PingPong")]
229//! # pub struct Ping {
230//! # pub sender: DamlParty,
231//! # pub receiver: DamlParty,
232//! # pub count: DamlInt64,
233//! # }
234//! # fn main() -> DamlResult<()> {
235//! # let created_event: DamlCreatedEvent = unimplemented!("delivered by the participant");
236//! # let ping_contract: PingContract = created_event.try_into()?;
237//! assert_eq!("Alice", ping_contract.data().sender);
238//! assert_eq!("Bob", ping_contract.data().receiver);
239//! assert_eq!(0, ping_contract.data().count);
240//! // Canton emits opaque hex-encoded contract ids (~130 chars); the shape
241//! // below is illustrative only.
242//! assert_eq!(
243//! "00abc0000000000000000000000000000000000000000000000000000000000001",
244//! ping_contract.id().contract_id,
245//! );
246//! # Ok::<(), DamlError>(())
247//! # }
248//! ```
249//!
250//! The `PingContract` types provides a method for each `choice` defined by the Daml `template` along with any
251//! parameters that choice may have. To exercise a choice on a Daml ledger a [`DamlExerciseCommand`] specific to our
252//! contract is needed. This can be constructed as follows:
253//!
254//! ```no_run
255//! # use daml::prelude::*;
256//! # use std::convert::TryInto;
257//! # #[DamlTemplate(package_name = "MyApp", module_name = "Fuji.PingPong")]
258//! # pub struct Ping {
259//! # pub sender: DamlParty,
260//! # pub receiver: DamlParty,
261//! # pub count: DamlInt64,
262//! # }
263//! # #[DamlChoices]
264//! # impl Ping {
265//! # #[ResetCount]
266//! # fn reset_count(&self, new_count: DamlInt64) {}
267//! # }
268//! # fn main() -> DamlResult<()> {
269//! # let created_event: DamlCreatedEvent = unimplemented!("delivered by the participant");
270//! # let ping_contract: PingContract = created_event.try_into()?;
271//! let exercise_command = ping_contract.id().reset_count_command(5);
272//! # Ok::<(), DamlError>(())
273//! }
274//! ```
275//!
276//! The generated [`DamlExerciseCommand`] can then be submitted to the Daml ledger via the [`DamlCommandService`] or
277//! [`DamlCommandSubmissionService`] as usual.
278//!
279//! Note that the name of the choice method _must_ match the name of the Daml choice (in `snake_case`) with a `_command`
280//! suffix and the choice parameters _must_ match between the Daml and Rust representations.
281//!
282//! See the documentation for [`macro@DamlTemplate`], [`macro@DamlChoices`] & [`macro@DamlData`] for full details and
283//! examples.
284//!
285//! ### Errors
286//!
287//! Returns the underlying [`DamlError`] (runtime-only) if the `try_into()` conversion from a [`DamlValue`] to an
288//! annotated type fails.
289//!
290//! ### Panics
291//!
292//! Panics (compile-time only) if errors are detected in the annotated `struct`, `enum` or `impl` blocks.
293//!
294//! [`DamlInt64`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlInt64.html
295//! [`DamlNumeric`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlNumeric.html
296//! [`DamlText`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlText.html
297//! [`DamlBool`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlBool.html
298//! [`DamlParty`]: https://docs.rs/daml/0.3.0/daml/prelude/struct.DamlParty.html
299//! [`DamlDate`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlDate.html
300//! [`DamlTimestamp`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlTimestamp.html
301//! [`DamlUnit`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlUnit.html
302//! [`DamlContractId`]: https://docs.rs/daml/0.3.0/daml/prelude/struct.DamlContractId.html
303//! [`DamlList<T>`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlList.html
304//! [`DamlTextMap<V>`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlTextMap.html
305//! [`DamlGenMap<K, V>`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlGenMap.html
306//! [`DamlOptional<T>`]: https://docs.rs/daml/0.3.0/daml/prelude/type.DamlOptional.html
307//! [`DamlCreateCommand`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/data/command/struct.DamlCreateCommand.html
308//! [`DamlExerciseCommand`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/data/command/struct.DamlExerciseCommand.html
309//! [`DamlCommandService`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/service/struct.DamlCommandService.html
310//! [`DamlCommandSubmissionService`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/service/struct.DamlCommandSubmissionService.html
311//! [`DamlCreatedEvent`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/data/event/struct.DamlCreatedEvent.html
312//! [`DamlError`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/data/enum.DamlError.html
313//! [`DamlValue`]: https://docs.rs/daml-grpc/0.3.0/daml_grpc/data/value/enum.DamlValue.html
314//! [Daml Template]: https://docs.daml.com/daml/reference/templates.html
315//! [Daml Template Choices]: https://docs.daml.com/daml/reference/choices.html
316//! [Daml Data (Record)]: https://docs.daml.com/daml/reference/data-types.html
317//! [Daml Data (Variant)]: https://docs.daml.com/daml/reference/data-types.html#sum-types
318//! [Daml Variant]: https://docs.daml.com/daml/reference/data-types.html#sum-types
319//! [Daml Enum]: https://docs.daml.com/daml/reference/data-types.html#sum-types
320//! [Daml primitive type alias]: ../daml-derive/index.html#mapping-daml-data-types-to-rust
321#![warn(clippy::all, clippy::pedantic, clippy::nursery, rust_2018_idioms)]
322#![allow(
323 clippy::module_name_repetitions,
324 clippy::default_trait_access,
325 clippy::needless_pass_by_value,
326 clippy::manual_assert,
327 // Style-only pedantic / nursery lints intentionally allowed
328 // workspace-wide — none affect correctness.
329 clippy::large_enum_variant,
330 clippy::too_many_lines,
331 clippy::non_canonical_partial_ord_impl,
332 clippy::too_long_first_doc_paragraph,
333 clippy::option_if_let_else,
334 clippy::trivially_copy_pass_by_ref,
335 // Proto-generated code (tonic-build / prost-build) derives PartialEq without Eq.
336 clippy::derive_partial_eq_without_eq,
337)]
338#![allow(non_snake_case, unused_extern_crates)]
339#![forbid(unsafe_code)]
340#![doc(html_favicon_url = "https://docs.daml.com/_static/images/favicon/favicon-32x32.png")]
341#![doc(html_logo_url = "https://docs.daml.com/_static/images/DAML_Logo_Blue.svg")]
342#![doc(html_root_url = "https://docs.rs/daml-derive/0.3.0")]
343
344mod convert;
345mod generator;
346
347use darling::FromMeta;
348use darling::ast::NestedMeta;
349use syn::{DeriveInput, ItemImpl, parse_macro_input};
350
351fn parse_attr_args(attr: proc_macro::TokenStream) -> Vec<NestedMeta> {
352 match NestedMeta::parse_meta_list(attr.into()) {
353 Ok(args) => args,
354 Err(e) => panic!("{}", darling::Error::from(e)),
355 }
356}
357
358/// Custom attribute for modelling Daml templates.
359///
360/// A [Daml Template](https://docs.daml.com/daml/reference/templates.html) is modelled in Rust as a `struct` with the
361/// custom `DamlTemplate` attribute.
362///
363/// # Format
364///
365/// ```ignore
366/// #[DamlTemplate(package_id = "...", module_name = "...")]
367/// pub struct MyTemplate {
368/// ... fields ...
369/// }
370/// ```
371///
372/// The `DamlTemplate` attribute takes the following parameters:
373/// - `package_name` (preferred) — Daml package-name for v2
374/// addressing. At least one of `package_name` / `package_id`
375/// must be set.
376/// - `package_id` — Daml package-id hash. Required if
377/// `package_name` is not provided.
378/// - `module_name` — the fully qualified Daml module name within
379/// the package.
380/// - `implements` (optional) — comma-separated list of
381/// `<pkg>:<Module.Path>:<Iface>` references to interfaces this
382/// template implements. The codegen emits an
383/// `impl <Iface> for <Foo>ContractId {}` block for each entry,
384/// plus `<iface>_<choice>_command(...)` exercise helpers.
385///
386/// Each field within the `struct` takes the form `field_name: FieldType` and fields are separated with an (optionally
387/// trailing) comma as usual. Any [Daml primitive type alias] or a custom [`macro@DamlData`] type may be used. Note
388/// that all fields must be owned by the `struct`, references and lifetimes are not supported.
389///
390/// Note that the supplied `struct` is fully replaced by this custom attribute and only the `struct` name, field names
391/// and types are read, all other information such as visibility modifiers or other attributes are discarded.
392///
393/// The generated `struct` (such as `MyTemplate`) represents the Daml template. The custom attribute also generates
394/// another `struct` (named as `MyTemplateContract`) which represents a contract instance of template on the Daml
395/// ledger. See below for how these two `struct` types can be used together to create and observe contract instances
396/// on the Daml ledger.
397///
398/// # Panics
399///
400/// Panics if the template struct cannot be parsed.
401///
402/// # Examples
403///
404/// Given the following Daml template declared in the `Fuji.PingPong` module of a given package:
405///
406/// ```daml
407/// template Ping
408/// with
409/// sender: Party
410/// receiver: Party
411/// count: Int
412/// where
413/// signatory sender
414/// observer receiver
415/// ```
416///
417/// This can be represented in Rust as follows:
418///
419/// ```no_run
420/// use daml::prelude::*;
421///
422/// #[DamlTemplate(package_id = r"...package id hash omitted...", module_name = "Fuji.PingPong")]
423/// pub struct Ping {
424/// pub sender: DamlParty,
425/// pub receiver: DamlParty,
426/// pub count: DamlInt64,
427/// }
428/// ```
429/// [Daml primitive type alias]: ../daml-derive/index.html#mapping-daml-data-types-to-rust
430#[proc_macro_attribute]
431pub fn DamlTemplate(attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
432 let template_info: DamlTemplateInfo =
433 DamlTemplateInfo::from_list(&parse_attr_args(attr)).unwrap_or_else(|e| panic!("{}", e));
434 let input: DeriveInput = parse_macro_input!(input as DeriveInput);
435 if template_info.package_name.is_none() && template_info.package_id.is_none() {
436 panic!("#[DamlTemplate] requires at least one of `package_name = \"...\"` or `package_id = \"...\"`");
437 }
438 generator::generate_template(
439 input,
440 template_info.package_name,
441 template_info.package_id.unwrap_or_default(),
442 template_info.module_name,
443 template_info.implements.unwrap_or_default(),
444 )
445}
446
447/// Custom attribute for modelling Daml interfaces.
448///
449/// Emits a marker trait whose `interface_id() -> DamlIdentifier`
450/// addresses the interface on the v2 Ledger API by package-name
451/// (preferred) or package-id. Templates that implement the
452/// interface are expected to write
453/// `impl <Interface> for <TemplateContractId> {}` manually for
454/// now; an `implements = "..."` knob on `#[DamlTemplate]` is a
455/// possible future extension.
456///
457/// ```no_run
458/// use daml::prelude::*;
459///
460/// #[DamlInterface(package_name = "fuji", module_name = "Fuji.Asset")]
461/// pub struct MyInterface;
462/// ```
463///
464/// # Panics
465///
466/// Compile-time panic if neither `package_name` nor `package_id` is set,
467/// if `attr` fails to parse via `darling::FromMeta`, or if `input` isn't
468/// a valid Rust `struct`.
469#[proc_macro_attribute]
470pub fn DamlInterface(attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
471 let interface_info: DamlInterfaceInfo =
472 DamlInterfaceInfo::from_list(&parse_attr_args(attr)).unwrap_or_else(|e| panic!("{}", e));
473 let input: DeriveInput = parse_macro_input!(input as DeriveInput);
474 if interface_info.package_name.is_none() && interface_info.package_id.is_none() {
475 panic!("#[DamlInterface] requires at least one of `package_name = \"...\"` or `package_id = \"...\"`");
476 }
477 generator::generate_interface(
478 input,
479 interface_info.package_name,
480 interface_info.package_id.unwrap_or_default(),
481 interface_info.module_name,
482 )
483}
484
485/// Custom attribute for modelling Daml choices.
486///
487/// Choices on Daml templates are modelled as `impl` blocks on the `struct` which defines the template.
488///
489/// # Format
490///
491/// ```ignore
492/// #[DamlChoices]
493/// impl MyTemplate {
494///
495/// #[MyChoice]
496/// fn my_choice(&self) {}
497///
498/// #[MyChoiceWithParams]
499/// fn my_choice_with_params(&self, my_first, param: DamlInt64, my_second_param: DamlParty) {}
500/// }
501/// ```
502///
503/// Note that:
504///
505/// - There can be many choices defined with a single impl block
506/// - Each choice must take `&self` as the first parameter and returns `()`
507/// - Each choice method may take any number of additional parameters
508/// - The name of the Daml choice (i.e. `MyChoice`) must match the Daml template choice name
509/// - The name of the Daml method (i.e. `my_choice`) must match the Daml template choice name in `snake_case`
510/// - Any method body provided is ignored
511/// - No distinction is made between consuming & non-consuming choices
512/// - All parameters must be either a [Daml primitive type alias] or a user defined [`macro@DamlData`]
513///
514/// # Examples
515///
516/// Given the following Daml template declared in the `Fuji.PingPong` module of a given package:
517///
518/// ```daml
519/// template Ping
520/// with
521/// sender: Party
522/// receiver: Party
523/// count: Int
524/// where
525/// signatory sender
526/// observer receiver
527///
528/// controller receiver can
529/// ResetCount : ()
530/// with
531/// new_count: Int
532/// do
533/// create Pong with sender; receiver; count = new_count
534/// return ()
535/// ```
536///
537/// This can be represented in Rust by using the [`macro@DamlTemplate`] and [`macro@DamlChoices`] custom attributes:
538///
539/// ```no_run
540/// use daml::prelude::*;
541///
542/// #[DamlTemplate(package_id = r"...package id hash omitted...", module_name = "Fuji.PingPong")]
543/// pub struct Ping {
544/// pub sender: DamlParty,
545/// pub receiver: DamlParty,
546/// pub count: DamlInt64,
547/// }
548///
549/// #[DamlChoices]
550/// impl Ping {
551/// #[ResetCount]
552/// fn reset_count(&self, new_count: DamlInt64) {}
553/// }
554/// ```
555/// [Daml primitive type alias]: ../daml-derive/index.html#mapping-daml-data-types-to-rust
556#[proc_macro_attribute]
557pub fn DamlChoices(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
558 let input: ItemImpl = parse_macro_input!(input as ItemImpl);
559 generator::generate_choices(input)
560}
561
562/// Custom attribute for modelling Daml data structures.
563///
564/// A [Daml Data](https://docs.daml.com/daml/reference/data-types.html#records-and-record-types) representing a `Record`
565/// and can be modelled in Rust as `struct` with the `DamlData` custom attribute.
566///
567/// # Record Format
568///
569/// Given the following Daml `data` definition:
570///
571/// ```daml
572/// data RGBA = RGBA
573/// with
574/// red: Int
575/// green: Int
576/// blue: Int
577/// alpha: Int
578/// deriving (Eq, Show)
579/// ```
580/// This can be represented as a Rust `struct` with the `DamlData` custom attribute as follows:
581///
582/// ```no_run
583/// use daml::prelude::*;
584///
585/// #[DamlData]
586/// pub struct RGBA {
587/// pub red: DamlInt64,
588/// pub green: DamlInt64,
589/// pub blue: DamlInt64,
590/// pub alpha: DamlInt64,
591/// }
592/// ```
593/// Each field within the `struct` takes the form `field_name: FieldType` and fields are separated with an (optionally
594/// trailing) comma as usual. Any [Daml primitive type alias] or a custom [`macro@DamlData`] type may be used. Note
595/// that all fields must be owned by the `struct`, references and lifetimes are not supported.
596///
597/// Note that the supplied `struct` is fully replaced by this custom attribute and only the `struct` name, field names
598/// and types are read, all other information such as visibility modifiers or other attributes are discarded.
599///
600/// [Daml primitive type alias]: ../daml-derive/index.html#mapping-daml-data-types-to-rust
601#[proc_macro_attribute]
602pub fn DamlData(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
603 let input: DeriveInput = parse_macro_input!(input as DeriveInput);
604 generator::generate_data_struct(input)
605}
606
607/// Custom attribute for modelling Daml variants.
608///
609/// A [Daml Variant](https://docs.daml.com/daml/reference/data-types.html#sum-types) representing a `Sum` types
610/// (variant) can be modelled in Rust as `enum` with the `DamlVariant` custom attribute.
611///
612/// # Format
613///
614/// Given the following Daml `data` definition:
615///
616/// ```daml
617/// data Color =
618/// Red |
619/// Green |
620/// Blue |
621/// Custom [Int] |
622/// Other RGBA
623/// deriving (Eq, Show)
624/// ```
625///
626/// This can be represented as a Rust `enum` with the `DamlVariant` custom attribute as follows:
627///
628/// ```no_run
629/// use daml::prelude::*;
630///
631/// #[DamlData]
632/// pub struct RGBA {
633/// pub red: DamlInt64,
634/// pub green: DamlInt64,
635/// pub blue: DamlInt64,
636/// pub alpha: DamlInt64,
637/// }
638///
639/// #[DamlVariant]
640/// pub enum Color {
641/// Red,
642/// Green,
643/// Blue,
644/// Custom(DamlList<DamlInt64>),
645/// Other(RGBA),
646/// }
647/// ```
648///
649/// Each Daml `Sum` variant constructor is represented as a Rust `enum` variant. Each variant may have either zero
650/// or a single type parameter of any [Daml primitive type alias] or a custom [`macro@DamlData`] type.
651///
652/// For clarify, in the above example there are three separate cases:
653///
654/// - No parameter: simple cases such as `Red`, `Green` and `Blue` in the example above
655/// - Single [Daml primitive type alias] type parameter: for cases such as `Custom` in the example above
656/// - Single [`macro@DamlData`] type parameter: for cases of nested record types such as `Other` in the example above
657///
658/// [Daml primitive type alias]: ../daml-derive/index.html#mapping-daml-data-types-to-rust
659#[proc_macro_attribute]
660pub fn DamlVariant(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
661 let input: DeriveInput = parse_macro_input!(input as DeriveInput);
662 generator::generate_data_variant(input)
663}
664
665/// Custom attribute for modelling Daml enums.
666///
667/// A [Daml Enum](https://docs.daml.com/daml/reference/data-types.html#sum-types) is a special case of a Daml variant
668/// where all constructors are parameterless. This can be modelled in Rust as `enum` with the `DamlEnum` custom
669/// attribute.
670///
671/// # Format
672///
673/// Given the following Daml `data` definition:
674///
675/// ```daml
676/// data DayOfWeek
677/// = Monday
678/// | Tuesday
679/// | Wednesday
680/// | Thursday
681/// | Friday
682/// | Saturday
683/// | Sunday
684/// ```
685///
686/// This can be represented as a Rust `enum` with the `DamlEnum` custom attribute as follows:
687///
688/// ```no_run
689/// use daml::prelude::*;
690///
691/// #[DamlEnum]
692/// pub enum Color {
693/// Red,
694/// Monday,
695/// Tuesday,
696/// Wednesday,
697/// Thursday,
698/// Friday,
699/// Saturday,
700/// Sunday,
701/// }
702/// ```
703#[proc_macro_attribute]
704pub fn DamlEnum(_attr: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
705 let input: DeriveInput = parse_macro_input!(input as DeriveInput);
706 generator::generate_data_enum(input)
707}
708
709/// Function-like procedural macro to generate Rust code for a Daml Daml `dar` ("Daml Archive") files.
710///
711/// This macro can be used to generate both intermediate and full decomposed type.
712///
713/// This section describes how to use use the procedural macro to generate both
714/// [`RenderMethod::Full`](daml_codegen::generator::RenderMethod::Full) and
715/// [`RenderMethod::Intermediate`](daml_codegen::generator::RenderMethod::Intermediate) Rust types from Daml `dar`
716/// file.
717///
718/// Given the following Daml code in module `Fuji.MyModule` of `MyApp` compiled to `MyApp.dar`:
719///
720/// ```daml
721/// template Ping
722/// with
723/// sender: Party
724/// receiver: Party
725/// count: Int
726/// where
727/// signatory sender
728/// observer receiver
729///
730/// controller receiver can
731/// ResetCount : ()
732/// with
733/// new_count: Int
734/// do
735/// create Pong with sender; receiver; count = new_count
736/// return ()
737/// ```
738///
739/// The Rust types and methods required to represent this template can be generated by using `daml_codegen` as
740/// follows:
741///
742/// ```ignore
743/// daml_codegen!(dar_file = r"MyApp.dar", mode = "intermediate");
744/// ```
745///
746/// This produces the following Rust code:
747///
748/// ```no_run
749/// pub mod my_app {
750/// pub mod fuji {
751/// pub mod my_module {
752/// use daml::prelude::*;
753/// #[DamlTemplate(package_id = r"...", module_name = "Fuji.MyModule")]
754/// pub struct Ping {
755/// pub sender: DamlParty,
756/// pub receiver: DamlParty,
757/// pub count: DamlInt64,
758/// }
759///
760/// #[DamlChoices]
761/// impl Ping {
762/// #[ResetCount]
763/// fn reset_count(&self, new_count: DamlInt64) {}
764/// }
765/// }
766/// }
767/// }
768/// ```
769/// See the above for details generated custom attributes such as [`macro@DamlTemplate`] and [`macro@DamlChoices`].
770///
771/// To generate [`RenderMethod::Full`](daml_codegen::generator::RenderMethod::Full) Rust types for a
772/// `MyDamlApplication.dar` for Daml modules which match the regex `Fuji.*`:
773///
774/// ```ignore
775/// daml_codegen!(dar_file = r"MyApp.dar", module_filter_regex = "Fuji.*", mode = "full");
776/// ```
777///
778/// ### Panics
779///
780/// Panics (compile-time only) if errors are detected during code generation.
781#[proc_macro]
782pub fn daml_codegen(attr: proc_macro::TokenStream) -> proc_macro::TokenStream {
783 let args = parse_attr_args(attr);
784 generator::generate_tokens(args)
785}
786
787#[doc(hidden)]
788#[derive(Debug, FromMeta)]
789struct CodeGeneratorParameters {
790 pub dar_file: String,
791 #[darling(multiple)]
792 pub module_filter_regex: Vec<String>,
793 #[darling(default)]
794 pub mode: Option<RenderModeArg>,
795}
796
797/// String-shaped `mode` argument for `daml_codegen!`. darling
798/// matches by variant name (case-insensitive), so `mode = "full"`
799/// and `mode = "Full"` both parse.
800#[doc(hidden)]
801#[derive(Debug, FromMeta)]
802pub(crate) enum RenderModeArg {
803 Intermediate,
804 Full,
805}
806
807#[doc(hidden)]
808#[derive(Debug, FromMeta)]
809struct DamlInterfaceInfo {
810 /// Daml package-name (preferred under v2). When set, the
811 /// generated `interface_id()` addresses the interface by
812 /// `#<package_name>` on the v2 Ledger API wire.
813 #[darling(default)]
814 pub package_name: Option<String>,
815 /// Daml package-id hash. Required when `package_name` is not
816 /// provided.
817 #[darling(default)]
818 pub package_id: Option<String>,
819 pub module_name: String,
820}
821
822#[doc(hidden)]
823#[derive(Debug, FromMeta)]
824struct DamlTemplateInfo {
825 /// Daml package-name (preferred under v2). When set, the
826 /// generated `template_id()` addresses the template by
827 /// `#<package_name>` on the v2 Ledger API wire.
828 #[darling(default)]
829 pub package_name: Option<String>,
830 /// Daml package-id hash. Required when `package_name` is not
831 /// provided; otherwise informational only.
832 #[darling(default)]
833 pub package_id: Option<String>,
834 pub module_name: String,
835 /// Comma-separated list of `<pkg>:<Module.Path>:<Iface>`
836 /// references to interfaces this template implements. The
837 /// codegen emits an `impl <Iface> for <Foo>ContractId {}`
838 /// block per entry plus the matching
839 /// `<iface>_<choice>_command(...)` exercise helpers.
840 #[darling(default)]
841 pub implements: Option<String>,
842}