-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Attempt to remove the where
bounds in arithmetic.
#7933
Conversation
@@ -37,13 +38,17 @@ pub trait PerThing: | |||
Sized + Saturating + Copy + Default + Eq + PartialEq + Ord + PartialOrd + Bounded + fmt::Debug | |||
{ | |||
/// The data type used to build this per-thingy. | |||
type Inner: BaseArithmetic + Unsigned + Copy + fmt::Debug; | |||
type Inner: BaseArithmetic + Unsigned + Copy + Into<u128> + fmt::Debug; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TLDR ^^^^^^^^^^^^^^^^^^^^^^
I think this is because: although |
TLDR: we could change All this is because But actually if diff --git a/primitives/arithmetic/src/per_things.rs b/primitives/arithmetic/src/per_things.rs
index c6a31a0ff..9304ff59f 100644
--- a/primitives/arithmetic/src/per_things.rs
+++ b/primitives/arithmetic/src/per_things.rs
@@ -362,7 +362,7 @@ macro_rules! implement_per_thing {
}
fn from_rational_approximation<N>(p: N, q: N) -> Self
- where N: Clone + Ord + From<Self::Inner> + TryInto<Self::Inner> + TryInto<Self::Upper>
+ where N: Clone + Ord + TryFrom<Self::Inner> + TryInto<Self::Inner> + TryInto<Self::Upper>
+ ops::Div<N, Output=N> + ops::Rem<N, Output=N> + ops::Add<N, Output=N> + Unsigned
{
let div_ceil = |x: N, f: N| -> N {
@@ -379,7 +379,23 @@ macro_rules! implement_per_thing {
// p should not be bigger than q.
let p: N = p.min(q.clone());
- let factor: N = div_ceil(q.clone(), $max.into()).max((1 as Self::Inner).into());
+ let acc: N = if let Ok(acc) = $max.try_into() {
+ acc
+ } else {
+ // $max doesn't fit into `N` arithmetic,
+ // thus $max is strictly more than `N::max_value()`,
+ // thus `N::max_value()` is strictly less than $max,
+ // but p and q are less than `N::max_value()`,
+ // thus p and q are less than $max,
+ // thus p * $max fits into `Upper` (Upper must be able to compute `$max^2`)
+ // and q fits into `Inner`
+ let part =
+ Self::Inner::try_from(p).expect("..") as $upper_type
+ * $max as $upper_type
+ / q as $upper_type;
+ return $name(part as Self::Inner)
+ };
+ let factor: N = div_ceil(q.clone(), acc).max((1 as Self::Inner).into());
// q cannot overflow: (q / (q/$max)) < $max. p < q hence p also cannot overflow.
let q_reduce: $type = (q.clone() / factor.clone()) EDIT: thinking of it again it might be wrong. Because then it allows ppl to use stuff like |
primitives/npos-elections/src/lib.rs
Outdated
}) | ||
.collect::<Vec<_>>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this formatting cant be right
bot merge |
Waiting for commit status. |
Head SHA changed; merge aborted. |
bot merge |
Waiting for commit status. |
Needed for #7929
So far, these
where
clauses have been haunting me everywhere up to the runtime. The reason for their existence is the use of<P: PerThing>
, which means that we don't initially know what is the typeP::Inner
and if it meets all the requirements of other functions (likefrom_rational_approximation
).So far, I have let this be, we need generic
P
in some places.During #7929, I was quite annoyed by this as the where clause literally propagates to almost every single file and function of staking, if you are to make
OffchainAccuracy
generic.Note that we already tolerate and accept this in #7909 as well, but there it is cleaner because everything is wrapper in
impl Pallet
.So I tried to just remove this where clause from the source, which is this PR. In essence, the only main assumption added is that
type Inner
is alwaysInto<u128>
. This can easily hold as long as we keep our per-things within the standard primitive types (note: unsigned types are already not allowed, so you haveu8 -> u128
left). But this would disallow using per-things with higher accuracy levels such as U256 etc.I had to shuffle a bit of
From<U> for T
intoInto<T> for U
, which to this moment still confuses me, but seemingly it was necessary since rustc does not assume it automatically. At first, I really expected just addingtype Inner: Into<u128>
but it is not.