rusttraitsiterator-traits

Function that accepts any indexable data type as an argument


I am trying to make a function that can take any class that accepts the [] operator. I would like it to be able to accept:

  1. Arrays either by reference or by value

  2. Vectors or any other container that can be indexed

By some experimenting I found that I also need some other traits like PartialOrd, PartialEq. I also need to find out how many objects are in the container.

Here is my code:

use std::ops::Index;
use std::iter::ExactSizeIterator;
use std::cmp::PartialEq;

pub fn find<'a, I>(input: I, key: <I as std::ops::Index<u32>>::Output) -> Option<u32>
where
    I: Index<u32> + ExactSizeIterator,
    <I as std::ops::Index<u32>>::Output: PartialEq + std::marker::Sized + std::cmp::PartialOrd,
{
    if input.len() == 0 {
        return None;
    }
    if key < input[0] || key > input[(input.len() - 1) as u32] {
        return None;
    }
    let mut index: u32 = (input.len() - 1) as u32;
    loop {
        if key < input[index] {
            index /= 2;
            continue;
        } else if input[index] < key && input[index + 1] > key {
            return None;
        } else if key > input[index] {
            index += index / 2;
            continue;
        } else if input[index] == key {
            return Some(index);
        } else {
            return None;
        }
    }
}

fn main() {
    assert_eq!(find(&[1, 2], 2), Some(1));
    assert_eq!(find([1, 2], 2), Some(1));
    assert_eq!(find(vec![1, 2], 2), Some(1));
}

It produces these errors:

error[E0277]: the trait bound `&[{integer}; 2]: std::ops::Index<u32>` is not satisfied
  --> src/main.rs:36:16
   |
36 |     assert_eq!(find(&[1, 2], 2), Some(1));
   |                ^^^^ the type `&[{integer}; 2]` cannot be indexed by `u32`
   |
   = help: the trait `std::ops::Index<u32>` is not implemented for `&[{integer}; 2]`
   = note: required by `find`

error[E0277]: the trait bound `&[{integer}; 2]: std::iter::ExactSizeIterator` is not satisfied
  --> src/main.rs:36:16
   |
36 |     assert_eq!(find(&[1, 2], 2), Some(1));
   |                ^^^^ the trait `std::iter::ExactSizeIterator` is not implemented for `&[{integer}; 2]`
   |
   = note: required by `find`

error[E0277]: the trait bound `[{integer}; 2]: std::ops::Index<u32>` is not satisfied
  --> src/main.rs:37:16
   |
37 |     assert_eq!(find([1, 2], 2), Some(1));
   |                ^^^^ the type `[{integer}; 2]` cannot be indexed by `u32`
   |
   = help: the trait `std::ops::Index<u32>` is not implemented for `[{integer}; 2]`
   = note: required by `find`

error[E0277]: the trait bound `[{integer}; 2]: std::iter::ExactSizeIterator` is not satisfied
  --> src/main.rs:37:16
   |
37 |     assert_eq!(find([1, 2], 2), Some(1));
   |                ^^^^ the trait `std::iter::ExactSizeIterator` is not implemented for `[{integer}; 2]`
   |
   = note: required by `find`

error[E0277]: the trait bound `std::vec::Vec<{integer}>: std::ops::Index<u32>` is not satisfied
  --> src/main.rs:38:16
   |
38 |     assert_eq!(find(vec![1, 2], 2), Some(1));
   |                ^^^^ the type `std::vec::Vec<{integer}>` cannot be indexed by `u32`
   |
   = help: the trait `std::ops::Index<u32>` is not implemented for `std::vec::Vec<{integer}>`
   = note: required by `find`

error[E0277]: the trait bound `std::vec::Vec<{integer}>: std::iter::ExactSizeIterator` is not satisfied
  --> src/main.rs:38:16
   |
38 |     assert_eq!(find(vec![1, 2], 2), Some(1));
   |                ^^^^ the trait `std::iter::ExactSizeIterator` is not implemented for `std::vec::Vec<{integer}>`
   |
   = note: required by `find`

Solution

  • I found a way to implement it but with some limitations.

    pub struct Validator {
        data: Vec<i32>,
    }
    impl<'a> From<&'a [i32; 2]> for Validator {
        fn from(input: &'a [i32; 2]) -> Self {
            Validator {
                data: input.iter().map(|c| *c).collect(),
            }
        }
    }
    impl From<[i32; 2]> for Validator {
        fn from(input: [i32; 2]) -> Self {
            Validator {
                data: input.iter().map(|c| *c).collect(),
            }
        }
    }
    impl From<Vec<i32>> for Validator {
        fn from(input: Vec<i32>) -> Self {
            Validator { data: input }
        }
    }
    
    pub fn find<T>(input: T, key: i32) -> Option<usize>
    where
        T: std::convert::Into<Validator>,
        Validator: std::convert::From<T>,
    {
        let input: Vec<i32> = input.into().data;
    
        if input.len() == 0 {
            return None;
        }
        if key < input[0] || key > input[(input.len() - 1)] {
            return None;
        }
        let mut index = input.len() - 1;
        loop {
            if key < input[index] {
                index /= 2;
                continue;
            } else if input[index] < key && input[index + 1] > key {
                return None;
            } else if key > input[index] {
                index += index / 2;
                continue;
            } else if input[index] == key {
                return Some(index);
            } else {
                return None;
            }
        }
    }
    
    fn main() {
        assert_eq!(find(&[1, 2], 2), Some(1));
        assert_eq!(find([1, 2], 2), Some(1));
        assert_eq!(find(vec![1, 2], 2), Some(1));
    }
    

    If you need a function that accepts an array of 3 or more numbers you will have to implement it for each number of elements. You can add support for more structs like VecDeque or custom ones by implementing the Into trait for the validator struct and the type you want to support.