[SOLVED] Need help with slice

#1

Hi,
I’m a Rust beginner, and I need help to work with slice. In my exemple I would like to make a func wich XOR each element of an array.

fn xor(tab1:[usize;4],tab2:[usize;4])->[usize;4]{
    let mut new_tab:[usize;4]=[0,0,0,0];
    for n in 0..=3{
        new_tab[n]=tab1[n]^tab2[n];
    }
    return new_tab;
}

fn main{
let mut key:[usize;32] = [0xc6 ,0x6a ,0xa6 ,0x12 ,0x4a ,0xba ,0x4d ,0x04 ,0x4a ,
    0x22 ,0x03 ,0x54 ,0x5b ,0x28 ,0x0e ,0x63 ,0xea ,0x79 ,
    0x79 ,0x20 ,0xc8 ,0x71 ,0x44 ,0x7d ,0x46 ,0x62 ,0x5f ,
    0x51 ,0x85 ,0xc1 ,0x3b, 0xcb];
for i in SimpleStepRange(12,0,-4){
            let slice1=&key[i..=i+4];
            let slice2=&key[i-4..=i];
            key[i..i+4]=xor(slice1,slice2);
     }
}

But I have this kind of error :

slice indices are of type `usize` or ranges of `usize`

I’ve try a lot of think C like or Python like but no one work. So how could I work with sub array in Rust ? please.

Thank a lot for any help
cyms

0 Likes

#2

The code you pasted is missing some parts, but from the error it sounds like the problem is that SimpleStepRange returns a iterator whose items are some numeric type other than usize. Try changing its Item type to usize. Or if that is not possible, try casting each item to usize:

     for i in SimpleStepRange(12,0,-4){
            let i = i as usize;
            // ...
     }
4 Likes

#3

Hi mbrubeck, thank a lot for the reply. Yep there is the missing part of my code.

struct SimpleStepRange(isize, isize, isize);  // start, end, and step

impl Iterator for SimpleStepRange {
     type Item = isize;

    #[inline]
    fn next(&mut self) -> Option<isize> {
        if self.0 > self.1 {
            let v = self.0;
            self.0 = v + self.2;
            Some(v)
        } else {
            None
       }
    }
}

Your solution resolve my first problem, thanks :). Has I understand slice, it’s a pointer to a part of an array. But I don’t know how to send it in function and how can I save the return of this function in a slice. If we take my previous example :

fn xor(tab1:[usize;4],tab2:[usize;4])->[usize;4]{
let mut new_tab:[usize;4]=[0,0,0,0];
for n in 0..=3{
    new_tab[n]=tab1[n]^tab2[n];
}
return new_tab;
}

fn main{
    let mut key:[usize;32] = [0xc6 ,0x6a ,0xa6 ,0x12 ,0x4a ,0xba ,0x4d ,0x04 ,0x4a ,
    0x22 ,0x03 ,0x54 ,0x5b ,0x28 ,0x0e ,0x63 ,0xea ,0x79 ,
    0x79 ,0x20 ,0xc8 ,0x71 ,0x44 ,0x7d ,0x46 ,0x62 ,0x5f ,
    0x51 ,0x85 ,0xc1 ,0x3b, 0xcb];
    for i in SimpleStepRange(12,0,-4){
        let j = i as usize;
        let slice1=&key[j..=j+4];
        let slice2=&key[j-4..=j];
        key[j..j+4]=xor(slice1,slice2);
     }
}

In this example I want to send 2 parts of 4 items of my array to my func XOR, and return the xored version in my initial array. But I don’t find how can I do that. Any advice ?

I have try this kind of declaration :
fn xor(tab1: &mut [usize],tab2:&mut [usize])->[usize;4]
let slice1=&mut old_state[j…=j+4];
But it doesn’t work, I don’t think I’m understanding what I’m doing here.

Thank a lot for any help
cyms

0 Likes

#4

This requires a Nightly compiler. Probably this misses or misunderstands part of the semantics you meant to give to your code, and it gives a run-time error, but it could give you some help to go forward:

