#interior-mutability #slice #zero-allocation #mutable #run-time #elements #scenario

indices

Indices 提供了用于从可变切片中安全地检索多个可变元素的宏和方法,针对切片元素通常需要 RefCellCell(内部可变性方法)的场景。

10 个版本

0.3.6 2024 年 7 月 21 日
0.3.5 2024 年 7 月 21 日
0.3.1 2024 年 4 月 23 日
0.2.1 2024 年 4 月 22 日
0.1.0 2024 年 4 月 21 日

#499 in Rust 模式

Download history 1/week @ 2024-05-03 4/week @ 2024-05-17 1/week @ 2024-05-24 1/week @ 2024-06-07 5/week @ 2024-06-14 2/week @ 2024-06-21 1/week @ 2024-06-28 15/week @ 2024-07-05 5/week @ 2024-07-12 480/week @ 2024-07-19 60/week @ 2024-07-26 13/week @ 2024-08-02 9/week @ 2024-08-09 10/week @ 2024-08-16

100 个月下载量
3 个包中使用了(通过 error_set_impl

Apache-2.0

54KB
1K SLoC

Indices

github crates.io docs.rs build status

Indices 提供了用于从 可变切片 中安全地检索 多个可变元素 的宏和方法,针对切片元素通常需要 RefCellCell(内部可变性方法)的场景。

例如:

let (four, one, two) = indices!(slice, 4, 1, 2);

这将展开为:

#[inline(always)]
fn func<T>(slice: &mut [T], one: usize, two: usize, three: usize,) -> (&mut T, &mut T, &mut T) {
    if one == two || one == three || two == three {
        panic!("Duplicate indices are not allowed.");
    }
    let slice_len = slice.len();
    if one >= slice_len || two >= slice_len || three >= slice_len {
        panic!("Index out of bounds.");
    }
    let ptr = slice.as_mut_ptr();
    unsafe { (&mut *ptr.add(one), &mut *ptr.add(two), &mut *ptr.add(three)) }
}
let (four, one, two) = func(slice, 4, 1, 2);

这将由 Rust 编译器优化为以下伪代码:

if 4 >= slice.len() {
    panic!("Index out of bounds.");
}
let (four, one, two) = (&mut slice[4], &mut slice[1], &mut slice[2])

以上代码是安全的、正确的,并且比使用 RefCellCell 更高效。`indices!` 会按照上述展开模式进行最多 4 个请求的索引。在这一点上,宏将切换到针对许多请求的索引的更优化方法。

还有 `try_indices!`、`indices_ordered!` 和 `try_indices_ordered!`。

示例

宏示例

所有宏都是零分配,允许在运行时检索可变数量的索引。当索引数量在编译时已知时,请首选宏。例如:

fn main() {
    struct Person {
        first: String,
        last: String,
    }
    let mut data = [
        Person { first: "John".to_string(), last: "Doe".to_string() },
        Person { first: "Jane".to_string(), last: "Smith".to_string() },
        Person { first: "Alice".to_string(), last: "Johnson".to_string() },
        Person { first: "Bob".to_string(), last: "Brown".to_string() },
        Person { first: "Charlie".to_string(), last: "White".to_string() },
    ];
    fn modify(data_slice: &mut [Person], index: usize){
        let (four, func_provided, three) = indices!(data_slice, 4, index, 3);
        four.last = "Black".to_string();
        func_provided.first = "Jack".to_string();
        three.last = "Jones".to_string();
    }
    let slice = data.as_mut_slice();
    modify(slice, 1);
    assert_eq!(data[4].last, "Black");
    assert_eq!(data[1].first, "Jack");
    assert_eq!(data[3].last, "Jones");
}
方法示例

当在编译时不知道索引数量时,方法允许更动态的运行时检索。例如:

fn main() {
    struct Node {
        index: usize,
        visited: usize,
        edges: Vec<usize>,
        message: String,
    }

    let mut graph = vec![
        Node {
            index: 0,
            visited: usize::MAX,
            edges: vec![1, 2],
            message: String::new(),
        },
        Node {
            index: 1,
            visited: usize::MAX,
            edges: vec![0, 2],
            message: String::new(),
        },
        Node {
            index: 2,
            visited: usize::MAX,
            edges: vec![3],
            message: String::new(),
        },
        Node {
            index: 4,
            visited: usize::MAX,
            edges: vec![1],
            message: String::new(),
        },
    ];

    fn traverse_graph(graph: &mut [Node], current: usize, start: usize) -> bool {
        if current == start {
            return true;
        }
        let edges = graph[current].edges.clone();
        let [mut current_node, mut edge_nodes] = indices_slices(graph, [&[current], &edges]);
        for edge_node in edge_nodes.iter_mut() {
            current_node[0].visited = current;
            edge_node.message.push_str(&format!(
                "This is Node `{}` Came from Node `{}`.",
                edge_node.index, current_node[0].visited
            ));
        }
        for edge in edges {
            if traverse_graph(graph, edge, start) {
                return true;
            }
        }
        return false;
    }
    traverse_graph(&mut *graph, 2, 0);
    let answers = [
        "This is Node `0` Came from Node `1`.",
        "This is Node `1` Came from Node `3`.",
        "This is Node `2` Came from Node `1`.",
        "This is Node `4` Came from Node `2`.",
    ];
    for (index, node) in graph.iter().enumerate() {
        assert_eq!(&node.message, answers[index]);
    }
}

无运行时依赖