1

I'm trying to make a trait to work for all numeric integer types. I though that limiting it for num_traits::Num would force it to be applicable only to u8, u16, etc so -1 would always work.

pub fn divide_round_up<T: num_traits::Num>(value: T, divisor: T) -> T {
    return (value + divisor - 1) / divisor;
}

I get


   |
19 | pub fn divide_round_up<T: num_traits::Num>(value: T, divisor: T) -> T {
   |                        - this type parameter
20 |     return (value + divisor - 1) / divisor;
   |                               ^ expected type parameter `T`, found integer

What should I do here?

By the way, isn't there a way of doing this without the crate?

Guerlando OCs
  • 1,886
  • 9
  • 61
  • 150
  • 2
    `Num: One`, so you should be able to use [`::one()`](https://docs.rs/num-traits/0.2.14/num_traits/identities/trait.One.html#tymethod.one) (`T::one()` also should work for brevity) to get the multiplicative identity 1. – EvilTak Nov 09 '21 at 22:15
  • @EvilTak what if I want to add or subtract 2 or 3? – Guerlando OCs Nov 10 '21 at 00:00
  • @GuerlandoOCs you add a bunch of ones together? `num_traits::Num` explicitely documents that it only knows about zero and one. Alternatively, you add a constraint on [`NumCast`](https://docs.rs/num/0.4.0/num/trait.NumCast.html) which lets you convert from an existing value. However it *might* be less efficient as there's more work to do to understand that the expressions are constant, whereas `One::one()` implementations are really simple and so not hard to inline and constant-fold. – Masklinn Nov 10 '21 at 06:41
  • *what if I want to add or subtract 2 or 3?* - You can add `T: TryFrom` and use `T::try_from(2).unwrap()` and `T::try_from(3).unwrap()`. (The unwraps will be optimized away by the compiler.) You need `try_from` in order to allow `T` to be `i8`, which is not `From`. If you don't need to support `i8`, you can go with the simpler `T: From` and produce 2 as `T::from(2)`. – user4815162342 Nov 10 '21 at 08:24
  • 1
    This looks duplicate with [this](https://stackoverflow.com/questions/50767912/how-do-i-use-floating-point-number-literals-when-using-generic-types) and [this](https://stackoverflow.com/questions/28565440/how-do-i-use-integer-number-literals-when-using-generic-types). See how it works at [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=7cc37cd4506c5a6970ceaa1e96bb8aa9). – Joe_Jingyu Nov 10 '21 at 10:01

1 Answers1

1

You can bind your trait to use num_traits::identities::One:

use num_traits; // 0.2.14

pub fn divide_round_up<T: num_traits::Num + num_traits::identities::One + Copy>(
    value: T,
    divisor: T,
) -> T {
    return (value + divisor - T::one()) / divisor;
}

Playground

Netwave
  • 40,134
  • 6
  • 50
  • 93
  • `Num: One`, so you [don't even need](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=819877eb2e64a36e41d267ce1614ef18) the additional bound. – EvilTak Nov 13 '21 at 00:32