1use alloc::{
18 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
19 vec::Vec,
20};
21use core::mem;
22use sp_runtime::{traits::Saturating, RuntimeDebug};
23use xcm::latest::{
24 Asset, AssetFilter, AssetId, AssetInstance, Assets,
25 Fungibility::{Fungible, NonFungible},
26 InteriorLocation, Location, Reanchorable,
27 WildAsset::{All, AllCounted, AllOf, AllOfCounted},
28 WildFungibility::{Fungible as WildFungible, NonFungible as WildNonFungible},
29};
30
31#[derive(Default, Clone, RuntimeDebug, Eq, PartialEq)]
33pub struct AssetsInHolding {
34 pub fungible: BTreeMap<AssetId, u128>,
36
37 pub non_fungible: BTreeSet<(AssetId, AssetInstance)>,
41}
42
43impl From<Asset> for AssetsInHolding {
44 fn from(asset: Asset) -> AssetsInHolding {
45 let mut result = Self::default();
46 result.subsume(asset);
47 result
48 }
49}
50
51impl From<Vec<Asset>> for AssetsInHolding {
52 fn from(assets: Vec<Asset>) -> AssetsInHolding {
53 let mut result = Self::default();
54 for asset in assets.into_iter() {
55 result.subsume(asset)
56 }
57 result
58 }
59}
60
61impl From<Assets> for AssetsInHolding {
62 fn from(assets: Assets) -> AssetsInHolding {
63 assets.into_inner().into()
64 }
65}
66
67impl From<AssetsInHolding> for Vec<Asset> {
68 fn from(a: AssetsInHolding) -> Self {
69 a.into_assets_iter().collect()
70 }
71}
72
73impl From<AssetsInHolding> for Assets {
74 fn from(a: AssetsInHolding) -> Self {
75 a.into_assets_iter().collect::<Vec<Asset>>().into()
76 }
77}
78
79#[derive(Debug)]
81pub enum TakeError {
82 AssetUnderflow(Asset),
84}
85
86impl AssetsInHolding {
87 pub fn new() -> Self {
89 Self::default()
90 }
91
92 pub fn len(&self) -> usize {
94 self.fungible.len() + self.non_fungible.len()
95 }
96
97 pub fn is_empty(&self) -> bool {
99 self.fungible.is_empty() && self.non_fungible.is_empty()
100 }
101
102 pub fn fungible_assets_iter(&self) -> impl Iterator<Item = Asset> + '_ {
104 self.fungible
105 .iter()
106 .map(|(id, &amount)| Asset { fun: Fungible(amount), id: id.clone() })
107 }
108
109 pub fn non_fungible_assets_iter(&self) -> impl Iterator<Item = Asset> + '_ {
111 self.non_fungible
112 .iter()
113 .map(|(id, instance)| Asset { fun: NonFungible(*instance), id: id.clone() })
114 }
115
116 pub fn into_assets_iter(self) -> impl Iterator<Item = Asset> {
118 self.fungible
119 .into_iter()
120 .map(|(id, amount)| Asset { fun: Fungible(amount), id })
121 .chain(
122 self.non_fungible
123 .into_iter()
124 .map(|(id, instance)| Asset { fun: NonFungible(instance), id }),
125 )
126 }
127
128 pub fn assets_iter(&self) -> impl Iterator<Item = Asset> + '_ {
130 self.fungible_assets_iter().chain(self.non_fungible_assets_iter())
131 }
132
133 pub fn subsume_assets(&mut self, mut assets: AssetsInHolding) {
137 for (asset_id, asset_amount) in assets.fungible {
140 self.fungible
141 .entry(asset_id)
142 .and_modify(|current_asset_amount| {
143 current_asset_amount.saturating_accrue(asset_amount)
144 })
145 .or_insert(asset_amount);
146 }
147 self.non_fungible.append(&mut assets.non_fungible);
151 }
152
153 pub fn subsume(&mut self, asset: Asset) {
157 match asset.fun {
158 Fungible(amount) => {
159 self.fungible
160 .entry(asset.id)
161 .and_modify(|e| *e = e.saturating_add(amount))
162 .or_insert(amount);
163 },
164 NonFungible(instance) => {
165 self.non_fungible.insert((asset.id, instance));
166 },
167 }
168 }
169
170 pub fn swapped(&mut self, mut with: AssetsInHolding) -> Self {
172 mem::swap(&mut *self, &mut with);
173 with
174 }
175
176 pub fn prepend_location(&mut self, prepend: &Location) {
182 let mut fungible = Default::default();
183 mem::swap(&mut self.fungible, &mut fungible);
184 self.fungible = fungible
185 .into_iter()
186 .map(|(mut id, amount)| {
187 let _ = id.prepend_with(prepend);
188 (id, amount)
189 })
190 .collect();
191 let mut non_fungible = Default::default();
192 mem::swap(&mut self.non_fungible, &mut non_fungible);
193 self.non_fungible = non_fungible
194 .into_iter()
195 .map(|(mut class, inst)| {
196 let _ = class.prepend_with(prepend);
197 (class, inst)
198 })
199 .collect();
200 }
201
202 pub fn reanchor(
207 &mut self,
208 target: &Location,
209 context: &InteriorLocation,
210 mut maybe_failed_bin: Option<&mut Self>,
211 ) {
212 let mut fungible = Default::default();
213 mem::swap(&mut self.fungible, &mut fungible);
214 self.fungible = fungible
215 .into_iter()
216 .filter_map(|(mut id, amount)| match id.reanchor(target, context) {
217 Ok(()) => Some((id, amount)),
218 Err(()) => {
219 maybe_failed_bin.as_mut().map(|f| f.fungible.insert(id, amount));
220 None
221 },
222 })
223 .collect();
224 let mut non_fungible = Default::default();
225 mem::swap(&mut self.non_fungible, &mut non_fungible);
226 self.non_fungible = non_fungible
227 .into_iter()
228 .filter_map(|(mut class, inst)| match class.reanchor(target, context) {
229 Ok(()) => Some((class, inst)),
230 Err(()) => {
231 maybe_failed_bin.as_mut().map(|f| f.non_fungible.insert((class, inst)));
232 None
233 },
234 })
235 .collect();
236 }
237
238 pub fn contains_asset(&self, asset: &Asset) -> bool {
240 match asset {
241 Asset { fun: Fungible(amount), id } =>
242 self.fungible.get(id).map_or(false, |a| a >= amount),
243 Asset { fun: NonFungible(instance), id } =>
244 self.non_fungible.contains(&(id.clone(), *instance)),
245 }
246 }
247
248 pub fn contains_assets(&self, assets: &Assets) -> bool {
250 assets.inner().iter().all(|a| self.contains_asset(a))
251 }
252
253 pub fn contains(&self, assets: &AssetsInHolding) -> bool {
255 assets
256 .fungible
257 .iter()
258 .all(|(k, v)| self.fungible.get(k).map_or(false, |a| a >= v)) &&
259 self.non_fungible.is_superset(&assets.non_fungible)
260 }
261
262 pub fn ensure_contains(&self, assets: &Assets) -> Result<(), TakeError> {
265 for asset in assets.inner().iter() {
266 match asset {
267 Asset { fun: Fungible(amount), id } => {
268 if self.fungible.get(id).map_or(true, |a| a < amount) {
269 return Err(TakeError::AssetUnderflow((id.clone(), *amount).into()))
270 }
271 },
272 Asset { fun: NonFungible(instance), id } => {
273 let id_instance = (id.clone(), *instance);
274 if !self.non_fungible.contains(&id_instance) {
275 return Err(TakeError::AssetUnderflow(id_instance.into()))
276 }
277 },
278 }
279 }
280 return Ok(())
281 }
282
283 fn general_take(
297 &mut self,
298 mask: AssetFilter,
299 saturate: bool,
300 ) -> Result<AssetsInHolding, TakeError> {
301 let mut taken = AssetsInHolding::new();
302 let maybe_limit = mask.limit().map(|x| x as usize);
303 match mask {
304 AssetFilter::Wild(All) | AssetFilter::Wild(AllCounted(_)) => match maybe_limit {
305 None => return Ok(self.swapped(AssetsInHolding::new())),
306 Some(limit) if self.len() <= limit =>
307 return Ok(self.swapped(AssetsInHolding::new())),
308 Some(0) => return Ok(AssetsInHolding::new()),
309 Some(limit) => {
310 let fungible = mem::replace(&mut self.fungible, Default::default());
311 fungible.into_iter().for_each(|(c, amount)| {
312 if taken.len() < limit {
313 taken.fungible.insert(c, amount);
314 } else {
315 self.fungible.insert(c, amount);
316 }
317 });
318 let non_fungible = mem::replace(&mut self.non_fungible, Default::default());
319 non_fungible.into_iter().for_each(|(c, instance)| {
320 if taken.len() < limit {
321 taken.non_fungible.insert((c, instance));
322 } else {
323 self.non_fungible.insert((c, instance));
324 }
325 });
326 },
327 },
328 AssetFilter::Wild(AllOfCounted { fun: WildFungible, id, .. }) |
329 AssetFilter::Wild(AllOf { fun: WildFungible, id }) =>
330 if maybe_limit.map_or(true, |l| l >= 1) {
331 if let Some((id, amount)) = self.fungible.remove_entry(&id) {
332 taken.fungible.insert(id, amount);
333 }
334 },
335 AssetFilter::Wild(AllOfCounted { fun: WildNonFungible, id, .. }) |
336 AssetFilter::Wild(AllOf { fun: WildNonFungible, id }) => {
337 let non_fungible = mem::replace(&mut self.non_fungible, Default::default());
338 non_fungible.into_iter().for_each(|(c, instance)| {
339 if c == id && maybe_limit.map_or(true, |l| taken.len() < l) {
340 taken.non_fungible.insert((c, instance));
341 } else {
342 self.non_fungible.insert((c, instance));
343 }
344 });
345 },
346 AssetFilter::Definite(assets) => {
347 if !saturate {
348 self.ensure_contains(&assets)?;
349 }
350 for asset in assets.into_inner().into_iter() {
351 match asset {
352 Asset { fun: Fungible(amount), id } => {
353 let (remove, amount) = match self.fungible.get_mut(&id) {
354 Some(self_amount) => {
355 let amount = amount.min(*self_amount);
356 *self_amount -= amount;
357 (*self_amount == 0, amount)
358 },
359 None => (false, 0),
360 };
361 if remove {
362 self.fungible.remove(&id);
363 }
364 if amount > 0 {
365 taken.subsume(Asset::from((id, amount)).into());
366 }
367 },
368 Asset { fun: NonFungible(instance), id } => {
369 let id_instance = (id, instance);
370 if self.non_fungible.remove(&id_instance) {
371 taken.subsume(id_instance.into())
372 }
373 },
374 }
375 }
376 },
377 }
378 Ok(taken)
379 }
380
381 pub fn saturating_take(&mut self, asset: AssetFilter) -> AssetsInHolding {
387 self.general_take(asset, true)
388 .expect("general_take never results in error when saturating")
389 }
390
391 pub fn try_take(&mut self, mask: AssetFilter) -> Result<AssetsInHolding, TakeError> {
397 self.general_take(mask, false)
398 }
399
400 pub fn checked_sub(mut self, asset: Asset) -> Result<AssetsInHolding, AssetsInHolding> {
403 match asset.fun {
404 Fungible(amount) => {
405 let remove = if let Some(balance) = self.fungible.get_mut(&asset.id) {
406 if *balance >= amount {
407 *balance -= amount;
408 *balance == 0
409 } else {
410 return Err(self)
411 }
412 } else {
413 return Err(self)
414 };
415 if remove {
416 self.fungible.remove(&asset.id);
417 }
418 Ok(self)
419 },
420 NonFungible(instance) =>
421 if self.non_fungible.remove(&(asset.id, instance)) {
422 Ok(self)
423 } else {
424 Err(self)
425 },
426 }
427 }
428
429 pub fn min(&self, mask: &AssetFilter) -> AssetsInHolding {
448 let mut masked = AssetsInHolding::new();
449 let maybe_limit = mask.limit().map(|x| x as usize);
450 if maybe_limit.map_or(false, |l| l == 0) {
451 return masked
452 }
453 match mask {
454 AssetFilter::Wild(All) | AssetFilter::Wild(AllCounted(_)) => {
455 if maybe_limit.map_or(true, |l| self.len() <= l) {
456 return self.clone()
457 } else {
458 for (c, &amount) in self.fungible.iter() {
459 masked.fungible.insert(c.clone(), amount);
460 if maybe_limit.map_or(false, |l| masked.len() >= l) {
461 return masked
462 }
463 }
464 for (c, instance) in self.non_fungible.iter() {
465 masked.non_fungible.insert((c.clone(), *instance));
466 if maybe_limit.map_or(false, |l| masked.len() >= l) {
467 return masked
468 }
469 }
470 }
471 },
472 AssetFilter::Wild(AllOfCounted { fun: WildFungible, id, .. }) |
473 AssetFilter::Wild(AllOf { fun: WildFungible, id }) =>
474 if let Some(&amount) = self.fungible.get(&id) {
475 masked.fungible.insert(id.clone(), amount);
476 },
477 AssetFilter::Wild(AllOfCounted { fun: WildNonFungible, id, .. }) |
478 AssetFilter::Wild(AllOf { fun: WildNonFungible, id }) =>
479 for (c, instance) in self.non_fungible.iter() {
480 if c == id {
481 masked.non_fungible.insert((c.clone(), *instance));
482 if maybe_limit.map_or(false, |l| masked.len() >= l) {
483 return masked
484 }
485 }
486 },
487 AssetFilter::Definite(assets) =>
488 for asset in assets.inner().iter() {
489 match asset {
490 Asset { fun: Fungible(amount), id } => {
491 if let Some(m) = self.fungible.get(id) {
492 masked.subsume((id.clone(), Fungible(*amount.min(m))).into());
493 }
494 },
495 Asset { fun: NonFungible(instance), id } => {
496 let id_instance = (id.clone(), *instance);
497 if self.non_fungible.contains(&id_instance) {
498 masked.subsume(id_instance.into());
499 }
500 },
501 }
502 },
503 }
504 masked
505 }
506}
507
508#[cfg(test)]
509mod tests {
510 use super::*;
511 use alloc::vec;
512 use xcm::latest::prelude::*;
513
514 #[allow(non_snake_case)]
515 fn CF(amount: u128) -> Asset {
517 (Here, amount).into()
518 }
519 #[allow(non_snake_case)]
520 fn CFG(index: u128, amount: u128) -> Asset {
522 (GeneralIndex(index), amount).into()
523 }
524 #[allow(non_snake_case)]
525 fn CFP(amount: u128) -> Asset {
527 (Parent, amount).into()
528 }
529 #[allow(non_snake_case)]
530 fn CFPP(amount: u128) -> Asset {
532 ((Parent, Parent), amount).into()
533 }
534 #[allow(non_snake_case)]
535 fn CNF(instance_id: u8) -> Asset {
537 (Here, [instance_id; 4]).into()
538 }
539
540 fn test_assets() -> AssetsInHolding {
541 let mut assets = AssetsInHolding::new();
542 assets.subsume(CF(300));
543 assets.subsume(CNF(40));
544 assets
545 }
546
547 #[test]
548 fn assets_in_holding_order_works() {
549 let mut assets = AssetsInHolding::new();
551 assets.subsume(CFPP(300));
552 assets.subsume(CFP(200));
553 assets.subsume(CNF(2));
554 assets.subsume(CF(100));
555 assets.subsume(CNF(1));
556 assets.subsume(CFG(10, 400));
557 assets.subsume(CFG(15, 500));
558
559 let mut iter = assets.clone().into_assets_iter();
565 assert_eq!(Some(CF(100)), iter.next());
567 assert_eq!(Some(CFG(10, 400)), iter.next());
569 assert_eq!(Some(CFG(15, 500)), iter.next());
571 assert_eq!(Some(CFP(200)), iter.next());
573 assert_eq!(Some(CFPP(300)), iter.next());
575 assert_eq!(Some(CNF(1)), iter.next());
577 assert_eq!(Some(CNF(2)), iter.next());
579 assert_eq!(None, iter.next());
581
582 let assets_same = assets.clone();
585 assets.subsume_assets(assets_same);
586
587 let mut iter = assets.into_assets_iter();
588 assert_eq!(Some(CF(200)), iter.next());
589 assert_eq!(Some(CFG(10, 800)), iter.next());
590 assert_eq!(Some(CFG(15, 1000)), iter.next());
591 assert_eq!(Some(CFP(400)), iter.next());
592 assert_eq!(Some(CFPP(600)), iter.next());
593 assert_eq!(Some(CNF(1)), iter.next());
594 assert_eq!(Some(CNF(2)), iter.next());
595 assert_eq!(None, iter.next());
596 }
597
598 #[test]
599 fn subsume_assets_equal_length_holdings() {
600 let mut t1 = test_assets();
601 let mut t2 = AssetsInHolding::new();
602 t2.subsume(CF(300));
603 t2.subsume(CNF(50));
604
605 let t1_clone = t1.clone();
606 let mut t2_clone = t2.clone();
607
608 t1.subsume_assets(t2.clone());
611 let mut iter = t1.into_assets_iter();
612 assert_eq!(Some(CF(600)), iter.next());
613 assert_eq!(Some(CNF(40)), iter.next());
614 assert_eq!(Some(CNF(50)), iter.next());
615 assert_eq!(None, iter.next());
616
617 t2_clone.subsume_assets(t1_clone.clone());
620 let mut iter = t2_clone.into_assets_iter();
621 assert_eq!(Some(CF(600)), iter.next());
622 assert_eq!(Some(CNF(40)), iter.next());
623 assert_eq!(Some(CNF(50)), iter.next());
624 assert_eq!(None, iter.next());
625 }
626
627 #[test]
628 fn subsume_assets_different_length_holdings() {
629 let mut t1 = AssetsInHolding::new();
630 t1.subsume(CFP(400));
631 t1.subsume(CFPP(100));
632
633 let mut t2 = AssetsInHolding::new();
634 t2.subsume(CF(100));
635 t2.subsume(CNF(50));
636 t2.subsume(CNF(40));
637 t2.subsume(CFP(100));
638 t2.subsume(CFPP(100));
639
640 let t1_clone = t1.clone();
641 let mut t2_clone = t2.clone();
642
643 t1.subsume_assets(t2);
646 let mut iter = t1.into_assets_iter();
647 assert_eq!(Some(CF(100)), iter.next());
648 assert_eq!(Some(CFP(500)), iter.next());
649 assert_eq!(Some(CFPP(200)), iter.next());
650 assert_eq!(Some(CNF(40)), iter.next());
651 assert_eq!(Some(CNF(50)), iter.next());
652 assert_eq!(None, iter.next());
653
654 t2_clone.subsume_assets(t1_clone);
657 let mut iter = t2_clone.into_assets_iter();
658 assert_eq!(Some(CF(100)), iter.next());
659 assert_eq!(Some(CFP(500)), iter.next());
660 assert_eq!(Some(CFPP(200)), iter.next());
661 assert_eq!(Some(CNF(40)), iter.next());
662 assert_eq!(Some(CNF(50)), iter.next());
663 assert_eq!(None, iter.next());
664 }
665
666 #[test]
667 fn subsume_assets_empty_holding() {
668 let mut t1 = AssetsInHolding::new();
669 let t2 = AssetsInHolding::new();
670 t1.subsume_assets(t2.clone());
671 let mut iter = t1.clone().into_assets_iter();
672 assert_eq!(None, iter.next());
673
674 t1.subsume(CFP(400));
675 t1.subsume(CNF(40));
676 t1.subsume(CFPP(100));
677
678 let t1_clone = t1.clone();
679 let mut t2_clone = t2.clone();
680
681 t1.subsume_assets(t2.clone());
684 let mut iter = t1.into_assets_iter();
685 assert_eq!(Some(CFP(400)), iter.next());
686 assert_eq!(Some(CFPP(100)), iter.next());
687 assert_eq!(Some(CNF(40)), iter.next());
688 assert_eq!(None, iter.next());
689
690 t2_clone.subsume_assets(t1_clone.clone());
693 let mut iter = t2_clone.into_assets_iter();
694 assert_eq!(Some(CFP(400)), iter.next());
695 assert_eq!(Some(CFPP(100)), iter.next());
696 assert_eq!(Some(CNF(40)), iter.next());
697 assert_eq!(None, iter.next());
698 }
699
700 #[test]
701 fn checked_sub_works() {
702 let t = test_assets();
703 let t = t.checked_sub(CF(150)).unwrap();
704 let t = t.checked_sub(CF(151)).unwrap_err();
705 let t = t.checked_sub(CF(150)).unwrap();
706 let t = t.checked_sub(CF(1)).unwrap_err();
707 let t = t.checked_sub(CNF(41)).unwrap_err();
708 let t = t.checked_sub(CNF(40)).unwrap();
709 let t = t.checked_sub(CNF(40)).unwrap_err();
710 assert_eq!(t, AssetsInHolding::new());
711 }
712
713 #[test]
714 fn into_assets_iter_works() {
715 let assets = test_assets();
716 let mut iter = assets.into_assets_iter();
717 assert_eq!(Some(CF(300)), iter.next());
719 assert_eq!(Some(CNF(40)), iter.next());
720 assert_eq!(None, iter.next());
721 }
722
723 #[test]
724 fn assets_into_works() {
725 let mut assets_vec: Vec<Asset> = Vec::new();
726 assets_vec.push(CF(300));
727 assets_vec.push(CNF(40));
728 assets_vec.push(CF(300));
730 assets_vec.push(CNF(40));
731
732 let assets: AssetsInHolding = assets_vec.into();
733 let mut iter = assets.into_assets_iter();
734 assert_eq!(Some(CF(600)), iter.next());
736 assert_eq!(Some(CNF(40)), iter.next());
738 assert_eq!(None, iter.next());
739 }
740
741 #[test]
742 fn min_all_and_none_works() {
743 let assets = test_assets();
744 let none = Assets::new().into();
745 let all = All.into();
746
747 let none_min = assets.min(&none);
748 assert_eq!(None, none_min.assets_iter().next());
749 let all_min = assets.min(&all);
750 assert!(all_min.assets_iter().eq(assets.assets_iter()));
751 }
752
753 #[test]
754 fn min_counted_works() {
755 let mut assets = AssetsInHolding::new();
756 assets.subsume(CNF(40));
757 assets.subsume(CF(3000));
758 assets.subsume(CNF(80));
759 let all = WildAsset::AllCounted(6).into();
760
761 let all = assets.min(&all);
762 let all = all.assets_iter().collect::<Vec<_>>();
763 assert_eq!(all, vec![CF(3000), CNF(40), CNF(80)]);
764 }
765
766 #[test]
767 fn min_all_concrete_works() {
768 let assets = test_assets();
769 let fungible = Wild((Here, WildFungible).into());
770 let non_fungible = Wild((Here, WildNonFungible).into());
771
772 let fungible = assets.min(&fungible);
773 let fungible = fungible.assets_iter().collect::<Vec<_>>();
774 assert_eq!(fungible, vec![CF(300)]);
775 let non_fungible = assets.min(&non_fungible);
776 let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>();
777 assert_eq!(non_fungible, vec![CNF(40)]);
778 }
779
780 #[test]
781 fn min_basic_works() {
782 let assets1 = test_assets();
783
784 let mut assets2 = AssetsInHolding::new();
785 assets2.subsume(CF(600));
787 assets2.subsume(CNF(40));
789 let assets2: Assets = assets2.into();
790
791 let assets_min = assets1.min(&assets2.into());
792 let assets_min = assets_min.into_assets_iter().collect::<Vec<_>>();
793 assert_eq!(assets_min, vec![CF(300), CNF(40)]);
794 }
795
796 #[test]
797 fn saturating_take_all_and_none_works() {
798 let mut assets = test_assets();
799
800 let taken_none = assets.saturating_take(vec![].into());
801 assert_eq!(None, taken_none.assets_iter().next());
802 let taken_all = assets.saturating_take(All.into());
803 assert_eq!(None, assets.assets_iter().next());
805 let all_iter = taken_all.assets_iter();
806 assert!(all_iter.eq(test_assets().assets_iter()));
807 }
808
809 #[test]
810 fn saturating_take_all_concrete_works() {
811 let mut assets = test_assets();
812 let fungible = Wild((Here, WildFungible).into());
813 let non_fungible = Wild((Here, WildNonFungible).into());
814
815 let fungible = assets.saturating_take(fungible);
816 let fungible = fungible.assets_iter().collect::<Vec<_>>();
817 assert_eq!(fungible, vec![CF(300)]);
818 let non_fungible = assets.saturating_take(non_fungible);
819 let non_fungible = non_fungible.assets_iter().collect::<Vec<_>>();
820 assert_eq!(non_fungible, vec![CNF(40)]);
821 }
822
823 #[test]
824 fn saturating_take_basic_works() {
825 let mut assets1 = test_assets();
826
827 let mut assets2 = AssetsInHolding::new();
828 assets2.subsume(CF(600));
830 assets2.subsume(CNF(40));
832 let assets2: Assets = assets2.into();
833
834 let taken = assets1.saturating_take(assets2.into());
835 let taken = taken.into_assets_iter().collect::<Vec<_>>();
836 assert_eq!(taken, vec![CF(300), CNF(40)]);
837 }
838
839 #[test]
840 fn try_take_all_counted_works() {
841 let mut assets = AssetsInHolding::new();
842 assets.subsume(CNF(40));
843 assets.subsume(CF(3000));
844 assets.subsume(CNF(80));
845 let all = assets.try_take(WildAsset::AllCounted(6).into()).unwrap();
846 assert_eq!(Assets::from(all).inner(), &vec![CF(3000), CNF(40), CNF(80)]);
847 }
848
849 #[test]
850 fn try_take_fungibles_counted_works() {
851 let mut assets = AssetsInHolding::new();
852 assets.subsume(CNF(40));
853 assets.subsume(CF(3000));
854 assets.subsume(CNF(80));
855 assert_eq!(Assets::from(assets).inner(), &vec![CF(3000), CNF(40), CNF(80),]);
856 }
857
858 #[test]
859 fn try_take_non_fungibles_counted_works() {
860 let mut assets = AssetsInHolding::new();
861 assets.subsume(CNF(40));
862 assets.subsume(CF(3000));
863 assets.subsume(CNF(80));
864 assert_eq!(Assets::from(assets).inner(), &vec![CF(3000), CNF(40), CNF(80)]);
865 }
866}