How do I check if a slice is sorted?
Assuming a function that accepts a slice of i32, is there an idiomatic Rust way of checking if the slice is sorted?
fn is_sorted(data: &[i32]) -> bool {
// ...
}
Would it be possible to generalize the above method so that it would accept an iterator?
fn is_sorted<I>(iter: I)
where
I: Iterator,
I::Item: Ord,
{
// ...
}
I'd grab pairs of elements and assert they are all in ascending (or descending, depending on what you mean by "sorted") order:
fn is_sorted<T>(data: &[T]) -> bool
where
T: Ord,
{
data.windows(2).all(|w| w[0] <= w[1])
}
fn main() {
assert!(is_sorted::<u8>(&[]));
assert!(is_sorted(&[1]));
assert!(is_sorted(&[1, 2, 3]));
assert!(is_sorted(&[1, 1, 1]));
assert!(!is_sorted(&[1, 3, 2]));
assert!(!is_sorted(&[3, 2, 1]));
}
Ditto for generic iterators:
extern crate itertools; // 0.7.8
use itertools::Itertools;
fn is_sorted<I>(data: I) -> bool
where
I: IntoIterator,
I::Item: Ord + Clone,
{
data.into_iter().tuple_windows().all(|(a, b)| a <= b)
}
fn main() {
assert!(is_sorted(&[] as &[u8]));
assert!(is_sorted(&[1]));
assert!(is_sorted(&[1, 2, 3]));
assert!(is_sorted(&[1, 1, 1]));
assert!(!is_sorted(&[1, 3, 2]));
assert!(!is_sorted(&[3, 2, 1]));
}
See also:
Are there equivalents to slice::chunks/windows for iterators to loop over pairs, triplets etc?
In nightly Rust, there are unstable methods to accomplish this:
slice::is_sorted
slice::is_sorted_by
slice::is_sorted_by_key
Iterator::is_sorted
Iterator::is_sorted_by
Iterator::is_sorted_by_key
It is not necessary to have Clone for an iterator is_sorted implementation. Here is a no-dependency Rust implementation of is_sorted:
fn is_sorted<I>(data: I) -> bool
where
I: IntoIterator,
I::Item: Ord,
{
let mut it = data.into_iter();
match it.next() {
None => true,
Some(first) => it.scan(first, |state, next| {
let cmp = *state <= next;
*state = next;
Some(cmp)
}).all(|b| b),
}
}
One more using try_fold():
pub fn is_sorted<T: IntoIterator>(t: T) -> bool
where
<T as IntoIterator>::Item: std::cmp::PartialOrd,
{
let mut iter = t.into_iter();
if let Some(first) = iter.next() {
iter.try_fold(first, |previous, current| {
if previous > current {
Err(())
} else {
Ok(current)
}
})
.is_ok()
} else {
true
}
}
Related
I have a simple QuadTree. For readability and to help me understand what is happening, It avoids recursion and has a static depth. The QuadTree stores references to the points that are owned by another container.
struct QuadLeaf<'a> {
vec: Vec<&'a (f32,f32)>,
rect: (f32, f32, f32, f32)
}
struct QuadTwig<'a> {
cells: [QuadLeaf<'a>; 4],
}
struct QuadBranch<'a> {
cells: [QuadTwig<'a>; 4],
}
struct QuadTree<'a> {
cells: [QuadBranch<'a>; 4],
}
Constructing and inserting into this tree is relatively simple. The QuadLeaf is constructed with a bounding rect and an empty vec, and has a method that attempts to insert a point. It returns true if the point is within the rect and has been inserted.
impl<'a> QuadLeaf<'a> {
fn new(rect: (f32, f32, f32, f32)) -> Self {
QuadLeaf {vec: Vec::new(),rect}
}
fn insert(&mut self, point: &'a (f32, f32)) -> bool {
if is_point_in_rect(point.0, point.1, self.rect) {
self.vec.push(point);
true
} else {
false
}
}
}
The QuadTwig new function splits the bounding rect into 4 and creates 4 new QuadLeafs . It's insert function attempts to insert into each leaf, short circuiting when it is successful, and returning false if unsuccessful.
impl<'a> QuadTwig<'a> {
fn new(rect: (f32, f32, f32, f32)) -> Self {
let rects = divide_into_4(rect);
QuadTwig {
cells: [
QuadLeaf::new(rects[0]),
QuadLeaf::new(rects[1]),
QuadLeaf::new(rects[2]),
QuadLeaf::new(rects[3])
]
}
}
fn insert(&mut self, point: &'a (f32, f32)) -> bool {
for cell in self.cells.iter_mut() {
if cell.insert(point) {
return true;
}
}
false
}
}
The implementations for QuadBranch and QuadTree are exactly the same, but the new function just constructs the next level down in the tree. This could be refactored later for less code duplication, but for demonstration purposes I will leave it. I also think it does not matter for the context of this question.
Question:
I want to create an Iterator that yields each point in the tree, and the 9 leaves that it is close to (or inside of).
I have managed to create a simpler version, that just yields each point and the leaf it is in:
/// An Iterator that yields each point and the leaf it is in
struct PointAndLeafIterator<'a> {
ptr: &'a QuadTree<'a>,
index: (usize, usize, usize, usize)
}
/// An Iterator that yields each point and the leaf it is in
impl<'a> Iterator for PointAndLeafIterator<'a> {
/// Returns (point, leaf)
type Item = (&'a (f32, f32), Vec<&'a (f32, f32)>);
/// Starts at (0,0,0,0) and ends at (3, 3, 3, num_points_in_leaf)
/// It increases the index by 1 each time, and if it reaches the end of the cell, it moves to the next cell
fn next(&mut self) -> Option<Self::Item> {
let (branch_index, twig_index, leaf_index, point_index) = &mut self.index;
let branch = &self.ptr.cells[*branch_index];
let twig = &branch.cells[*twig_index];
let leaf = &twig.cells[*leaf_index];
let point = leaf.vec.get(*point_index);
//go through all the points in the leaf
if let Some(point) = point {
*point_index += 1;
return Some((point, leaf.vec.clone()));
}
//if we reach the end of the leaf, go to the next leaf
*point_index = 0;
*leaf_index += 1;
if *leaf_index < 4 {
return self.next();
}
//if we reach the end of the twig, go to the next twig
*leaf_index = 0;
*twig_index += 1;
if *twig_index < 4 {
return self.next();
}
//if we reach the end of the branch, go to the next branch
*twig_index = 0;
*branch_index += 1;
if *branch_index < 4 {
return self.next();
}
//if we reach the end of the tree, we are done
None
}
}
This can be used like this:
fn main() {
let points: Vec<(f32, f32)> = vec![
(0.0, 0.0),
(1.0, 1.0),
(31.0,31.0),
(2.0, 2.0),
(3.0, 3.0),
(32.0,32.0),
];
let mut quadtree = QuadTree::new((0.0, 0.0, 40.0, 40.0));
for point in points.iter() {
quadtree.insert(point);
}
for (point, leaf) in quadtree.into_point_and_leaf_iter() {
println!("Point: {:?}", point);
println!("Leaf: {:?}", leaf);
}
}
However the neighbouring version is proving to be much more difficult. How can I write this algorithm?
/// An Iterator that yields each point, the leaf it is in, and the neighbouring leaves
struct PointAndLeafAndNeighboursIterator<'a> {
ptr: &'a QuadTree<'a>,
index: (usize, usize, usize, usize)
}
impl<'a> Iterator for PointAndLeafAndNeighboursIterator<'a> {
///Return the 9 leaves that surround the point
///If there is no leaf in a direction, it will return an empty leaf
type Item = (&'a (f32, f32), [Vec<&'a (f32, f32)>; 9]);
/// Starts at (0,0,0,0) and ends at (3, 3, 3, num_points_in_leaf)
/// It increases the index by 1 each time, and if it reaches the end of the cell, it moves to the next cell
fn next(&mut self) -> Option<Self::Item> {
unimplemented!()
}
}
Here is a Rust playground link to all code in this question.
My implementation.
First I added indexing by leaf indices since the QuadTree struct is basically an 8x8 matrix of leaves.
use std::ops::Index;
#[derive(Clone, Copy, Debug)]
struct QuadLeafId {
x: i8,
y: i8,
}
impl QuadLeafId {
fn new(x: i8, y: i8) -> Self {
Self { x, y }
}
fn level_index(&self, level: usize) -> usize {
(((self.y >> level) % 2) * 2 + ((self.x >> level) % 2)) as usize
}
/// Extract the QuadTwig array index containing this leaf
fn twig_index(&self) -> usize {
self.level_index(0)
}
/// Extract the QuadBranch array index containing this leaf
fn branch_index(&self) -> usize {
self.level_index(1)
}
/// Extract the QuadTree array index containing this leaf
fn tree_index(&self) -> usize {
self.level_index(2)
}
}
impl<'a> Index<QuadLeafId> for QuadTwig<'a> {
type Output = QuadLeaf<'a>;
fn index(&self, index: QuadLeafId) -> &Self::Output {
&self.cells[index.twig_index()]
}
}
impl<'a> Index<QuadLeafId> for QuadBranch<'a> {
type Output = QuadLeaf<'a>;
fn index(&self, index: QuadLeafId) -> &Self::Output {
&self.cells[index.branch_index()][index]
}
}
impl<'a> Index<QuadLeafId> for QuadTree<'a> {
type Output = QuadLeaf<'a>;
fn index(&self, index: QuadLeafId) -> &Self::Output {
&self.cells[index.tree_index()][index]
}
}
Then added iterating over nearby leaves in a QuadTree
impl QuadLeafId {
/// The ids of the 9 nearby leaves
fn near_ids(self) -> impl Iterator<Item = Self> {
(-1..=1).flat_map(move |x| {
(-1..=1).map(move |y| Self {
x: self.x + x,
y: self.y + y,
})
})
}
fn is_valid(&self) -> bool {
0 <= self.y && self.y < 8 && 0 <= self.x && self.x < 8
}
}
impl<'a> QuadTree<'a> {
fn get_leaf(&self, id: QuadLeafId) -> Option<&QuadLeaf<'a>> {
id.is_valid().then(|| &self[id])
}
fn near_leaves(&self, id: QuadLeafId) -> impl Iterator<Item = Option<&QuadLeaf<'a>>> {
id.near_ids().map(|id| self.get_leaf(id))
}
}
Implementing the iterator afterwards is straightforward:
impl QuadLeafId {
fn next_id(mut self) -> Option<Self> {
self.x += 1;
if self.x < 8 {
return Some(self);
}
self.x = 0;
self.y += 1;
(self.y < 8).then_some(self)
}
}
impl<'a> QuadTree<'a> {
fn into_point_and_leaf_and_neighbours_iter(
&'a mut self,
) -> PointAndLeafAndNeighboursIterator<'a> {
PointAndLeafAndNeighboursIterator::<'a> {
ptr: self,
index: Some(QuadLeafId::new(0, 0)),
point_index: 0,
}
}
}
/// An Iterator that yields each point, the leaf it is in, and the neighboring leaves
struct PointAndLeafAndNeighboursIterator<'a> {
ptr: &'a QuadTree<'a>,
index: Option<QuadLeafId>,
point_index: usize,
}
impl<'a> Iterator for PointAndLeafAndNeighboursIterator<'a> {
///Return the 9 leaves that surround the point
///If there is no leaf in a direction, it will return an empty leaf
type Item = (&'a (f32, f32), [Vec<&'a (f32, f32)>; 9]);
/// Starts at (0,0,0,0) and ends at (3, 3, 3, num_points_in_leaf)
/// It increases the index by 1 each time, and if it reaches the end of the cell, it moves to the next cell
fn next(&mut self) -> Option<Self::Item> {
loop {
let ind = self.index?;
let leaf = &self.ptr[ind];
if let Some(point) = leaf.vec.get(self.point_index) {
self.point_index += 1;
let mut iter = self
.ptr
.near_leaves(ind)
.map(|leaf| leaf.map(|leaf| leaf.vec.clone()).unwrap_or_default());
return Some((*point, [(); 9].map(|_| iter.next().unwrap())));
}
self.point_index = 0;
self.index = ind.next_id();
}
}
}
What is the idiomatic way to create static iterable collection of named structs? I have n instances of a struct, where n is known at compile time and is less than 20. I would like to be able to iterate over all the entries and also be able to refer to each entry by a name instead of an index. All the data is known at compile time.
I could use an array or enum, along with hand written constants which map the labels to indexes; but this seems finicky.
fn common_behaviour(x: f64) {
print!("{}", x);
}
const ADD: usize = 0;
const SUBTRACT: usize = 1;
fn main () {
let mut foos: [f64; 2] = [0.0; 2];
foos[ADD] = 4.0;
foos[SUBTRACT] = 2.0;
for foo in &foos {
common_behaviour(*foo);
}
foos[ADD] += 1.0;
foos[SUBTRACT] -= 1.0;
}
Alternatively, I could just pay the performance cost and use a HashMap as the hashing overhead might not actually matter that much, but this seems suboptimal as well.
Perhaps, I could refactor my code to use function pointers instead special casing the different special cases.
fn common_behaviour(x: f64) {
print!("{}", x);
}
fn add(x: f64) -> f64 {
x + 1.0
}
fn subtract(x: f64) -> f64 {
x - 1.0
}
struct Foo {
data: f64,
special: fn(f64) -> f64
}
impl Foo {
fn new(data: f64, special: fn(f64) -> f64) -> Foo {
Foo { data, special }
}
}
fn main() {
let mut foos = [Foo::new(4.0, add), Foo::new(2.0, subtract)];
for foo in &mut foos {
common_behaviour(foo.data);
foo.data = (foo.special)(foo.data);
}
}
What is most idiomatic way to handle this situation?
Looking at:
fn main() {
let mut foos = [Foo::new(4.0, add), Foo::new(2.0, subtract)];
for foo in &mut foos {
common_behaviour(foo.data);
foo.data = (foo.special)(foo.data);
}
}
I see a Command Pattern struggling to emerge, and Rust is great at expressing this pattern, thanks to enum:
enum Foo {
Add(f64),
Sub(f64),
}
impl Foo {
fn apply(&mut self) {
match self {
Foo::Add(x) => {
Self::common(*x);
*x += 1.0;
},
Foo::Sub(x) => {
Self::common(*x);
*x -= 1.0;
},
}
}
fn common(x: f64) {
print!("{}", x);
}
}
And your example becomes:
fn main() {
let mut foos = [Foo::Add(4.0), Foo::Sub(2.0)];
for foo in &mut foos {
foo.apply();
}
}
What would be the easiest way to achieve this?
enum E {
A,
B,
C,
}
// Should return "A" for 0, "B" for 1 and "C" for 2
fn convert(i: u32) -> str {
// ???
}
You cannot return a str, but you can return a &str. Combine ideas from How do I match enum values with an integer? and Get enum as string:
#[macro_use]
extern crate strum_macros;
extern crate strum;
use strum::IntoEnumIterator;
#[derive(EnumIter, AsRefStr)]
enum E {
A,
B,
C,
}
fn main() {
let e = E::iter().nth(2);
assert_eq!(e.as_ref().map(|e| e.as_ref()), Some("C"));
}
It was necessary to add the #[derive(Debug)] attribute and define an implementation on the enum:
#[derive(Debug)]
#[derive(Copy, Clone)]
enum E {
A,
B,
C,
}
impl E {
fn from(t: u8) -> E {
assert(t<=enum_to_int(E::C), "Enum range check failed!");
let el: E = unsafe { std::mem::transmute(t) };
return el;
}
fn to_string(&self) -> String {
return format!("{:?}", self);
}
fn string_from_int(t: u8) -> String {
return E::from(t).to_string();
}
}
fn enum_to_int(el: &E) -> u8 {
*el as u8
}
It can then by used like this:
fn main() {
let s = E::string_from_int(3 as u8);
println!("{}", s);
}
Can I write a Rust for loop equivalent to this C code:
for(int i = 2; i <= 128; i=i*i){
//do something
}
I'm only seeing things like
for i in 0..128 { /* do something */ }
or
let v = vec![0, 1, 2, /* ... */ ];
for i in v.iter() { /* do something */ }
Should I just use a while loop?
You can always create a custom iterator that does whatever unique sequence you need:
struct Doubling {
current: u64,
max: u64,
}
impl Iterator for Doubling {
type Item = u64;
fn next(&mut self) -> Option<Self::Item> {
if self.current > self.max {
None
} else {
let v = Some(self.current);
self.current *= 2;
v
}
}
}
fn main() {
let iter = Doubling { current: 2, max: 128 };
let values: Vec<_> = iter.collect();
println!("{:?}", values);
}
It's important to recognize that this logic (like the original C!) has nasty edge cases when the value is doubled beyond the size of the type.
In this particular case, you can also recognize that you have an exponential series:
fn main() {
let iter = (1..8).map(|p| 2i32.pow(p));
let values: Vec<_> = iter.collect();
println!("{:?}", values);
}
If you want to get really experimental, check out Lazy sequence generation in Rust. Adapted here:
#![feature(generators, generator_trait, conservative_impl_trait)]
use std::ops::{Generator, GeneratorState};
fn doubling(mut start: u64, max: u64) -> impl Iterator<Item = u64> {
GeneratorIteratorAdapter(move || {
while start <= max {
yield start;
start *= 2;
}
})
}
fn main() {
let iter = doubling(2, 128);
let sum: Vec<_> = iter.collect();
println!("{:?}", sum);
}
/* copy-pasta */
struct GeneratorIteratorAdapter<G>(G);
impl<G> Iterator for GeneratorIteratorAdapter<G>
where
G: Generator<Return = ()>,
{
type Item = G::Yield;
fn next(&mut self) -> Option<Self::Item> {
match self.0.resume() {
GeneratorState::Yielded(x) => Some(x),
GeneratorState::Complete(_) => None,
}
}
}
can I write a for loop equivalent to this C code:
That specifically, yes:
extern crate itertools;
for i in itertools::iterate(2, |&i| i*i).take_while(|&i| i <= 128) {
// do something
}
But in general, no. There is no single, direct equivalent to all possible uses of C's for loop. If there's no way to write it using iterators then yes, you need to use a more general loop form:
{
let mut i = 2;
while i <= 128 {
// do something
i = i*i;
}
}
Can I achieve something similar to boost::math::tools::promote_args in Rust? See also Idiomatic C++11 type promotion
To be more specific: is it possible to calculate the return type of a function or trait method based on its arguments and ensure, that the return type has the same type as one of the arguments?
Consider the following case. I have two structs:
#[derive(Debug, Clone, Copy)]
struct MySimpleType(f64);
#[derive(Debug, Clone, Copy)]
struct MyComplexType(f64, f64);
where MySimpleType can be promoted to MyComplexType via the From trait.
impl From<MySimpleType> for MyComplexType {
fn from(src: MySimpleType) -> MyComplexType {
let MySimpleType(x1) = src;
MyComplexType(x1, 0.0)
}
}
I want to write a function that takes two arguments of types MySimpleType or MyComplexType and return a value of type MySimpleType if all arguments are typed as MySimpleType, otherwise the function should return a value of type MyComplexType. Assuming I have implemented Add<Output=Self> for both types I could do something like this:
trait Foo<S, T> {
fn foo(s: S, t: T) -> Self;
}
impl<S, T, O> Foo<S, T> for O
where O: From<S> + From<T> + Add<Output = Self>
{
fn foo(s: S, t: T) -> Self {
let s: O = From::from(s);
let t: O = From::from(t);
s + t
}
}
but then the compiler doesn't know that O should be either S or T and I have to annotate most method calls.
My second attempt is to use a slightly different trait and write two implementations:
trait Foo<S, T> {
fn foo(s: S, t: T) -> Self;
}
impl Foo<MySimpleType, MySimpleType> for MySimpleType {
fn foo(s: MySimpleType, t: MySimpleType) -> Self {
s + t
}
}
impl<S, T> Foo<S, T> for MyComplexType
where MyComplexType: From<S> + From<T>
{
fn foo(s: S, t: T) -> Self {
let s: MyComplexType = From::from(s);
let t: MyComplexType = From::from(t);
s + t
}
}
but again, the compiler isn't able to figure the return type of
Foo::foo(MySimpleType(1.0), MySimpleType(1.0))
The third attempt is something similar to the std::ops::{Add, Mul, ...}. Use an associated type and write a specific implementation for each possible combination of argument types
trait Foo<T> {
type Output;
fn foo(self, t: T) -> Self::Output;
}
impl<T: Add<Output=T>> Foo<T> for T {
type Output = Self;
fn foo(self, t: T) -> Self::Output {
self + t
}
}
impl Foo<MySimpleType> for MyComplexType {
type Output = Self;
fn foo(self, t: MySimpleType) -> Self::Output {
let t: Self = From::from(t);
self + t
}
}
impl Foo<MyComplexType> for MySimpleType {
type Output = MyComplexType;
fn foo(self, t: MyComplexType) -> Self::Output {
let s: MyComplexType = From::from(self);
s + t
}
}
This seems to be the best solution until one needs a function with n arguments. Because then one has to write 2^n - n + 1 impl statements. Of course, this gets even worse if more then two types being considered.
===
Edit:
In my code I've multiple nested function calls and I want to avoid non necessary type promotion, since the evaluation of the functions for the simple type is cheap and expensive for the complex type. By using #MatthieuM. 's proposed solution, this is not achieved. Please consider the following example
#![feature(core_intrinsics)]
use std::ops::Add;
trait Promote<Target> {
fn promote(self) -> Target;
}
impl<T> Promote<T> for T {
fn promote(self) -> T {
self
}
}
impl Promote<u64> for u32 {
fn promote(self) -> u64 {
self as u64
}
}
fn foo<Result, Left, Right>(left: Left, right: Right) -> Result
where Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
println!("============\nFoo called");
println!("Left: {}", unsafe { std::intrinsics::type_name::<Left>() });
println!("Right: {}",
unsafe { std::intrinsics::type_name::<Right>() });
println!("Result: {}",
unsafe { std::intrinsics::type_name::<Result>() });
left.promote() + right.promote()
}
fn bar<Result, Left, Right>(left: Left, right: Right) -> Result
where Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
left.promote() + right.promote()
}
fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
where A: Promote<Result>,
B: Promote<Result>,
C: Promote<Result>,
D: Promote<Result>,
Result: Add<Output = Result>
{
let lhs = foo(a, b).promote();
let rhs = bar(c, d).promote();
lhs + rhs
}
fn main() {
let one = baz(1u32, 1u32, 1u64, 1u32);
println!("{}", one);
}
I would expect the simplest way to implement promotion is to create a Promote trait:
trait Promote<Target> {
fn promote(self) -> Target;
}
impl<T> Promote<T> for T {
fn promote(self) -> T { self }
}
Note: I provide a blanket implementation as all types can be promoted to themselves.
Using associated types is NOT an option here, because a single type can be promoted to multiple types; thus we just use a regular type parameter.
Using this, a simple example is:
impl Promote<u64> for u32 {
fn promote(self) -> u64 { self as u64 }
}
fn add<Result, Left, Right>(left: Left, right: Right) -> Result
where
Left: Promote<Result>,
Right: Promote<Result>,
Result: Add<Output = Result>
{
left.promote() + right.promote()
}
fn main() {
let one: u32 = add(1u32, 1u32);
let two: u64 = add(1u32, 2u64);
let three: u64 = add(2u64, 1u32);
let four: u64 = add(2u64, 2u64);
println!("{} {} {} {}", one, two, three, four);
}
The only issue is that in the case of two u32 arguments, the result type must be specified otherwise the compiler cannot choose between which possible Promote implementation to use: Promote<u32> or Promote<u64>.
I am not sure if this is an issue in practice, however, since at some point you should have a concrete type to anchor type inference. For example:
fn main() {
let v = vec![add(1u32, 1u32), add(1u32, 2u64)];
println!("{:?}", v);
}
compiles without type hint, because add(1u32, 2u64) can only be u64, and therefore since a Vec is a homogeneous collection, add(1u32, 1u32) has to return a u64 here.
As you experienced, though, sometimes you need the ability to direct the result beyond what type inference can handle. It's fine, you just need another trait for it:
trait PromoteTarget {
type Output;
}
impl<T> PromoteTarget for (T, T) {
type Output = T;
}
And then a little implementation:
impl PromoteTarget for (u32, u64) {
type Output = u64;
}
impl PromoteTarget for (u64, u32) {
type Output = u64;
}
With that out of the way, we can rewrite baz signature to correctly account for all intermediate types. Unfortunately I don't know any way to introduce aliases in a where clause, so brace yourself:
fn baz<Result, A, B, C, D>(a: A, b: B, c: C, d: D) -> Result
where
A: Promote<<(A, B) as PromoteTarget>::Output>,
B: Promote<<(A, B) as PromoteTarget>::Output>,
C: Promote<<(C, D) as PromoteTarget>::Output>,
D: Promote<<(C, D) as PromoteTarget>::Output>,
(A, B): PromoteTarget,
(C, D): PromoteTarget,
<(A, B) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(A, B) as PromoteTarget>::Output>,
<(C, D) as PromoteTarget>::Output: Promote<Result> + Add<Output = <(C, D) as PromoteTarget>::Output>,
Result: Add<Output = Result>
{
let lhs = foo(a, b).promote();
let rhs = bar(c, d).promote();
lhs + rhs
}
Link to the playground here, so you can check the result:
============
Foo called
Left: u32
Right: u32
Result: u32
4