daml_macro

Macro daml_path

Source
macro_rules! daml_path {
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] ? $( :: $type:ident )? ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] $( :: $type:ident )? ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? $( :: $type:ident )? ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? ? $( :: $type:ident )? ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] ? $($rest:tt)* ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] $($rest:tt)* ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? ? $($rest:tt)* ) => { ... };
    ( @priv $record:ident / $path:ident { => $variant:ident } $($rest0:tt)* ) => { ... };
    ( @priv $record:ident / $path:ident $( { => $variant:ident } )? $($rest1:tt)* ) => { ... };
    ( @priv $value:ident ) => { ... };
    ( @priv c $value:ident ) => { ... };
    ( @priv u $value:ident ) => { ... };
    ( @priv p $value:ident ) => { ... };
    ( @priv i $value:ident ) => { ... };
    ( @priv f $value:ident ) => { ... };
    ( @priv t $value:ident ) => { ... };
    ( @priv b $value:ident ) => { ... };
    ( @priv s $value:ident ) => { ... };
    ( @priv d $value:ident ) => { ... };
    ( @priv r $value:ident ) => { ... };
    ( @priv l $value:ident ) => { ... };
    ( @priv v $value:ident ) => { ... };
    ( @get_record_field $record:ident, $path:ident ) => { ... };
    ( @get_list_item $value:ident, $index:expr ) => { ... };
    ( @get_variant_value $value:ident , $variant:ident ) => { ... };
    ( @get_variant_value $value:ident , ) => { ... };
    ( $($rest:tt)* ) => { ... };
}
Expand description

Construct a Daml data extractor function from a path expression.

This macro provides a concise DSL for constructing a Daml data extractor closure as required by DamlRecord::extract and DamlValue::extract. The closure produced will have the following signature:

Fn(&DamlRecord) -> DamlResult<R>

The type of R depends on the path expression provided and may either be a reference to a DamlValue or a reference to another type such as &str.

§Syntax

Path expressions take the following form (pseudo-regex syntax):

field ( '{' '=>' variant '}' )? ( '[' index ']' )? ( '?' )?  (  '/'  ...  )*  ( '::' type )?
----- ------------------------- ------------------ --------  -  ---  ---  --  --------------
 (1)              (2)                   (3)          (4)     |  (5)  (6)  |        (7)

Each field corresponds to a labelled DamlRecordField within the DamlRecord on which the data extractor is to be executed.

Syntax Items:

  1. the field of the current DamlValue::Record to traverse
  2. extract the DamlValue if field is a DamlValue::Variant and variant matches the constructor.
  3. extract the DamlValue from list at index (expression) if field is a DamlValue::List
  4. extract the DamlValue if field is a DamlValue::Optional
  5. a separator between field entries
  6. a repeat of items (1), (2), (3) & (4). Items (5) & (6) are repeated zero or many times.
  7. an optional type specifier

Note that any or all of (2), (3) & (4) can be applied for a single field and will run consecutively. i.e. in the single path field people{=>Persons}[0]? will interpret people as a DamlValue::Variant with a constructor of Persons which is a DamlValue::List which has an element at index 0 which contain an DamlValue::Optional that is a DamlValue::Int64.

Note that the path expression is not whitespace sensitive.

Fields which are nested DamlRecord can be traversed by chaining together multiple field elements delimited with a / character. Nesting can be of arbitrary depth (up to the default recursive macro limit). Attempting to access a non-existent field will return in an UnknownField error being returned.

List elements of fields which are of type DamlValue::List can be accessed by specifying a list index expression inside [] braces. A ListIndexOutOfRange error will be returned if an attempt is made to access lists elements outside the available bounds.

Optional fields of type DamlValue::Optional can be accessed by appending a ? character to the record field name or list element. If the optional is Some then the embedded DamlValue is extracted and processing of the path expression continues. If the optional is None then a MissingRequiredField error will be returned.

The final field may optionally have a type specifier by appending a :: token followed by one of several supported type specifier codes. If no type specifier code is provided then the expression will return a DamlValue otherwise a type appropriate to the specifier will be returned.

If the constructor of a DamlValue::Variant does not match then UnexpectedVariant error is returned. The special variant value of __ can be used to indicate that any variant is acceptable. Attempting to access the nested DamlValue within a variant will produce an error if the type of the item does not match the actual variant type.

The supported type specifiers are:

codenameRust typevalue variant
ccontract id&strDamlValue::ContractId
uunit&()DamlValue::Unit
pparty&strDamlValue::Party
iint64&i64DamlValue::Int64
fnumeric&BigIntegerDamlValue::Numeric
ttext&strDamlValue::Text
stimestamp&DateTime<Utc>DamlValue::Timestamp
bboolean&boolDamlValue::Bool
ddate&Date<Utc>DamlValue::Date
rrecord&DamlRecordDamlValue::Record
llist&Vec<DamlValue>DamlValue::List
vvariant&DamlVariantDamlValue::Variant

§Limitations

Path expressions only support labelled DamlRecordField fields. Accessing unlabelled fields will result in an UnknownField error being returned.

Accessing values from a list-of-list is not supported and therefore path expression syntax my_list[0][1] is not valid. To access the sublist first extract the parent list with the path expression my_list[0] and then apply a second path expression to the resulting DamlValue. Note that a list containing DamlRecord which in turn contains nested lists is supported.

All type specifiers return references, even for simple copy types, and so must be dereferenced as needed.

There is currently no support for DamlValue::Map, DamlValue::GenMap or DamlValue::Enum.

§Examples

let value = daml_value![{
    party: "Alice"::p,
    trade: {
        trade_id: 123,
        counterparty: "Bob"::p,
        trade_details: {
            ticker: "GOOG",
            prices: [1231.54, 1234.85, 1237.92]
        },
        order_type: {?= "MarketOrder"}
    }
}];
assert_eq!("Alice", value.extract(daml_path![party::p])?);
assert_eq!(123, *value.extract(daml_path![trade/trade_id::i])?);
assert_eq!("Bob", value.extract(daml_path![trade/counterparty::p])?);
assert_eq!("GOOG", value.extract(daml_path![trade/trade_details/ticker::t])?);
assert_eq!(&BigDecimal::try_from(1234.85).unwrap(),
                value.extract(daml_path![trade/trade_details/prices[1]::f])?);
assert_eq!("MarketOrder", value.extract(daml_path![trade/order_type?::t])?);