#![feature(try_from)]
use std::convert::TryInto;

const N: usize = 4;
type T = usize;
type ArrN = [T; N];

fn arrn_xor(arr1: &ArrN, arr2: &ArrN, result: &mut ArrN) {
    for (r, (&a1, &a2)) in result.iter_mut().zip(arr1.iter().zip(arr2)) {
        *r = a1 ^ a2;
    }
}

fn main() {
    let mut data: [T; 32] = [
        0xc6, 0x6a, 0xa6, 0x12, 0x4a, 0xba, 0x4d, 0x04, 0x4a, 0x22, 0x03,
        0x54, 0x5b, 0x28, 0x0e, 0x63, 0xea, 0x79, 0x79, 0x20, 0xc8, 0x71,
        0x44, 0x7d, 0x46, 0x62, 0x5f, 0x51, 0x85, 0xc1, 0x3b, 0xcb,
    ];

    for i in (0 ..= 12).rev().step_by(N) { // 12 8 4 0
        let a = &data[i ..= i + N].try_into().unwrap();
        let b = &data[i - N ..= i].try_into().unwrap();
        arrn_xor(a, b, &mut data[i .. i + N].try_into().unwrap());
    }
}

Unfortunately currently the Nightly Rust language lacks good enough slice -> array conversions.

Rustc compiles the arrn_xor function well enough, removing tons of abstractions:

arrn_xor:
    vmovups ymm0, ymmword ptr [rsi]
    vxorps  ymm0, ymm0, ymmword ptr [rdi]
    vmovups ymmword ptr [rdx], ymm0
    vzeroupper
    ret
0 Likes

#5

Thank a lot for the reply, I think I have understand what your code do, but when I want to launch it, I have this kind of error :

0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
         at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
1: std::sys_common::backtrace::_print
         at src/libstd/sys_common/backtrace.rs:70
2: std::panicking::default_hook::{{closure}}
         at src/libstd/sys_common/backtrace.rs:58
         at src/libstd/panicking.rs:200
3: std::panicking::default_hook
         at src/libstd/panicking.rs:215
4: std::panicking::rust_panic_with_hook
         at src/libstd/panicking.rs:478
5: std::panicking::continue_panic_fmt
         at src/libstd/panicking.rs:385
6: rust_begin_unwind
         at src/libstd/panicking.rs:312
7: core::panicking::panic_fmt
         at src/libcore/panicking.rs:85
8: core::result::unwrap_failed
         at /rustc/daa53a52a2667533d5fe59bfcc5b8614b79c3d31/src/libcore/macros.rs:16
9: <core::result::Result<T, E>>::unwrap
         at /rustc/daa53a52a2667533d5fe59bfcc5b8614b79c3d31/src/libcore/result.rs:798
10: test_dev::main
         at src/main.rs:22
11: std::rt::lang_start::{{closure}}
         at /rustc/daa53a52a2667533d5fe59bfcc5b8614b79c3d31/src/libstd/rt.rs:64
12: std::panicking::try::do_call
         at src/libstd/rt.rs:49
         at src/libstd/panicking.rs:297
13: __rust_maybe_catch_panic
         at src/libpanic_unwind/lib.rs:92
14: std::rt::lang_start_internal
         at src/libstd/panicking.rs:276
         at src/libstd/panic.rs:388
         at src/libstd/rt.rs:48
15: std::rt::lang_start
         at /rustc/daa53a52a2667533d5fe59bfcc5b8614b79c3d31/src/libstd/rt.rs:64
 16: main
 17: __libc_start_main
 18: _start

Maybe is more easy to send the mutable full array to my function no ? Or work without function in this case ? Also it’s the first time, I have heard of Nightly compiler, what more can it add compared to the official compiler ?

Thank :slight_smile:
cyms

0 Likes

#6

My first version gives a run-time error, it was just a starting point for you. Perhaps you want something closer to this?

const N: usize = 4;
type T = usize;

fn xor(arr: &mut[T], i: usize, j: usize) {
    for k in 0 .. N {
        arr[i + k] ^= arr[j + k];
    }
}

