1#[macro_export]
151macro_rules! daml_path {
152
153 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] ? $( :: $type:ident )? ) => {
168 {
169 let field_value = daml_path!(@get_record_field $record, $path);
170 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
171 let list_item_value = daml_path!(@get_list_item variant_value, $index);
172 let optional_value = list_item_value.try_optional()?.ok_or(DamlError::MissingRequiredField)?;
173 daml_path!(@priv $($type)? optional_value)
174 }
175 };
176
177 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] $( :: $type:ident )? ) => {
179 {
180 let field_value = daml_path!(@get_record_field $record, $path);
181 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
182 let list_item_value = daml_path!(@get_list_item variant_value, $index);
183 daml_path!(@priv $($type)? list_item_value)
184 }
185 };
186
187 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? $( :: $type:ident )? ) => {
189 {
190 let field_value = daml_path!(@get_record_field $record, $path);
191 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
192 daml_path!(@priv $($type)? variant_value)
193 }
194 };
195
196 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? ? $( :: $type:ident )? ) => {
198 {
199 let field_value = daml_path!(@get_record_field $record, $path);
200 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
201 let optional_value = variant_value.try_optional()?.ok_or(DamlError::MissingRequiredField)?;
202 daml_path!(@priv $($type)? optional_value)
203 }
204 };
205
206 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] ? $($rest:tt)* ) => {
208 {
209 let field_value = daml_path!(@get_record_field $record, $path);
210 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
211 let list_item_value = daml_path!(@get_list_item variant_value, $index);
212 let optional_value = list_item_value.try_optional()?.ok_or(DamlError::MissingRequiredField)?;
213 let field_as_record = &(optional_value.try_record()?);
214 daml_path!( @priv field_as_record $($rest)* )
215 }
216 };
217
218 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? [ $index:expr ] $($rest:tt)* ) => {
220 {
221 let field_value = daml_path!(@get_record_field $record, $path);
222 let value_from_variant = daml_path!(@get_variant_value field_value, $($variant)? )?;
223 let list_item_value = daml_path!(@get_list_item value_from_variant, $index);
224 let field_as_record = &(list_item_value.try_record()?);
225 daml_path!( @priv field_as_record $($rest)* )
226 }
227 };
228
229 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? ? $($rest:tt)* ) => {
231 {
232 let field_value = daml_path!(@get_record_field $record, $path);
233 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
234 let optional_value = variant_value.try_optional()?.ok_or(DamlError::MissingRequiredField)?;
235 let field_as_record = &(optional_value.try_record()?);
236 daml_path!( @priv field_as_record $($rest)* )
237 }
238 };
239
240 ( @priv $record:ident / $path:ident { => $variant:ident } $($rest0:tt)* ) => {
242 {
243 let field_value = daml_path!(@get_record_field $record, $path);
244 let variant_value = daml_path!(@get_variant_value field_value, $variant )?;
245 let field_as_record = &(variant_value.try_record()?);
246 daml_path!( @priv field_as_record $($rest0)* )
247 }
248 };
249
250 ( @priv $record:ident / $path:ident $( { => $variant:ident } )? $($rest1:tt)* ) => {
252 {
253 let field_value = daml_path!(@get_record_field $record, $path);
254 let variant_value = daml_path!(@get_variant_value field_value, $($variant)? )?;
255 let field_as_record = &(variant_value.try_record()?);
256 daml_path!( @priv field_as_record $($rest1)* )
257 }
258 };
259
260 ( @priv $value:ident ) => {
262 {
263 let res: DamlResult<&DamlValue> = Ok($value);
264 res
265 }
266 };
267 ( @priv c $value:ident ) => {
268 $value.try_contract_id()
269 };
270 ( @priv u $value:ident ) => {
271 $value.try_unit_ref()
272 };
273 ( @priv p $value:ident ) => {
274 $value.try_party()
275 };
276 ( @priv i $value:ident ) => {
277 $value.try_int64_ref()
278 };
279 ( @priv f $value:ident ) => {
280 $value.try_numeric()
281 };
282 ( @priv t $value:ident ) => {
283 $value.try_text()
284 };
285 ( @priv b $value:ident ) => {
286 $value.try_bool_ref()
287 };
288 ( @priv s $value:ident ) => {
289 $value.try_timestamp_ref()
290 };
291 ( @priv d $value:ident ) => {
292 $value.try_date_ref()
293 };
294 ( @priv r $value:ident ) => {
295 $value.try_record()
296 };
297 ( @priv l $value:ident ) => {
298 $value.try_list()
299 };
300 ( @priv v $value:ident ) => {
301 $value.try_variant()
302 };
303
304 ( @get_record_field $record:ident, $path:ident ) => {
306 $record.field(stringify!($path))?
307 };
308
309 ( @get_list_item $value:ident, $index:expr ) => {
311 {
312 let field_as_list = $value.try_list()?;
313 let list_item_value: &DamlValue = field_as_list.get($index).ok_or(DamlError::ListIndexOutOfRange($index))?;
314 list_item_value
315 }
316 };
317
318 ( @get_variant_value $value:ident , $variant:ident ) => {
320 {
321 let variant = $value.try_variant()?;
322 if stringify!($variant) == "__" || variant.constructor() == stringify!($variant) {
323 Ok(variant.value())
324 } else {
325 Err(DamlError::UnexpectedVariant(stringify!($variant).to_owned(), variant.constructor().to_owned()))
326 }
327 }
328 };
329
330 ( @get_variant_value $value:ident , ) => {
332 {
333 let res: DamlResult<_> = Ok($value);
334 res
335 }
336 };
337
338 ( $($rest:tt)* ) => {
340 {
341 use $crate::daml_grpc::data::DamlResult;
342 use $crate::daml_grpc::data::value::DamlRecord;
343 let func: fn(&DamlRecord) -> DamlResult<&_> = | rec_ref: &DamlRecord | {
344 daml_path!( @priv rec_ref / $($rest)* )
345 };
346 func
347 }
348 };
349}
350
351#[cfg(test)]
352mod test {
353 use crate::daml_value;
354 use crate::test_util::TestResult;
355 use crate::test_util::{make_date, make_timestamp};
356 use bigdecimal::BigDecimal;
357 use daml_grpc::data::value::{DamlRecord, DamlValue, DamlVariant};
358 use daml_grpc::data::DamlError;
359 use std::convert::TryFrom;
360
361 #[test]
362 pub fn test_top_party() -> TestResult {
363 let value: DamlValue = get_test_value();
364 assert_eq!("Alice", value.extract(daml_path![sender::p])?);
365 Ok(())
366 }
367
368 #[test]
369 pub fn test_record_top_party() -> TestResult {
370 let value: DamlValue = get_test_value();
371 let record: &DamlRecord = value.try_record()?;
372 assert_eq!("Alice", record.extract(daml_path![sender::p])?);
373 Ok(())
374 }
375
376 #[test]
377 pub fn test_nested_party() -> TestResult {
378 let value: DamlValue = get_test_value();
379 assert_eq!("Sue", value.extract(daml_path![person / party::p])?);
380 Ok(())
381 }
382
383 #[test]
384 pub fn test_nested_contract() -> TestResult {
385 let value: DamlValue = get_test_value();
386 assert_eq!("#1:1", value.extract(daml_path![person / data / contractId::c])?);
387 Ok(())
388 }
389
390 #[test]
391 pub fn test_nested_value() -> TestResult {
392 let value: DamlValue = get_test_value();
393 assert_eq!(&DamlValue::new_contract_id("#1:1"), value.extract(daml_path![person / data / contractId])?);
394 Ok(())
395 }
396
397 #[test]
398 pub fn test_nested_int64() -> TestResult {
399 let value: DamlValue = get_test_value();
400 assert_eq!(0_i64, *value.extract(daml_path![person / data / count::i])?);
401 Ok(())
402 }
403
404 #[test]
405 pub fn test_nested_bool() -> TestResult {
406 let value: DamlValue = get_test_value();
407 assert!(!*value.extract(daml_path![person / data / is_true::b])?);
408 Ok(())
409 }
410
411 #[test]
412 pub fn test_nested_unit() -> TestResult {
413 let value: DamlValue = get_test_value();
414 assert_eq!((), *value.extract(daml_path![person / empty::u])?);
415 Ok(())
416 }
417
418 #[test]
419 pub fn test_top_numeric() -> TestResult {
420 let value: DamlValue = get_test_value();
421 assert_eq!(&BigDecimal::try_from(1.23).unwrap(), value.extract(daml_path![height::f])?);
422 Ok(())
423 }
424
425 #[test]
426 pub fn test_top_date() -> TestResult {
427 let value: DamlValue = get_test_value();
428 assert_eq!(&make_date("2019-01-02")?, value.extract(daml_path![today::d])?);
429 Ok(())
430 }
431
432 #[test]
433 pub fn test_top_datetime() -> TestResult {
434 let value: DamlValue = get_test_value();
435 assert_eq!(&make_timestamp("2019-01-02T03:45:56Z")?, value.extract(daml_path![right_now::s])?);
436 Ok(())
437 }
438
439 #[test]
440 pub fn test_top_optional_value() -> TestResult {
441 let value: DamlValue = get_test_value();
442 assert_eq!(&DamlValue::new_int64(123), value.extract(daml_path![opt_int?])?);
443 Ok(())
444 }
445
446 #[test]
447 pub fn test_top_variant_value() -> TestResult {
448 let value: DamlValue = get_test_value();
449 assert_eq!(&DamlValue::new_text("I'm a Foo"), value.extract(daml_path![variant_text{=>Foo}])?);
450 Ok(())
451 }
452
453 #[test]
454 pub fn test_top_variant() -> TestResult {
455 let value: DamlValue = get_test_value();
456 assert_eq!(
457 &DamlVariant::new("Foo", Box::new(DamlValue::new_text("I'm a Foo")), None),
458 value.extract(daml_path![variant_text::v])?
459 );
460 Ok(())
461 }
462
463 #[test]
464 pub fn test_nested_text() -> TestResult {
465 let value: DamlValue = get_test_value();
466 assert_eq!("apple", value.extract(daml_path![person / data / fruit::t])?);
467 Ok(())
468 }
469
470 #[test]
471 pub fn test_nested_record() -> TestResult {
472 let value: DamlValue = get_test_value();
473 assert_eq!(4, value.extract(daml_path![person / data::r])?.fields().len());
474 Ok(())
475 }
476
477 #[test]
478 pub fn test_nested_list() -> TestResult {
479 let value: DamlValue = get_test_value();
480 assert_eq!(3, value.extract(daml_path![person / stats::l])?.len());
481 Ok(())
482 }
483
484 #[test]
485 pub fn test_list_item() -> TestResult {
486 let value: DamlValue = get_test_value();
487 assert_eq!("a", value.extract(daml_path![items::l])?[0].extract(daml_path![a::t])?);
488 assert_eq!("b", value.extract(daml_path![items::l])?[1].extract(daml_path![b::t])?);
489 Ok(())
490 }
491
492 #[test]
493 pub fn test_top_list_record_item_text() -> TestResult {
494 let value: DamlValue = get_test_value();
495 assert_eq!("a", value.extract(daml_path![items[0] / a::t])?);
496 Ok(())
497 }
498
499 #[test]
500 pub fn test_top_list_leaf_item_text() -> TestResult {
501 let value: DamlValue = get_test_value();
502 assert_eq!("foo", value.extract(daml_path![simple_list[0]::t])?);
503 assert_eq!("bar", value.extract(daml_path![simple_list[1]::t])?);
504 Ok(())
505 }
506
507 #[test]
508 pub fn test_top_list_leaf_item_value() -> TestResult {
509 let value: DamlValue = get_test_value();
510 assert_eq!(&DamlValue::new_text("bar"), value.extract(daml_path![simple_list[1]])?);
511 Ok(())
512 }
513
514 #[test]
515 pub fn test_list_index_expression() -> TestResult {
516 let value: DamlValue = get_test_value();
517 assert_eq!("bar", value.extract(daml_path![simple_list[2 - 1]::t])?);
518 Ok(())
519 }
520
521 #[test]
522 pub fn test_nested_list_item_value() -> TestResult {
523 let value: DamlValue = get_test_value();
524 assert_eq!(&DamlValue::new_int64(1), value.extract(daml_path![person / stats[0]])?);
525 Ok(())
526 }
527
528 #[test]
529 pub fn test_nested_list_item_int64() -> TestResult {
530 let value: DamlValue = get_test_value();
531 assert_eq!(1, *value.extract(daml_path![person/stats[0]::i])?);
532 Ok(())
533 }
534
535 #[test]
544 pub fn test_list_in_list_of_record() -> TestResult {
545 let value: DamlValue = get_test_value();
546 assert_eq!(99, *value.extract(daml_path![items[1]/the_list[0]::i])?);
547 Ok(())
548 }
549
550 #[test]
551 pub fn test_optional_int() -> TestResult {
552 let value: DamlValue = get_test_value();
553 assert_eq!(123, *value.extract(daml_path![opt_int?::i])?);
554 Ok(())
555 }
556
557 #[test]
558 pub fn test_optional_rec() -> TestResult {
559 let value: DamlValue = get_test_value();
560 assert_eq!("cat", value.extract(daml_path![opt_rec? / pet::t])?);
561 Ok(())
562 }
563
564 #[test]
565 pub fn test_nested_optional_rec() -> TestResult {
566 let value: DamlValue = get_test_value();
567 assert!(*value.extract(daml_path![opt_rec?/is_cat?::b])?);
568 Ok(())
569 }
570
571 #[test]
572 pub fn test_list_of_optional_final() -> TestResult {
573 let value: DamlValue = get_test_value();
574 assert_eq!(1, *value.extract(daml_path![list_of_opt[0]?::i])?);
575 Ok(())
576 }
577
578 #[test]
579 pub fn test_list_of_optional_non_final() -> TestResult {
580 let value: DamlValue = get_test_value();
581 assert_eq!("a", value.extract(daml_path![list_of_opt_rec[0]? / a::t])?);
582 Ok(())
583 }
584
585 #[test]
586 pub fn test_top_named_variant_text() -> TestResult {
587 let value: DamlValue = get_test_value();
588 assert_eq!("I'm a Foo", value.extract(daml_path![variant_text{=>Foo}::t])?);
589 Ok(())
590 }
591
592 #[test]
593 pub fn test_top_named_variant_value() -> TestResult {
594 let value: DamlValue = get_test_value();
595 assert_eq!(&DamlValue::new_text("I'm a Foo"), value.extract(daml_path![variant_text{=>Foo}])?);
596 Ok(())
597 }
598
599 #[test]
600 pub fn test_top_any_variant_text() -> TestResult {
601 let value: DamlValue = get_test_value();
602 assert_eq!("I'm a Foo", value.extract(daml_path![variant_text{=>__}::t])?);
603 Ok(())
604 }
605
606 #[test]
607 pub fn test_top_named_variant_optional_int() -> TestResult {
608 let value: DamlValue = get_test_value();
609 assert_eq!(999, *value.extract(daml_path![variant_opt_int{=>Foo}?::i])?);
610 Ok(())
611 }
612
613 #[test]
614 pub fn test_top_named_variant_list() -> TestResult {
615 let value: DamlValue = get_test_value();
616 assert_eq!("One", value.extract(daml_path![variant_list{=>Foo}[0]::t])?);
617 Ok(())
618 }
619
620 #[test]
621 pub fn test_top_named_variant_list_optional() -> TestResult {
622 let value: DamlValue = get_test_value();
623 assert_eq!("Two", value.extract(daml_path![variant_list_opt{=>Foo}[1]?::t])?);
624 Ok(())
625 }
626
627 #[test]
628 pub fn test_nested_named_variant_int() -> TestResult {
629 let value: DamlValue = get_test_value();
630 assert_eq!(4, *value.extract(daml_path![other{=>Cat}/paw_count::i])?);
631 Ok(())
632 }
633
634 #[test]
635 pub fn test_nested_any_variant_int() -> TestResult {
636 let value: DamlValue = get_test_value();
637 assert_eq!(4, *value.extract(daml_path![other{=>__}/paw_count::i])?);
638 Ok(())
639 }
640
641 #[test]
642 pub fn test_nested_named_variant_optional_int() -> TestResult {
643 let value: DamlValue = get_test_value();
644 assert_eq!("Red", value.extract(daml_path![other_opt{=>Fruit}?/color::t])?);
645 Ok(())
646 }
647
648 #[test]
649 pub fn test_nested_named_variant_list() -> TestResult {
650 let value: DamlValue = get_test_value();
651 assert_eq!("Blue", value.extract(daml_path![other_var_list{=>Foo}[0]/color::t])?);
652 Ok(())
653 }
654
655 #[test]
656 pub fn test_nested_named_variant_list_optional() -> TestResult {
657 let value: DamlValue = get_test_value();
658 assert_eq!("Green", value.extract(daml_path![other_var_list_opt{=>Foo}[0]?/color::t])?);
659 Ok(())
660 }
661
662 #[test]
663 pub fn test_top_no_result_function() {
664 let value: DamlValue = get_test_value();
665 assert_eq!("Alice", value.extract(daml_path![sender::p]).expect("should not fail"));
666 }
667
668 #[test]
669 pub fn test_unknown_field() {
670 let value: DamlValue = get_test_value();
671 let result = value.extract(daml_path![unknown]);
672 match result {
673 Err(DamlError::UnknownField(s)) => assert_eq!("unknown", s),
674 _ => panic!("expected failure"),
675 }
676 }
677
678 #[test]
679 pub fn test_nested_unknown_field() {
680 let value: DamlValue = get_test_value();
681 let result = value.extract(daml_path![person / unknown]);
682 match result {
683 Err(DamlError::UnknownField(s)) => assert_eq!("unknown", s),
684 _ => panic!("expected failure"),
685 }
686 }
687
688 #[test]
689 pub fn test_wrong_type_field() {
690 let value: DamlValue = get_test_value();
691 let result = value.extract(daml_path![sender::i]);
692 match result {
693 Err(DamlError::UnexpectedType(expected, actual)) => {
694 assert_eq!("Int64", expected);
695 assert_eq!("Party", actual);
696 },
697 _ => panic!("expected failure"),
698 }
699 }
700
701 #[test]
702 pub fn test_list_index_out_of_range() {
703 let value: DamlValue = get_test_value();
704 let result = value.extract(daml_path![items[99]::i]);
705 match result {
706 Err(DamlError::ListIndexOutOfRange(idx)) => assert_eq!(99, idx),
707 _ => panic!("expected failure"),
708 }
709 }
710
711 #[test]
712 pub fn test_bad_variant() {
713 let value: DamlValue = get_test_value();
714 let result = value.extract(daml_path![variant_text{=>Bar}::t]);
715 match result {
716 Err(DamlError::UnexpectedVariant(expected, actual)) => {
717 assert_eq!("Bar", expected);
718 assert_eq!("Foo", actual);
719 },
720 _ => panic!("expected failure"),
721 }
722 }
723
724 fn get_test_value() -> DamlValue {
725 daml_value![{
726 sender: "Alice"::p,
727 receiver: "Bob"::p,
728 person: {
729 party: "Sue"::p,
730 data: {
731 count: 0,
732 fruit: "apple",
733 contractId: "#1:1"::c,
734 is_true: false
735 },
736 stats: [1, 2, 3],
737 empty: ()
738 },
739 height: 1.23,
740 items: [{a: "a"}, {b: "b", the_list: [99, 98, 101]}],
741 simple_list: ["foo", "bar", ["text in nested list"]],
742 today: "2019-01-02"::d,
743 right_now: "2019-01-02T03:45:56Z"::t,
744 opt_int: {?= 123},
745 opt_rec: {?= {
746 pet: "cat",
747 is_cat: {?= true},
748 food: ["ham", "eggs"]
749 }},
750 list_of_opt: [{?=1}, {?=2}, {?=3}],
751 opt_list: {?=[1,2,3]},
752 list_of_opt_rec: [
753 {?= {a: "a"}},
754 {?= {b: "b"}},
755 {?= {c: "c"}}
756 ],
757 variant_text: {=>Foo "I'm a Foo"},
758 variant_opt_int: {=>Foo {?= 999}},
759 variant_list: {=>Foo ["One", "Two"]},
760 variant_list_opt: {=>Foo [{?="One"}, {?="Two"}]},
761 other: {=>Cat {
762 paw_count: 4
763 }},
764 other_opt: {=>Fruit {?= {
765 color: "Red"
766 }}},
767 other_var_list: {=>Foo [{color: "Blue"}]},
768 other_var_list_opt: {=>Foo [{?= {color: "Green"}}]}
769 }]
770 }
771}