1use super::*;
21use core::{
22 marker::PhantomData,
23 ops::{Div, Rem},
24};
25
26#[derive(
30 CloneNoBound, EqNoBound, PartialEqNoBound, Encode, Decode, DebugNoBound, TypeInfo, MaxEncodedLen,
31)]
32#[scale_info(skip_type_params(MaxEntries))]
33pub struct Bitfield<MaxEntries: Get<u32>>(pub BoundedVec<u16, BitfieldLenOf<MaxEntries>>);
34
35pub type BitfieldLenOf<MaxEntries> = ConstDivCeil<MaxEntries, ConstU32<16>, u32, u32>;
37
38pub struct ConstDivCeil<Dividend, Divisor, R, T>(pub PhantomData<(Dividend, Divisor, R, T)>);
40
41impl<Dividend: Get<T>, Divisor: Get<T>, R: AtLeast32BitUnsigned, T: Into<R>> Get<R>
42 for ConstDivCeil<Dividend, Divisor, R, T>
43where
44 R: Div + Rem + Zero + One + Copy,
45{
46 fn get() -> R {
47 let dividend: R = Dividend::get().into();
48 let divisor: R = Divisor::get().into();
49
50 let v = dividend / divisor;
51 let remainder = dividend % divisor;
52
53 if remainder.is_zero() {
54 v
55 } else {
56 v + One::one()
57 }
58 }
59}
60
61impl<MaxEntries: Get<u32>> Default for Bitfield<MaxEntries> {
62 fn default() -> Self {
63 Self(
64 vec![0u16; BitfieldLenOf::<MaxEntries>::get() as usize]
65 .try_into()
66 .expect("Bitfield construction checked in integrity test; qed."),
67 )
68 }
69}
70
71impl<MaxEntries: Get<u32>> Bitfield<MaxEntries> {
72 pub fn set_if_not_set(&mut self, index: usize) -> Result<(), ()> {
74 let word_index = index / 16;
75 let bit_index = index % 16;
76
77 let word = self.0.get_mut(word_index).ok_or(())?;
78 if (*word & (1u16 << bit_index)) == 0 {
79 *word |= 1u16 << bit_index;
80 Ok(())
81 } else {
82 Err(())
83 }
84 }
85
86 pub fn with_bits(mut self, indices: impl IntoIterator<Item = usize>) -> Result<Self, ()> {
90 for index in indices {
91 self.set_if_not_set(index)?;
92 }
93 Ok(self)
94 }
95
96 pub fn count_ones(&self) -> u32 {
98 self.0.iter().cloned().map(u16::count_ones).sum()
99 }
100}
101
102#[derive(
109 Clone,
110 Eq,
111 PartialEq,
112 Encode,
113 Decode,
114 Default,
115 Debug,
116 TypeInfo,
117 MaxEncodedLen,
118 DecodeWithMemTracking,
119)]
120pub struct IdentifiedConsideration<AccountId, Footprint, C> {
121 pub depositor: AccountId,
125
126 pub ticket: Option<C>,
128
129 #[doc(hidden)]
130 pub _phantom: PhantomData<Footprint>,
131}
132
133impl<AccountId: Clone + Eq, Footprint, C: Consideration<AccountId, Footprint>>
134 IdentifiedConsideration<AccountId, Footprint, C>
135{
136 pub fn new(
138 depositor: &AccountId,
139 fp: impl Into<Option<Footprint>>,
140 ) -> Result<Self, DispatchError> {
141 let ticket = if let Some(fp) = fp.into() {
142 Some(Consideration::<AccountId, Footprint>::new(depositor, fp)?)
143 } else {
144 None
145 };
146
147 Ok(Self { depositor: depositor.clone(), ticket, _phantom: Default::default() })
148 }
149
150 pub fn update(
152 self,
153 new_depositor: &AccountId,
154 new_fp: impl Into<Option<Footprint>>,
155 ) -> Result<Self, DispatchError> {
156 let fp = new_fp.into();
157 if let Some(ticket) = self.ticket {
158 ticket.drop(&self.depositor)?;
159 }
160
161 let ticket = if let Some(fp) = fp {
162 Some(Consideration::<AccountId, Footprint>::new(&new_depositor, fp)?)
163 } else {
164 None
165 };
166 Ok(Self { depositor: new_depositor.clone(), ticket, _phantom: Default::default() })
167 }
168
169 pub fn try_drop(self) -> Result<(), DispatchError> {
171 if let Some(ticket) = self.ticket {
172 ticket.drop(&self.depositor)?;
173 }
174 Ok(())
175 }
176}