fn main() {
    let mut data: [T; 32] = [
        0xc6, 0x6a, 0xa6, 0x12, 0x4a, 0xba, 0x4d, 0x04, 0x4a, 0x22, 0x03,
        0x54, 0x5b, 0x28, 0x0e, 0x63, 0xea, 0x79, 0x79, 0x20, 0xc8, 0x71,
        0x44, 0x7d, 0x46, 0x62, 0x5f, 0x51, 0x85, 0xc1, 0x3b, 0xcb,
    ];

    for i in (1 ..= 12).rev().step_by(N) { // 12 8 4
        xor(&mut data, i, i - N);
    }
}

The Nightly was to use the try_from because you were trying to convert slices into fixed-size arrays.

1 Like

#7

I’ll try to explain what mistakes are in the code, and how it is done correctly.

1. Ranges

The slices in the for-loop use an A..=B range, which is inclusive. This means that &key[i ..= i+4] contains 5 elements: i, i+1, i+2, i+3, and i+4. Since you want only 4 elements, you need an A..B range (without the equals sign). This means that A is included, but B is not.

let slice1 = &key[i .. i+4];
let slice2 = &key[i-4 .. i];

Alternatively, you can write &key[i ..= i+3] to get a slice of the correct size.

2. Arrays vs. slices

An array [T;N] has a constant size N, a slice &[T] doesn’t. Therefore, you can’t use a slice where an array is required, so xor(slice1,slice2) is forbidden. The easiest way to prevent this error is to use slices in xor(), not arrays:

fn xor(tab1: &[usize], tab2: &[usize]) -> [usize; 4] {
    let mut new_tab: [usize; 4] = [0, 0, 0, 0];
    for n in 0 ..= 3 {
        new_tab[n] = tab1[n] ^ tab2[n];
    }
    return new_tab;
}

3. Assigning a slice

Look at this line in the main() function:

key[i .. i+4] = xor(slice1, slice2);

This is illegal: key[i .. i+4] has the type [usize], so its size is unknown at compile-time. Therefore, slices always have to be behind a reference (e.g. &[usize]).

But even if you add the &, it won’t compile, because you can’t assign to a slice (this syntax is forbidden on the left side of an assignment). Instead, you can use &[usize]::clone_from_slice() to clone the elements from a slice into another slice.

This is the corrected for-loop:

for i in SimpleStepRange(12, 0, -4) {
    let i = i as usize;
    
    let slice1 = &key[i .. i+4];
    let slice2 = &key[i-4 .. i];
    
    let result = xor(slice1, slice2);
    &mut key[i .. i+4].clone_from_slice(&result[..]);
}

Performance

This implementation creates slices from an array, passes it to xor() which then generates an array, which is then cloned into the original array – this is pretty inefficient.

Ideal implementation

The following implementation should be pretty efficient:

fn main() {
    let mut data: [T; 32] = [
        0xc6, 0x6a, 0xa6, 0x12, 0x4a, 0xba, 0x4d, 0x04, 0x4a, 0x22, 0x03,
        0x54, 0x5b, 0x28, 0x0e, 0x63, 0xea, 0x79, 0x79, 0x20, 0xc8, 0x71,
        0x44, 0x7d, 0x46, 0x62, 0x5f, 0x51, 0x85, 0xc1, 0x3b, 0xcb,
    ];
    
    // Iterate over [12, 8, 4]
    for i in SimpleStepRange(12, 0, -4) {
        let i = i as usize;
        
        // Get two mutable slices of the array
        // split_at_mut() is needed to satisfy the borrow checker
        let (slice2, slice1) = (&mut key[i-4 .. i+4]).split_at_mut(4);
        
        // Perform xor on each element of the slices
        for (a, b) in slice1.iter_mut().zip(slice2) {
            *a = *a ^ *b;
        }
    }
}
1 Like

#8

Many many thanks for the help. Now I sould be able to finish my project.

Thanks again guys

EDIT:

Yep all work now, thanks again guys

0 Likes