Skip to main content

BindGroupEntries

Struct BindGroupEntries 

Source
pub struct BindGroupEntries<'b, const N: usize = 1> { /* private fields */ }
Available on crate feature bevy_render only.
Expand description

Helper for constructing bindgroups.

Allows constructing the descriptor’s entries as:

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &BindGroupEntries::with_indices((
        (2, &my_sampler),
        (3, my_uniform),
    )),
);

instead of

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &[
        BindGroupEntry {
            binding: 2,
            resource: BindingResource::Sampler(&my_sampler),
        },
        BindGroupEntry {
            binding: 3,
            resource: my_uniform,
        },
    ],
);

or

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &BindGroupEntries::sequential((
        &my_sampler,
        my_uniform,
    )),
);

instead of

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &[
        BindGroupEntry {
            binding: 0,
            resource: BindingResource::Sampler(&my_sampler),
        },
        BindGroupEntry {
            binding: 1,
            resource: my_uniform,
        },
    ],
);

or

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &BindGroupEntries::single(my_uniform),
);

instead of

ⓘ
render_device.create_bind_group(
    "my_bind_group",
    &my_layout,
    &[
        BindGroupEntry {
            binding: 0,
            resource: my_uniform,
        },
    ],
);

Implementations§

Source§

impl<'b, const N: usize> BindGroupEntries<'b, N>

Source

pub fn sequential( resources: impl IntoBindingArray<'b, N>, ) -> BindGroupEntries<'b, N>

Examples found in repository?
examples/shader_advanced/deferred_raymarch.rs (line 225)
213fn raymarch_bind_group(
214    ctx: &RenderContext,
215    pipeline_cache: &PipelineCache,
216    layout: &BindGroupLayoutDescriptor,
217    view_uniforms: &ViewUniforms,
218    globals: &GlobalsBuffer,
219) -> Option<BindGroup> {
220    let view_binding = view_uniforms.uniforms.binding()?;
221    let globals_binding = globals.buffer.binding()?;
222    Some(ctx.render_device().create_bind_group(
223        "raymarch_bind_group",
224        &pipeline_cache.get_bind_group_layout(layout),
225        &BindGroupEntries::sequential((view_binding, globals_binding)),
226    ))
227}
More examples
Hide additional examples
examples/shader/gpu_readback.rs (lines 175-178)
160fn prepare_bind_group(
161    mut commands: Commands,
162    pipeline: Res<ComputePipeline>,
163    render_device: Res<RenderDevice>,
164    pipeline_cache: Res<PipelineCache>,
165    buffer: Res<ReadbackBuffer>,
166    image: Res<ReadbackImage>,
167    buffers: Res<RenderAssets<GpuShaderBuffer>>,
168    images: Res<RenderAssets<GpuImage>>,
169) {
170    let buffer = buffers.get(&buffer.0).unwrap();
171    let image = images.get(&image.0).unwrap();
172    let bind_group = render_device.create_bind_group(
173        None,
174        &pipeline_cache.get_bind_group_layout(&pipeline.layout),
175        &BindGroupEntries::sequential((
176            buffer.buffer.as_entire_buffer_binding(),
177            image.texture_view.into_binding(),
178        )),
179    );
180    commands.insert_resource(GpuBufferBindGroup(bind_group));
181}
examples/shader/compute_shader_game_of_life.rs (lines 151-155)
130fn prepare_bind_group(
131    mut commands: Commands,
132    pipeline: Res<GameOfLifePipeline>,
133    gpu_images: Res<RenderAssets<GpuImage>>,
134    game_of_life_images: Res<GameOfLifeImages>,
135    game_of_life_uniforms: Res<GameOfLifeUniforms>,
136    render_device: Res<RenderDevice>,
137    pipeline_cache: Res<PipelineCache>,
138    queue: Res<RenderQueue>,
139) {
140    let view_a = gpu_images.get(&game_of_life_images.texture_a).unwrap();
141    let view_b = gpu_images.get(&game_of_life_images.texture_b).unwrap();
142
143    // Uniform buffer is used here to demonstrate how to set up a uniform in a compute shader
144    // Alternatives such as storage buffers or push constants may be more suitable for your use case
145    let mut uniform_buffer = UniformBuffer::from(game_of_life_uniforms.into_inner());
146    uniform_buffer.write_buffer(&render_device, &queue);
147
148    let bind_group_0 = render_device.create_bind_group(
149        None,
150        &pipeline_cache.get_bind_group_layout(&pipeline.texture_bind_group_layout),
151        &BindGroupEntries::sequential((
152            &view_a.texture_view,
153            &view_b.texture_view,
154            &uniform_buffer,
155        )),
156    );
157    let bind_group_1 = render_device.create_bind_group(
158        None,
159        &pipeline_cache.get_bind_group_layout(&pipeline.texture_bind_group_layout),
160        &BindGroupEntries::sequential((
161            &view_b.texture_view,
162            &view_a.texture_view,
163            &uniform_buffer,
164        )),
165    );
166    commands.insert_resource(GameOfLifeImageBindGroups([bind_group_0, bind_group_1]));
167}
examples/shader_advanced/texture_binding_array.rs (line 139)
105    fn as_bind_group(
106        &self,
107        layout: &BindGroupLayoutDescriptor,
108        render_device: &RenderDevice,
109        pipeline_cache: &PipelineCache,
110        _: &FallbackBuffer,
111        shader_buffer_assets: &RenderAssets<GpuShaderBuffer>,
112        (image_assets, fallback_image): &mut SystemParamItem<'_, '_, Self::Param>,
113    ) -> Result<PreparedBindGroup, AsBindGroupError> {
114        let _ = shader_buffer_assets;
115        // retrieve the render resources from handles
116        let mut images = vec![];
117        for handle in self.textures.iter().take(MAX_TEXTURE_COUNT) {
118            match image_assets.get(handle) {
119                Some(image) => images.push(image),
120                None => return Err(AsBindGroupError::RetryNextUpdate),
121            }
122        }
123
124        let fallback_image = &fallback_image.d2;
125
126        let textures = vec![&fallback_image.texture_view; MAX_TEXTURE_COUNT];
127
128        // convert bevy's resource types to WGPU's references
129        let mut textures: Vec<_> = textures.into_iter().map(|texture| &**texture).collect();
130
131        // fill in up to the first `MAX_TEXTURE_COUNT` textures and samplers to the arrays
132        for (id, image) in images.into_iter().enumerate() {
133            textures[id] = &*image.texture_view;
134        }
135
136        let bind_group = render_device.create_bind_group(
137            Self::label(),
138            &pipeline_cache.get_bind_group_layout(layout),
139            &BindGroupEntries::sequential((&textures[..], &fallback_image.sampler)),
140        );
141
142        Ok(PreparedBindGroup {
143            bindings: BindingResources(vec![]),
144            bind_group,
145        })
146    }
examples/shader_advanced/custom_post_processing.rs (lines 109-113)
88fn prepare_bind_groups(
89    mut commands: Commands,
90    mut views: Query<(Entity, &ViewTarget, Option<&mut PostProcessBindGroups>)>,
91    post_process_pipeline: Option<Res<PostProcessPipeline>>,
92    pipeline_cache: Res<PipelineCache>,
93    settings_uniforms: Res<ComponentUniforms<PostProcessSettings>>,
94    render_device: Res<RenderDevice>,
95) {
96    let Some(post_process_pipeline) = post_process_pipeline else {
97        return;
98    };
99    let Some(settings_binding) = settings_uniforms.uniforms().binding() else {
100        return;
101    };
102
103    let create_bind_group = |texture: &TextureView| {
104        (
105            texture.id(),
106            render_device.create_bind_group(
107                "post_process_bind_group",
108                &pipeline_cache.get_bind_group_layout(&post_process_pipeline.layout),
109                &BindGroupEntries::sequential((
110                    texture,
111                    &post_process_pipeline.sampler,
112                    settings_binding.clone(),
113                )),
114            ),
115        )
116    };
117
118    for (entity, view_target, mut maybe_bind_groups) in &mut views {
119        let main_texture_view = view_target.main_texture_view();
120        let main_texture_other_view = view_target.main_texture_other_view();
121
122        // Only update the cached bind groups if the main texture has changed
123        if let Some(bind_groups) = &mut maybe_bind_groups {
124            if bind_groups.a.0 != main_texture_view.id() {
125                bind_groups.a = create_bind_group(main_texture_view);
126            }
127            if bind_groups.b.0 != main_texture_other_view.id() {
128                bind_groups.b = create_bind_group(main_texture_other_view);
129            }
130        } else {
131            // Create the bind groups and add them to the view
132            commands.entity(entity).insert(PostProcessBindGroups {
133                a: create_bind_group(main_texture_view),
134                b: create_bind_group(main_texture_other_view),
135            });
136        }
137    }
138}
examples/shader_advanced/mesh_shader_intro.rs (line 231)
202fn draw_mesh_shader_cubes(
203    mut views: Query<(
204        &ExtractedCamera,
205        &ExtractedView,
206        &ViewTarget,
207        &ViewDepthStencilTexture,
208        &ViewUniformOffset,
209        Option<&MainPassResolutionOverride>,
210    )>,
211    mut render_context: RenderContext,
212    data: Res<MyMeshShaderDrawNode>,
213    view_uniforms: Res<ViewUniforms>,
214    globals: Res<GlobalsBuffer>,
215    pipeline_cache: Res<PipelineCache>,
216) {
217    let Some(mesh_pipeline) = pipeline_cache.get_render_pipeline(data.mesh_pipeline) else {
218        return;
219    };
220
221    for (camera, _, target, depth, view_uniform_offset, resolution_override) in &mut views {
222        let Some(view_binding) = view_uniforms.uniforms.binding() else {
223            return;
224        };
225        let Some(globals_binding) = globals.buffer.binding() else {
226            return;
227        };
228        let bind_group = render_context.render_device().create_bind_group(
229            "custom_task_mesh_bind_group",
230            &pipeline_cache.get_bind_group_layout(&data.layout),
231            &BindGroupEntries::sequential((globals_binding, view_binding)),
232        );
233
234        {
235            let mut pass = render_context.begin_tracked_render_pass(RenderPassDescriptor {
236                label: Some("custom_mesh_shader_pass"),
237                // Write directly to the view target
238                color_attachments: &[Some(target.get_color_attachment())],
239                depth_stencil_attachment: Some(depth.get_attachment(StoreOp::Store)),
240                timestamp_writes: None,
241                occlusion_query_set: None,
242                multiview_mask: None,
243            });
244
245            pass.set_render_pipeline(mesh_pipeline);
246            pass.set_bind_group(0, &bind_group, &[view_uniform_offset.offset]);
247            if let Some(viewport) =
248                Viewport::from_viewport_and_override(camera.viewport.as_ref(), resolution_override)
249            {
250                pass.set_camera_viewport(&viewport);
251            }
252
253            // Since this MeshPipeline has a task shader, this call
254            // dispatches the task shader workgroup
255            pass.draw_mesh_tasks(1, 1, 1);
256        }
257    }
258}
Source

pub fn with_indices( indexed_resources: impl IntoIndexedBindingArray<'b, N>, ) -> BindGroupEntries<'b, N>

Source§

impl<'b> BindGroupEntries<'b>

Source

pub fn single(resource: impl IntoBinding<'b>) -> [BindGroupEntry<'b>; 1]

Methods from Deref<Target = [BindGroupEntry<'b>]>§

1.0.0 · Source

pub fn len(&self) -> usize

Returns the number of elements in the slice.

§Examples
let a = [1, 2, 3];
assert_eq!(a.len(), 3);
1.0.0 · Source

pub fn is_empty(&self) -> bool

Returns true if the slice has a length of 0.

§Examples
let a = [1, 2, 3];
assert!(!a.is_empty());

let b: &[i32] = &[];
assert!(b.is_empty());
1.0.0 · Source

pub fn first(&self) -> Option<&T>

Returns the first element of the slice, or None if it is empty.

§Examples
let v = [10, 40, 30];
assert_eq!(Some(&10), v.first());

let w: &[i32] = &[];
assert_eq!(None, w.first());
1.5.0 · Source

pub fn split_first(&self) -> Option<(&T, &[T])>

Returns the first and all the rest of the elements of the slice, or None if it is empty.

§Examples
let x = &[0, 1, 2];

if let Some((first, elements)) = x.split_first() {
    assert_eq!(first, &0);
    assert_eq!(elements, &[1, 2]);
}
1.5.0 · Source

pub fn split_last(&self) -> Option<(&T, &[T])>

Returns the last and all the rest of the elements of the slice, or None if it is empty.

§Examples
let x = &[0, 1, 2];

if let Some((last, elements)) = x.split_last() {
    assert_eq!(last, &2);
    assert_eq!(elements, &[0, 1]);
}
1.0.0 · Source

pub fn last(&self) -> Option<&T>

Returns the last element of the slice, or None if it is empty.

§Examples
let v = [10, 40, 30];
assert_eq!(Some(&30), v.last());

let w: &[i32] = &[];
assert_eq!(None, w.last());
1.77.0 · Source

pub fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>

Returns an array reference to the first N items in the slice.

If the slice is not at least N in length, this will return None.

§Examples
let u = [10, 40, 30];
assert_eq!(Some(&[10, 40]), u.first_chunk::<2>());

let v: &[i32] = &[10];
assert_eq!(None, v.first_chunk::<2>());

let w: &[i32] = &[];
assert_eq!(Some(&[]), w.first_chunk::<0>());
1.77.0 · Source

pub fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>

Returns an array reference to the first N items in the slice and the remaining slice.

If the slice is not at least N in length, this will return None.

§Examples
let x = &[0, 1, 2];

if let Some((first, elements)) = x.split_first_chunk::<2>() {
    assert_eq!(first, &[0, 1]);
    assert_eq!(elements, &[2]);
}

assert_eq!(None, x.split_first_chunk::<4>());
1.77.0 · Source

pub fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>

Returns an array reference to the last N items in the slice and the remaining slice.

If the slice is not at least N in length, this will return None.

§Examples
let x = &[0, 1, 2];

if let Some((elements, last)) = x.split_last_chunk::<2>() {
    assert_eq!(elements, &[0]);
    assert_eq!(last, &[1, 2]);
}

assert_eq!(None, x.split_last_chunk::<4>());
1.77.0 · Source

pub fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>

Returns an array reference to the last N items in the slice.

If the slice is not at least N in length, this will return None.

§Examples
let u = [10, 40, 30];
assert_eq!(Some(&[40, 30]), u.last_chunk::<2>());

let v: &[i32] = &[10];
assert_eq!(None, v.last_chunk::<2>());

let w: &[i32] = &[];
assert_eq!(Some(&[]), w.last_chunk::<0>());
1.0.0 · Source

pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
where I: SliceIndex<[T]>,

Returns a reference to an element or subslice depending on the type of index.

  • If given a position, returns a reference to the element at that position or None if out of bounds.
  • If given a range, returns the subslice corresponding to that range, or None if out of bounds.
§Examples
let v = [10, 40, 30];
assert_eq!(Some(&40), v.get(1));
assert_eq!(Some(&[10, 40][..]), v.get(0..2));
assert_eq!(None, v.get(3));
assert_eq!(None, v.get(0..4));
1.0.0 · Source

pub unsafe fn get_unchecked<I>( &self, index: I, ) -> &<I as SliceIndex<[T]>>::Output
where I: SliceIndex<[T]>,

Returns a reference to an element or subslice, without doing bounds checking.

For a safe alternative see get.

§Safety

Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used.

You can think of this like .get(index).unwrap_unchecked(). It’s UB to call .get_unchecked(len), even if you immediately convert to a pointer. And it’s UB to call .get_unchecked(..len + 1), .get_unchecked(..=len), or similar.

§Examples
let x = &[1, 2, 4];

unsafe {
    assert_eq!(x.get_unchecked(1), &2);
}
1.0.0 · Source

pub fn as_ptr(&self) -> *const T

Returns a raw pointer to the slice’s buffer.

The caller must ensure that the slice outlives the pointer this function returns, or else it will end up dangling.

The caller must also ensure that the memory the pointer (non-transitively) points to is never written to (except inside an UnsafeCell) using this pointer or any pointer derived from it. If you need to mutate the contents of the slice, use as_mut_ptr.

Modifying the container referenced by this slice may cause its buffer to be reallocated, which would also make any pointers to it invalid.

§Examples
let x = &[1, 2, 4];
let x_ptr = x.as_ptr();

unsafe {
    for i in 0..x.len() {
        assert_eq!(x.get_unchecked(i), &*x_ptr.add(i));
    }
}
1.48.0 · Source

pub fn as_ptr_range(&self) -> Range<*const T> ⓘ

Returns the two raw pointers spanning the slice.

The returned range is half-open, which means that the end pointer points one past the last element of the slice. This way, an empty slice is represented by two equal pointers, and the difference between the two pointers represents the size of the slice.

See as_ptr for warnings on using these pointers. The end pointer requires extra caution, as it does not point to a valid element in the slice.

This function is useful for interacting with foreign interfaces which use two pointers to refer to a range of elements in memory, as is common in C++.

It can also be useful to check if a pointer to an element refers to an element of this slice:

let a = [1, 2, 3];
let x = &a[1] as *const _;
let y = &5 as *const _;

assert!(a.as_ptr_range().contains(&x));
assert!(!a.as_ptr_range().contains(&y));
1.93.0 · Source

pub fn as_array<const N: usize>(&self) -> Option<&[T; N]>

Gets a reference to the underlying array.

If N is not exactly equal to the length of self, then this method returns None.

1.0.0 · Source

pub fn iter(&self) -> Iter<'_, T> ⓘ

Returns an iterator over the slice.

The iterator yields all items from start to end.

§Examples
let x = &[1, 2, 4];
let mut iterator = x.iter();

assert_eq!(iterator.next(), Some(&1));
assert_eq!(iterator.next(), Some(&2));
assert_eq!(iterator.next(), Some(&4));
assert_eq!(iterator.next(), None);
1.0.0 · Source

pub fn windows(&self, size: usize) -> Windows<'_, T> ⓘ

Returns an iterator over all contiguous windows of length size. The windows overlap. If the slice is shorter than size, the iterator returns no values.

§Panics

Panics if size is zero.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.windows(3);
assert_eq!(iter.next().unwrap(), &['l', 'o', 'r']);
assert_eq!(iter.next().unwrap(), &['o', 'r', 'e']);
assert_eq!(iter.next().unwrap(), &['r', 'e', 'm']);
assert!(iter.next().is_none());

If the slice is shorter than size:

let slice = ['f', 'o', 'o'];
let mut iter = slice.windows(4);
assert!(iter.next().is_none());

Because the Iterator trait cannot represent the required lifetimes, there is no windows_mut analog to windows; [0,1,2].windows_mut(2).collect() would violate the rules of references (though a LendingIterator analog is possible). You can sometimes use Cell::as_slice_of_cells in conjunction with windows instead:

use std::cell::Cell;

let mut array = ['R', 'u', 's', 't', ' ', '2', '0', '1', '5'];
let slice = &mut array[..];
let slice_of_cells: &[Cell<char>] = Cell::from_mut(slice).as_slice_of_cells();
for w in slice_of_cells.windows(3) {
    Cell::swap(&w[0], &w[2]);
}
assert_eq!(array, ['s', 't', ' ', '2', '0', '1', '5', 'u', 'R']);
1.0.0 · Source

pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> ⓘ

Returns an iterator over chunk_size elements of the slice at a time, starting at the beginning of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last chunk will not have length chunk_size.

See chunks_exact for a variant of this iterator that returns chunks of always exactly chunk_size elements, and rchunks for the same iterator but starting at the end of the slice.

If your chunk_size is a constant, consider using as_chunks instead, which will give references to arrays of exactly that length, rather than slices.

§Panics

Panics if chunk_size is zero.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.chunks(2);
assert_eq!(iter.next().unwrap(), &['l', 'o']);
assert_eq!(iter.next().unwrap(), &['r', 'e']);
assert_eq!(iter.next().unwrap(), &['m']);
assert!(iter.next().is_none());
1.31.0 · Source

pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> ⓘ

Returns an iterator over chunk_size elements of the slice at a time, starting at the beginning of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved from the remainder function of the iterator.

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the resulting code better than in the case of chunks.

See chunks for a variant of this iterator that also returns the remainder as a smaller chunk, and rchunks_exact for the same iterator but starting at the end of the slice.

If your chunk_size is a constant, consider using as_chunks instead, which will give references to arrays of exactly that length, rather than slices.

§Panics

Panics if chunk_size is zero.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.chunks_exact(2);
assert_eq!(iter.next().unwrap(), &['l', 'o']);
assert_eq!(iter.next().unwrap(), &['r', 'e']);
assert!(iter.next().is_none());
assert_eq!(iter.remainder(), &['m']);
1.88.0 · Source

pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]]

Splits the slice into a slice of N-element arrays, assuming that there’s no remainder.

This is the inverse operation to as_flattened.

As this is unsafe, consider whether you could use as_chunks or as_rchunks instead, perhaps via something like if let (chunks, []) = slice.as_chunks() or let (chunks, []) = slice.as_chunks() else { unreachable!() };.

§Safety

This may only be called when

  • The slice splits exactly into N-element chunks (aka self.len() % N == 0).
  • N != 0.
§Examples
let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
let chunks: &[[char; 1]] =
    // SAFETY: 1-element chunks never have remainder
    unsafe { slice.as_chunks_unchecked() };
assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
let chunks: &[[char; 3]] =
    // SAFETY: The slice length (6) is a multiple of 3
    unsafe { slice.as_chunks_unchecked() };
assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);

// These would be unsound:
// let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
// let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
1.88.0 · Source

pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T])

Splits the slice into a slice of N-element arrays, starting at the beginning of the slice, and a remainder slice with length strictly less than N.

The remainder is meaningful in the division sense. Given let (chunks, remainder) = slice.as_chunks(), then:

  • chunks.len() equals slice.len() / N,
  • remainder.len() equals slice.len() % N, and
  • slice.len() equals chunks.len() * N + remainder.len().

You can flatten the chunks back into a slice-of-T with as_flattened.

§Panics

Panics if N is zero.

Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let (chunks, remainder) = slice.as_chunks();
assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
assert_eq!(remainder, &['m']);

If you expect the slice to be an exact multiple, you can combine let-else with an empty slice pattern:

let slice = ['R', 'u', 's', 't'];
let (chunks, []) = slice.as_chunks::<2>() else {
    panic!("slice didn't have even length")
};
assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
1.88.0 · Source

pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]])

Splits the slice into a slice of N-element arrays, starting at the end of the slice, and a remainder slice with length strictly less than N.

The remainder is meaningful in the division sense. Given let (remainder, chunks) = slice.as_rchunks(), then:

  • remainder.len() equals slice.len() % N,
  • chunks.len() equals slice.len() / N, and
  • slice.len() equals chunks.len() * N + remainder.len().

You can flatten the chunks back into a slice-of-T with as_flattened.

§Panics

Panics if N is zero.

Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let (remainder, chunks) = slice.as_rchunks();
assert_eq!(remainder, &['l']);
assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
1.94.0 · Source

pub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> ⓘ

Returns an iterator over overlapping windows of N elements of a slice, starting at the beginning of the slice.

This is the const generic equivalent of windows.

If N is greater than the size of the slice, it will return no windows.

§Panics

Panics if N is zero.

Note that this check is against a const generic parameter, not a runtime value, and thus a particular monomorphization will either always panic or it will never panic.

§Examples
let slice = [0, 1, 2, 3];
let mut iter = slice.array_windows();
assert_eq!(iter.next().unwrap(), &[0, 1]);
assert_eq!(iter.next().unwrap(), &[1, 2]);
assert_eq!(iter.next().unwrap(), &[2, 3]);
assert!(iter.next().is_none());
1.31.0 · Source

pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> ⓘ

Returns an iterator over chunk_size elements of the slice at a time, starting at the end of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last chunk will not have length chunk_size.

See rchunks_exact for a variant of this iterator that returns chunks of always exactly chunk_size elements, and chunks for the same iterator but starting at the beginning of the slice.

If your chunk_size is a constant, consider using as_rchunks instead, which will give references to arrays of exactly that length, rather than slices.

§Panics

Panics if chunk_size is zero.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.rchunks(2);
assert_eq!(iter.next().unwrap(), &['e', 'm']);
assert_eq!(iter.next().unwrap(), &['o', 'r']);
assert_eq!(iter.next().unwrap(), &['l']);
assert!(iter.next().is_none());
1.31.0 · Source

pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> ⓘ

Returns an iterator over chunk_size elements of the slice at a time, starting at the end of the slice.

The chunks are slices and do not overlap. If chunk_size does not divide the length of the slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved from the remainder function of the iterator.

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the resulting code better than in the case of rchunks.

See rchunks for a variant of this iterator that also returns the remainder as a smaller chunk, and chunks_exact for the same iterator but starting at the beginning of the slice.

If your chunk_size is a constant, consider using as_rchunks instead, which will give references to arrays of exactly that length, rather than slices.

§Panics

Panics if chunk_size is zero.

§Examples
let slice = ['l', 'o', 'r', 'e', 'm'];
let mut iter = slice.rchunks_exact(2);
assert_eq!(iter.next().unwrap(), &['e', 'm']);
assert_eq!(iter.next().unwrap(), &['o', 'r']);
assert!(iter.next().is_none());
assert_eq!(iter.remainder(), &['l']);
1.77.0 · Source

pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F> ⓘ
where F: FnMut(&T, &T) -> bool,

Returns an iterator over the slice producing non-overlapping runs of elements using the predicate to separate them.

The predicate is called for every pair of consecutive elements, meaning that it is called on slice[0] and slice[1], followed by slice[1] and slice[2], and so on.

§Examples
let slice = &[1, 1, 1, 3, 3, 2, 2, 2];

let mut iter = slice.chunk_by(|a, b| a == b);

assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
assert_eq!(iter.next(), Some(&[3, 3][..]));
assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
assert_eq!(iter.next(), None);

This method can be used to extract the sorted subslices:

let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4];

let mut iter = slice.chunk_by(|a, b| a <= b);

assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..]));
assert_eq!(iter.next(), Some(&[2, 3][..]));
assert_eq!(iter.next(), Some(&[2, 3, 4][..]));
assert_eq!(iter.next(), None);
1.0.0 · Source

pub fn split_at(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index.

The first will contain all indices from [0, mid) (excluding the index mid itself) and the second will contain all indices from [mid, len) (excluding the index len itself).

§Panics

Panics if mid > len. For a non-panicking alternative see split_at_checked.

§Examples
let v = ['a', 'b', 'c'];

{
   let (left, right) = v.split_at(0);
   assert_eq!(left, []);
   assert_eq!(right, ['a', 'b', 'c']);
}

{
    let (left, right) = v.split_at(2);
    assert_eq!(left, ['a', 'b']);
    assert_eq!(right, ['c']);
}

{
    let (left, right) = v.split_at(3);
    assert_eq!(left, ['a', 'b', 'c']);
    assert_eq!(right, []);
}
1.79.0 · Source

pub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T])

Divides one slice into two at an index, without doing bounds checking.

The first will contain all indices from [0, mid) (excluding the index mid itself) and the second will contain all indices from [mid, len) (excluding the index len itself).

For a safe alternative see split_at.

§Safety

Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. The caller has to ensure that 0 <= mid <= self.len().

§Examples
let v = ['a', 'b', 'c'];

unsafe {
   let (left, right) = v.split_at_unchecked(0);
   assert_eq!(left, []);
   assert_eq!(right, ['a', 'b', 'c']);
}

unsafe {
    let (left, right) = v.split_at_unchecked(2);
    assert_eq!(left, ['a', 'b']);
    assert_eq!(right, ['c']);
}

unsafe {
    let (left, right) = v.split_at_unchecked(3);
    assert_eq!(left, ['a', 'b', 'c']);
    assert_eq!(right, []);
}
1.80.0 · Source

pub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])>

Divides one slice into two at an index, returning None if the slice is too short.

If mid ≤ len, returns a pair of slices where the first will contain all indices from [0, mid) (excluding the index mid itself) and the second will contain all indices from [mid, len) (excluding the index len itself).

Otherwise, if mid > len, returns None.

§Examples
let v = [1, -2, 3, -4, 5, -6];

{
   let (left, right) = v.split_at_checked(0).unwrap();
   assert_eq!(left, []);
   assert_eq!(right, [1, -2, 3, -4, 5, -6]);
}

{
    let (left, right) = v.split_at_checked(2).unwrap();
    assert_eq!(left, [1, -2]);
    assert_eq!(right, [3, -4, 5, -6]);
}

{
    let (left, right) = v.split_at_checked(6).unwrap();
    assert_eq!(left, [1, -2, 3, -4, 5, -6]);
    assert_eq!(right, []);
}

assert_eq!(None, v.split_at_checked(7));
1.0.0 · Source

pub fn split<F>(&self, pred: F) -> Split<'_, T, F> ⓘ
where F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match pred. The matched element is not contained in the subslices.

§Examples
let slice = [10, 40, 33, 20];
let mut iter = slice.split(|num| num % 3 == 0);

assert_eq!(iter.next().unwrap(), &[10, 40]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none());

If the first element is matched, an empty slice will be the first item returned by the iterator. Similarly, if the last element in the slice is matched, an empty slice will be the last item returned by the iterator:

let slice = [10, 40, 33];
let mut iter = slice.split(|num| num % 3 == 0);

assert_eq!(iter.next().unwrap(), &[10, 40]);
assert_eq!(iter.next().unwrap(), &[]);
assert!(iter.next().is_none());

If two matched elements are directly adjacent, an empty slice will be present between them:

let slice = [10, 6, 33, 20];
let mut iter = slice.split(|num| num % 3 == 0);

assert_eq!(iter.next().unwrap(), &[10]);
assert_eq!(iter.next().unwrap(), &[]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none());
1.51.0 · Source

pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F> ⓘ
where F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match pred. The matched element is contained in the end of the previous subslice as a terminator.

§Examples
let slice = [10, 40, 33, 20];
let mut iter = slice.split_inclusive(|num| num % 3 == 0);

assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
assert_eq!(iter.next().unwrap(), &[20]);
assert!(iter.next().is_none());

If the last element of the slice is matched, that element will be considered the terminator of the preceding slice. That slice will be the last item returned by the iterator.

let slice = [3, 10, 40, 33];
let mut iter = slice.split_inclusive(|num| num % 3 == 0);

assert_eq!(iter.next().unwrap(), &[3]);
assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
assert!(iter.next().is_none());
1.27.0 · Source

pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F> ⓘ
where F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match pred, starting at the end of the slice and working backwards. The matched element is not contained in the subslices.

§Examples
let slice = [11, 22, 33, 0, 44, 55];
let mut iter = slice.rsplit(|num| *num == 0);

assert_eq!(iter.next().unwrap(), &[44, 55]);
assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
assert_eq!(iter.next(), None);

As with split(), if the first or last element is matched, an empty slice will be the first (or last) item returned by the iterator.

let v = &[0, 1, 1, 2, 3, 5, 8];
let mut it = v.rsplit(|n| *n % 2 == 0);
assert_eq!(it.next().unwrap(), &[]);
assert_eq!(it.next().unwrap(), &[3, 5]);
assert_eq!(it.next().unwrap(), &[1, 1]);
assert_eq!(it.next().unwrap(), &[]);
assert_eq!(it.next(), None);
1.0.0 · Source

pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F> ⓘ
where F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match pred, limited to returning at most n items. The matched element is not contained in the subslices.

The last element returned, if any, will contain the remainder of the slice.

§Examples

Print the slice split once by numbers divisible by 3 (i.e., [10, 40], [20, 60, 50]):

let v = [10, 40, 30, 20, 60, 50];

for group in v.splitn(2, |num| *num % 3 == 0) {
    println!("{group:?}");
}
1.0.0 · Source

pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F> ⓘ
where F: FnMut(&T) -> bool,

Returns an iterator over subslices separated by elements that match pred limited to returning at most n items. This starts at the end of the slice and works backwards. The matched element is not contained in the subslices.

The last element returned, if any, will contain the remainder of the slice.

§Examples

Print the slice split once, starting from the end, by numbers divisible by 3 (i.e., [50], [10, 40, 30, 20]):

let v = [10, 40, 30, 20, 60, 50];

for group in v.rsplitn(2, |num| *num % 3 == 0) {
    println!("{group:?}");
}
Source

pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the first element that matches the specified predicate.

If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns None.

§Examples
#![feature(slice_split_once)]
let s = [1, 2, 3, 2, 4];
assert_eq!(s.split_once(|&x| x == 2), Some((
    &[1][..],
    &[3, 2, 4][..]
)));
assert_eq!(s.split_once(|&x| x == 0), None);
Source

pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
where F: FnMut(&T) -> bool,

🔬This is a nightly-only experimental API. (slice_split_once)

Splits the slice on the last element that matches the specified predicate.

If any matching elements are present in the slice, returns the prefix before the match and suffix after. The matching element itself is not included. If no elements match, returns None.

§Examples
#![feature(slice_split_once)]
let s = [1, 2, 3, 2, 4];
assert_eq!(s.rsplit_once(|&x| x == 2), Some((
    &[1, 2, 3][..],
    &[4][..]
)));
assert_eq!(s.rsplit_once(|&x| x == 0), None);
1.0.0 · Source

pub fn contains(&self, x: &T) -> bool
where T: PartialEq,

Returns true if the slice contains an element with the given value.

This operation is O(n).

Note that if you have a sorted slice, binary_search may be faster.

§Examples
let v = [10, 40, 30];
assert!(v.contains(&30));
assert!(!v.contains(&50));

If you do not have a &T, but some other value that you can compare with one (for example, String implements PartialEq<str>), you can use iter().any:

let v = [String::from("hello"), String::from("world")]; // slice of `String`
assert!(v.iter().any(|e| e == "hello")); // search with `&str`
assert!(!v.iter().any(|e| e == "hi"));
1.0.0 · Source

pub fn starts_with(&self, needle: &[T]) -> bool
where T: PartialEq,

Returns true if needle is a prefix of the slice or equal to the slice.

§Examples
let v = [10, 40, 30];
assert!(v.starts_with(&[10]));
assert!(v.starts_with(&[10, 40]));
assert!(v.starts_with(&v));
assert!(!v.starts_with(&[50]));
assert!(!v.starts_with(&[10, 50]));

Always returns true if needle is an empty slice:

let v = &[10, 40, 30];
assert!(v.starts_with(&[]));
let v: &[u8] = &[];
assert!(v.starts_with(&[]));
1.0.0 · Source

pub fn ends_with(&self, needle: &[T]) -> bool
where T: PartialEq,

Returns true if needle is a suffix of the slice or equal to the slice.

§Examples
let v = [10, 40, 30];
assert!(v.ends_with(&[30]));
assert!(v.ends_with(&[40, 30]));
assert!(v.ends_with(&v));
assert!(!v.ends_with(&[50]));
assert!(!v.ends_with(&[50, 30]));

Always returns true if needle is an empty slice:

let v = &[10, 40, 30];
assert!(v.ends_with(&[]));
let v: &[u8] = &[];
assert!(v.ends_with(&[]));
1.51.0 · Source

pub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]>
where P: SlicePattern<Item = T> + ?Sized, T: PartialEq,

Returns a subslice with the prefix removed.

If the slice starts with prefix, returns the subslice after the prefix, wrapped in Some. If prefix is empty, simply returns the original slice. If prefix is equal to the original slice, returns an empty slice.

If the slice does not start with prefix, returns None.

§Examples
let v = &[10, 40, 30];
assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
assert_eq!(v.strip_prefix(&[10, 40, 30]), Some(&[][..]));
assert_eq!(v.strip_prefix(&[50]), None);
assert_eq!(v.strip_prefix(&[10, 50]), None);

let prefix : &str = "he";
assert_eq!(b"hello".strip_prefix(prefix.as_bytes()),
           Some(b"llo".as_ref()));
1.51.0 · Source

pub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]>
where P: SlicePattern<Item = T> + ?Sized, T: PartialEq,

Returns a subslice with the suffix removed.

If the slice ends with suffix, returns the subslice before the suffix, wrapped in Some. If suffix is empty, simply returns the original slice. If suffix is equal to the original slice, returns an empty slice.

If the slice does not end with suffix, returns None.

§Examples
let v = &[10, 40, 30];
assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
assert_eq!(v.strip_suffix(&[10, 40, 30]), Some(&[][..]));
assert_eq!(v.strip_suffix(&[50]), None);
assert_eq!(v.strip_suffix(&[50, 30]), None);
1.98.0 · Source

pub fn strip_circumfix<S, P>(&self, prefix: &P, suffix: &S) -> Option<&[T]>
where T: PartialEq, S: SlicePattern<Item = T> + ?Sized, P: SlicePattern<Item = T> + ?Sized,

Returns a subslice with the prefix and suffix removed.

If the slice starts with prefix, ends with suffix, and the prefix and suffix don’t overlap, returns the subslice after the prefix and before the suffix, wrapped in Some.

If the slice does not start with prefix, does not end with suffix, or the prefix and suffix overlap in the slice, returns None.

§Examples
let v = &[10, 50, 40, 30];
assert_eq!(v.strip_circumfix(&[10], &[30]), Some(&[50, 40][..]));
assert_eq!(v.strip_circumfix(&[10], &[40, 30]), Some(&[50][..]));
assert_eq!(v.strip_circumfix(&[10, 50], &[40, 30]), Some(&[][..]));
assert_eq!(v.strip_circumfix(&[50], &[30]), None);
assert_eq!(v.strip_circumfix(&[10], &[40]), None);
assert_eq!(v.strip_circumfix(&[], &[40, 30]), Some(&[10, 50][..]));
assert_eq!(v.strip_circumfix(&[10, 50], &[]), Some(&[40, 30][..]));
assert_eq!(v.strip_circumfix(&[10, 50, 40], &[50, 40, 30]), None);
1.100.0 · Source

pub fn trim_prefix<P>(&self, prefix: &P) -> &[T]
where P: SlicePattern<Item = T> + ?Sized, T: PartialEq,

Returns a subslice with the optional prefix removed.

If the slice starts with prefix, returns the subslice after the prefix. If prefix is empty or the slice does not start with prefix, simply returns the original slice. If prefix is equal to the original slice, returns an empty slice.

§Examples
let v = &[10, 40, 30];

// Prefix present - removes it
assert_eq!(v.trim_prefix(&[10]), &[40, 30][..]);
assert_eq!(v.trim_prefix(&[10, 40]), &[30][..]);
assert_eq!(v.trim_prefix(&[10, 40, 30]), &[][..]);

// Prefix absent - returns original slice
assert_eq!(v.trim_prefix(&[50]), &[10, 40, 30][..]);
assert_eq!(v.trim_prefix(&[10, 50]), &[10, 40, 30][..]);

let prefix : &str = "he";
assert_eq!(b"hello".trim_prefix(prefix.as_bytes()), b"llo".as_ref());
1.100.0 · Source

pub fn trim_suffix<P>(&self, suffix: &P) -> &[T]
where P: SlicePattern<Item = T> + ?Sized, T: PartialEq,

Returns a subslice with the optional suffix removed.

If the slice ends with suffix, returns the subslice before the suffix. If suffix is empty or the slice does not end with suffix, simply returns the original slice. If suffix is equal to the original slice, returns an empty slice.

§Examples
let v = &[10, 40, 30];

// Suffix present - removes it
assert_eq!(v.trim_suffix(&[30]), &[10, 40][..]);
assert_eq!(v.trim_suffix(&[40, 30]), &[10][..]);
assert_eq!(v.trim_suffix(&[10, 40, 30]), &[][..]);

// Suffix absent - returns original slice
assert_eq!(v.trim_suffix(&[50]), &[10, 40, 30][..]);
assert_eq!(v.trim_suffix(&[50, 30]), &[10, 40, 30][..]);

Binary searches this slice for a given element. If the slice is not sorted, the returned result is unspecified and meaningless.

If the value is found then Result::Ok is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then Result::Err is returned, containing the index where a matching element could be inserted while maintaining sorted order.

See also binary_search_by, binary_search_by_key, and partition_point.

§Examples

Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in [1, 4].

let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

assert_eq!(s.binary_search(&13),  Ok(9));
assert_eq!(s.binary_search(&4),   Err(7));
assert_eq!(s.binary_search(&100), Err(13));
let r = s.binary_search(&1);
assert!(match r { Ok(1..=4) => true, _ => false, });

If you want to find that whole range of matching items, rather than an arbitrary matching one, that can be done using partition_point:

let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

let low = s.partition_point(|x| x < &1);
assert_eq!(low, 1);
let high = s.partition_point(|x| x <= &1);
assert_eq!(high, 5);
let r = s.binary_search(&1);
assert!((low..high).contains(&r.unwrap()));

assert!(s[..low].iter().all(|&x| x < 1));
assert!(s[low..high].iter().all(|&x| x == 1));
assert!(s[high..].iter().all(|&x| x > 1));

// For something not found, the "range" of equal items is empty
assert_eq!(s.partition_point(|x| x < &11), 9);
assert_eq!(s.partition_point(|x| x <= &11), 9);
assert_eq!(s.binary_search(&11), Err(9));

If you want to insert an item to a sorted vector, while maintaining sort order, consider using partition_point:

let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
let num = 42;
let idx = s.partition_point(|&x| x <= num);
// If `num` is unique, `s.partition_point(|&x| x < num)` (with `<`) is equivalent to
// `s.binary_search(&num).unwrap_or_else(|x| x)`, but using `<=` will allow `insert`
// to shift less elements.
s.insert(idx, num);
assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
1.0.0 · Source

pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
where F: FnMut(&'a T) -> Ordering,

Binary searches this slice with a comparator function.

The comparator function should return an order code that indicates whether its argument is Less, Equal or Greater the desired target. If the slice is not sorted or if the comparator function does not implement an order consistent with the sort order of the underlying slice, the returned result is unspecified and meaningless.

If the value is found then Result::Ok is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then Result::Err is returned, containing the index where a matching element could be inserted while maintaining sorted order.

See also binary_search, binary_search_by_key, and partition_point.

§Examples

Looks up a series of four elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in [1, 4].

let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];

let seek = 13;
assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
let seek = 4;
assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
let seek = 100;
assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
let seek = 1;
let r = s.binary_search_by(|probe| probe.cmp(&seek));
assert!(match r { Ok(1..=4) => true, _ => false, });
1.10.0 · Source

pub fn binary_search_by_key<'a, B, F>( &'a self, b: &B, f: F, ) -> Result<usize, usize>
where F: FnMut(&'a T) -> B, B: Ord,

Binary searches this slice with a key extraction function.

Assumes that the slice is sorted by the key, for instance with sort_by_key using the same key extraction function. If the slice is not sorted by the key, the returned result is unspecified and meaningless.

If the value is found then Result::Ok is returned, containing the index of the matching element. If there are multiple matches, then any one of the matches could be returned. The index is chosen deterministically, but is subject to change in future versions of Rust. If the value is not found then Result::Err is returned, containing the index where a matching element could be inserted while maintaining sorted order.

See also binary_search, binary_search_by, and partition_point.

§Examples

Looks up a series of four elements in a slice of pairs sorted by their second elements. The first is found, with a uniquely determined position; the second and third are not found; the fourth could match any position in [1, 4].

let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
         (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
         (1, 21), (2, 34), (4, 55)];

assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b),  Ok(9));
assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b),   Err(7));
assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
let r = s.binary_search_by_key(&1, |&(a, b)| b);
assert!(match r { Ok(1..=4) => true, _ => false, });
1.30.0 · Source

pub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])

Transmutes the slice to a slice of another type, ensuring alignment of the types is maintained.

This method splits the slice into three distinct slices: prefix, correctly aligned middle slice of a new type, and the suffix slice. The middle part will be as big as possible under the given alignment constraint and element size.

This method has no purpose when either input element T or output element U are zero-sized and will return the original slice without splitting anything.

§Safety

This method is essentially a transmute with respect to the elements in the returned middle slice, so all the usual caveats pertaining to transmute::<T, U> also apply here.

§Examples

Basic usage:

unsafe {
    let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
    let (prefix, shorts, suffix) = bytes.align_to::<u16>();
    // less_efficient_algorithm_for_bytes(prefix);
    // more_efficient_algorithm_for_aligned_shorts(shorts);
    // less_efficient_algorithm_for_bytes(suffix);
}
Source

pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
where Simd<T, LANES>: AsRef<[T; LANES]>, T: SimdElement,

🔬This is a nightly-only experimental API. (portable_simd)

Splits a slice into a prefix, a middle of aligned SIMD types, and a suffix.

This is a safe wrapper around slice::align_to, so inherits the same guarantees as that method.

§Panics

This will panic if the size of the SIMD type is different from LANES times that of the scalar.

At the time of writing, the trait restrictions on Simd<T, LANES> keeps that from ever happening, as only power-of-two numbers of lanes are supported. It’s possible that, in the future, those restrictions might be lifted in a way that would make it possible to see panics from this method for something like LANES == 3.

§Examples
#![feature(portable_simd)]
use core::simd::prelude::*;

let short = &[1, 2, 3];
let (prefix, middle, suffix) = short.as_simd::<4>();
assert_eq!(middle, []); // Not enough elements for anything in the middle

// They might be split in any possible way between prefix and suffix
let it = prefix.iter().chain(suffix).copied();
assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);

fn basic_simd_sum(x: &[f32]) -> f32 {
    use std::ops::Add;
    let (prefix, middle, suffix) = x.as_simd();
    let sums = f32x4::from_array([
        prefix.iter().copied().sum(),
        0.0,
        0.0,
        suffix.iter().copied().sum(),
    ]);
    let sums = middle.iter().copied().fold(sums, f32x4::add);
    sums.reduce_sum()
}

let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
1.82.0 · Source

pub fn is_sorted(&self) -> bool
where T: PartialOrd,

Checks if the elements of this slice are sorted.

That is, for each element a and its following element b, a <= b must hold. If the slice yields exactly zero or one element, true is returned.

Note that if Self::Item is only PartialOrd, but not Ord, the above definition implies that this function returns false if any two consecutive items are not comparable.

§Examples
let empty: [i32; 0] = [];

assert!([1, 2, 2, 9].is_sorted());
assert!(![1, 3, 2, 4].is_sorted());
assert!([0].is_sorted());
assert!(empty.is_sorted());
assert!(![0.0, 1.0, f32::NAN].is_sorted());
1.82.0 · Source

pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool
where F: FnMut(&'a T, &'a T) -> bool,

Checks if the elements of this slice are sorted using the given comparator function.

Instead of using PartialOrd::partial_cmp, this function uses the given compare function to determine whether two elements are to be considered in sorted order.

§Examples
assert!([1, 2, 2, 9].is_sorted_by(|a, b| a <= b));
assert!(![1, 2, 2, 9].is_sorted_by(|a, b| a < b));

assert!([0].is_sorted_by(|a, b| true));
assert!([0].is_sorted_by(|a, b| false));

let empty: [i32; 0] = [];
assert!(empty.is_sorted_by(|a, b| false));
assert!(empty.is_sorted_by(|a, b| true));
1.82.0 · Source

pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
where F: FnMut(&'a T) -> K, K: PartialOrd,

Checks if the elements of this slice are sorted using the given key extraction function.

Instead of comparing the slice’s elements directly, this function compares the keys of the elements, as determined by f. Apart from that, it’s equivalent to is_sorted; see its documentation for more information.

§Examples
assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
1.52.0 · Source

pub fn partition_point<P>(&self, pred: P) -> usize
where P: FnMut(&T) -> bool,

Returns the index of the partition point according to the given predicate (the index of the first element of the second partition).

The slice is assumed to be partitioned according to the given predicate. This means that all elements for which the predicate returns true are at the start of the slice and all elements for which the predicate returns false are at the end. For example, [7, 15, 3, 5, 4, 12, 6] is partitioned under the predicate x % 2 != 0 (all odd numbers are at the start, all even at the end).

If this slice is not partitioned, the returned result is unspecified and meaningless, as this method performs a kind of binary search.

See also binary_search, binary_search_by, and binary_search_by_key.

§Examples
let v = [1, 2, 3, 3, 5, 6, 7];
let i = v.partition_point(|&x| x < 5);

assert_eq!(i, 4);
assert!(v[..i].iter().all(|&x| x < 5));
assert!(v[i..].iter().all(|&x| !(x < 5)));

If all elements of the slice match the predicate, including if the slice is empty, then the length of the slice will be returned:

let a = [2, 4, 8];
assert_eq!(a.partition_point(|x| x < &100), a.len());
let a: [i32; 0] = [];
assert_eq!(a.partition_point(|x| x < &100), 0);

If you want to insert an item to a sorted vector, while maintaining sort order:

let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
let num = 42;
let idx = s.partition_point(|&x| x <= num);
s.insert(idx, num);
assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
1.94.0 · Source

pub fn element_offset(&self, element: &T) -> Option<usize>

Returns the index that an element reference points to.

Returns None if element does not point to the start of an element within the slice.

This method is useful for extending slice iterators like slice::split.

Note that this uses pointer arithmetic and does not compare elements. To find the index of an element via comparison, use .iter().position() instead.

§Panics

Panics if T is zero-sized.

§Examples

Basic usage:

let nums: &[u32] = &[1, 7, 1, 1];
let num = &nums[2];

assert_eq!(num, &1);
assert_eq!(nums.element_offset(num), Some(2));

Returning None with an unaligned element:

let arr: &[[u32; 2]] = &[[0, 1], [2, 3]];
let flat_arr: &[u32] = arr.as_flattened();

let ok_elm: &[u32; 2] = flat_arr[0..2].try_into().unwrap();
let weird_elm: &[u32; 2] = flat_arr[1..3].try_into().unwrap();

assert_eq!(ok_elm, &[0, 1]);
assert_eq!(weird_elm, &[1, 2]);

assert_eq!(arr.element_offset(ok_elm), Some(0)); // Points to element 0
assert_eq!(arr.element_offset(weird_elm), None); // Points between element 0 and 1
1.98.0 · Source

pub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>>

Returns the range of indices that a subslice points to.

Returns None if subslice does not point within the slice or if it is not aligned with the elements in the slice.

This method does not compare elements. Instead, this method finds the location in the slice that subslice was obtained from. To find the index of a subslice via comparison, instead use .windows().position().

This method is useful for extending slice iterators like slice::split.

Note that this may return a false positive (either Some(0..0) or Some(self.len()..self.len())) if subslice has a length of zero and points to the beginning or end of another, separate, slice.

§Panics

Panics if T is zero-sized.

§Examples

Basic usage:

use core::range::Range;

let nums = &[0, 5, 10, 0, 0, 5];

let mut iter = nums
    .split(|t| *t == 0)
    .map(|n| nums.subslice_range(n).unwrap());

assert_eq!(iter.next(), Some(Range { start: 0, end: 0 }));
assert_eq!(iter.next(), Some(Range { start: 1, end: 3 }));
assert_eq!(iter.next(), Some(Range { start: 4, end: 4 }));
assert_eq!(iter.next(), Some(Range { start: 5, end: 6 }));
Source

pub fn as_slice(&self) -> &[T]

🔬This is a nightly-only experimental API. (str_as_str)

Returns the same slice &[T].

This method is redundant when used directly on &[T], but it helps dereferencing other “container” types to slices, for example Box<[T]> or Arc<[T]>.

1.0.0 · Source

pub fn to_vec(&self) -> Vec<T>
where T: Clone,

Available on non-no_global_oom_handling only.

Copies self into a new Vec.

§Examples
let s = [10, 40, 30];
let x = s.to_vec();
// Here, `s` and `x` can be modified independently.
Examples found in repository?
examples/3d/occlusion_culling.rs (line 591)
559fn readback_indirect_parameters(
560    mut indirect_parameters_staging_buffers: ResMut<IndirectParametersStagingBuffers>,
561    saved_indirect_parameters: Res<SavedIndirectParameters>,
562) {
563    // If culling isn't supported on this platform, bail.
564    if !saved_indirect_parameters
565        .lock()
566        .unwrap()
567        .as_ref()
568        .unwrap()
569        .occlusion_culling_supported
570    {
571        return;
572    }
573
574    // Grab the staging buffers.
575    let (Some(data_buffer), Some(batch_sets_buffer)) = (
576        indirect_parameters_staging_buffers.data.take(),
577        indirect_parameters_staging_buffers.batch_sets.take(),
578    ) else {
579        return;
580    };
581
582    // Read the GPU buffers back.
583    let saved_indirect_parameters_0 = (**saved_indirect_parameters).clone();
584    let saved_indirect_parameters_1 = (**saved_indirect_parameters).clone();
585    readback_buffer::<IndirectParametersIndexed>(data_buffer, move |indirect_parameters| {
586        saved_indirect_parameters_0
587            .lock()
588            .unwrap()
589            .as_mut()
590            .unwrap()
591            .data = indirect_parameters.to_vec();
592    });
593    readback_buffer::<u32>(batch_sets_buffer, move |indirect_parameters_count| {
594        saved_indirect_parameters_1
595            .lock()
596            .unwrap()
597            .as_mut()
598            .unwrap()
599            .count = indirect_parameters_count[0];
600    });
601}
More examples
Hide additional examples
examples/shader_advanced/texture_binding_array.rs (line 198)
165    fn bind_group_layout_entries(_: &RenderDevice, _: bool) -> Vec<BindGroupLayoutEntry>
166    where
167        Self: Sized,
168    {
169        BindGroupLayoutEntries::with_indices(
170            // The layout entries will only be visible in the fragment stage
171            ShaderStages::FRAGMENT,
172            (
173                // Screen texture
174                //
175                // @group(#{MATERIAL_BIND_GROUP}) @binding(0) var textures: binding_array<texture_2d<f32>>;
176                (
177                    0,
178                    texture_2d(TextureSampleType::Float { filterable: true })
179                        .count(NonZero::<u32>::new(MAX_TEXTURE_COUNT as u32).unwrap()),
180                ),
181                // Sampler
182                //
183                // @group(#{MATERIAL_BIND_GROUP}) @binding(1) var nearest_sampler: sampler;
184                //
185                // Note: as with textures, multiple samplers can also be bound
186                // onto one binding slot:
187                //
188                // ```
189                // sampler(SamplerBindingType::Filtering)
190                //     .count(NonZero::<u32>::new(MAX_TEXTURE_COUNT as u32).unwrap()),
191                // ```
192                //
193                // One may need to pay attention to the limit of sampler binding
194                // amount on some platforms.
195                (1, sampler(SamplerBindingType::Filtering)),
196            ),
197        )
198        .to_vec()
199    }
examples/math/render_primitives.rs (line 456)
430fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
431    const POSITION: Vec2 = Vec2::new(-LEFT_RIGHT_OFFSET_2D, 0.0);
432    let angle = time.elapsed_secs();
433    let isometry = Isometry2d::new(POSITION, Rot2::radians(angle));
434    let color = Color::WHITE;
435
436    #[expect(
437        clippy::match_same_arms,
438        reason = "Certain primitives don't have any 2D rendering support yet."
439    )]
440    match state.get() {
441        PrimitiveSelected::RectangleAndCuboid => {
442            gizmos.primitive_2d(&RECTANGLE, isometry, color);
443        }
444        PrimitiveSelected::CircleAndSphere => {
445            gizmos.primitive_2d(&CIRCLE, isometry, color);
446        }
447        PrimitiveSelected::Ellipse => drop(gizmos.primitive_2d(&ELLIPSE, isometry, color)),
448        PrimitiveSelected::Triangle => gizmos.primitive_2d(&TRIANGLE_2D, isometry, color),
449        PrimitiveSelected::Plane => gizmos.primitive_2d(&PLANE_2D, isometry, color),
450        PrimitiveSelected::Line => drop(gizmos.primitive_2d(&LINE_2D, isometry, color)),
451        PrimitiveSelected::Segment => {
452            drop(gizmos.primitive_2d(&SEGMENT_2D, isometry, color));
453        }
454        PrimitiveSelected::Polyline => gizmos.primitive_2d(
455            &Polyline2d {
456                vertices: POLYLINE_2D_VERTICES.to_vec(),
457            },
458            isometry,
459            color,
460        ),
461        PrimitiveSelected::ConvexPolygon => gizmos.primitive_2d(
462            &Polygon::from(ConvexPolygon::new(CONVEX_POLYGON_VERTICES).unwrap()),
463            isometry,
464            color,
465        ),
466        PrimitiveSelected::Polygon => gizmos.primitive_2d(
467            &Polygon {
468                vertices: vec![
469                    Vec2::new(-BIG_2D, -SMALL_2D),
470                    Vec2::new(BIG_2D, -SMALL_2D),
471                    Vec2::new(BIG_2D, SMALL_2D),
472                    Vec2::new(0.0, 0.0),
473                    Vec2::new(-BIG_2D, SMALL_2D),
474                ],
475            },
476            isometry,
477            color,
478        ),
479        PrimitiveSelected::RegularPolygon => {
480            gizmos.primitive_2d(&REGULAR_POLYGON, isometry, color);
481        }
482        PrimitiveSelected::Capsule => gizmos.primitive_2d(&CAPSULE_2D, isometry, color),
483        PrimitiveSelected::Cylinder => {}
484        PrimitiveSelected::Cone => {}
485        PrimitiveSelected::ConicalFrustum => {}
486        PrimitiveSelected::Torus => drop(gizmos.primitive_2d(&ANNULUS, isometry, color)),
487        PrimitiveSelected::Tetrahedron => {}
488        PrimitiveSelected::Arc => gizmos.primitive_2d(&ARC, isometry, color),
489        PrimitiveSelected::CircularSector => {
490            gizmos.primitive_2d(&CIRCULAR_SECTOR, isometry, color);
491        }
492        PrimitiveSelected::CircularSegment => {
493            gizmos.primitive_2d(&CIRCULAR_SEGMENT, isometry, color);
494        }
495    }
496}
497
498/// Marker for primitive meshes to record in which state they should be visible in
499#[derive(Debug, Clone, Component, Default, Reflect)]
500pub struct PrimitiveData {
501    camera_mode: CameraActive,
502    primitive_state: PrimitiveSelected,
503}
504
505/// Marker for meshes of 2D primitives
506#[derive(Debug, Clone, Component, Default)]
507pub struct MeshDim2;
508
509/// Marker for meshes of 3D primitives
510#[derive(Debug, Clone, Component, Default)]
511pub struct MeshDim3;
512
513fn spawn_primitive_2d(
514    mut commands: Commands,
515    mut materials: ResMut<Assets<ColorMaterial>>,
516    mut meshes: ResMut<Assets<Mesh>>,
517) {
518    const POSITION: Vec3 = Vec3::new(LEFT_RIGHT_OFFSET_2D, 0.0, 0.0);
519    let material: Handle<ColorMaterial> = materials.add(Color::WHITE);
520    let camera_mode = CameraActive::Dim2;
521    let polyline_2d = Polyline2d {
522        vertices: POLYLINE_2D_VERTICES.to_vec(),
523    };
524    let convex_polygon = ConvexPolygon::new(CONVEX_POLYGON_VERTICES).unwrap();
525    [
526        Some(RECTANGLE.mesh().build()),
527        Some(CIRCLE.mesh().build()),
528        Some(ELLIPSE.mesh().build()),
529        Some(TRIANGLE_2D.mesh().build()),
530        None, // plane
531        None, // line
532        Some(SEGMENT_2D.mesh().build()),
533        Some(polyline_2d.mesh().build()),
534        None, // polygon
535        Some(convex_polygon.mesh().build()),
536        Some(REGULAR_POLYGON.mesh().build()),
537        Some(CAPSULE_2D.mesh().build()),
538        None, // cylinder
539        None, // cone
540        None, // conical frustum
541        Some(ANNULUS.mesh().build()),
542        None, // tetrahedron
543        None, // arc
544        Some(CIRCULAR_SECTOR.mesh().build()),
545        Some(CIRCULAR_SEGMENT.mesh().build()),
546    ]
547    .into_iter()
548    .zip(PrimitiveSelected::ALL)
549    .for_each(|(maybe_mesh, state)| {
550        if let Some(mesh) = maybe_mesh {
551            commands.spawn((
552                MeshDim2,
553                PrimitiveData {
554                    camera_mode,
555                    primitive_state: state,
556                },
557                Mesh2d(meshes.add(mesh)),
558                MeshMaterial2d(material.clone()),
559                Transform::from_translation(POSITION),
560            ));
561        }
562    });
563}
564
565fn spawn_primitive_3d(
566    mut commands: Commands,
567    mut materials: ResMut<Assets<StandardMaterial>>,
568    mut meshes: ResMut<Assets<Mesh>>,
569) {
570    const POSITION: Vec3 = Vec3::new(-LEFT_RIGHT_OFFSET_3D, 0.0, 0.0);
571    let material: Handle<StandardMaterial> = materials.add(Color::WHITE);
572    let camera_mode = CameraActive::Dim3;
573    let polyline_3d = Polyline3d {
574        vertices: POLYLINE_3D_VERTICES.to_vec(),
575    };
576    [
577        Some(CUBOID.mesh().build()),
578        Some(SPHERE.mesh().build()),
579        None, // ellipse
580        Some(TRIANGLE_3D.mesh().build()),
581        Some(PLANE_3D.mesh().build()),
582        None, // line
583        Some(SEGMENT_3D.mesh().build()),
584        Some(polyline_3d.mesh().build()),
585        None, // polygon
586        None, // convex polygon
587        None, // regular polygon
588        Some(CAPSULE_3D.mesh().build()),
589        Some(CYLINDER.mesh().build()),
590        Some(CONE.mesh().build()),
591        Some(CONICAL_FRUSTUM.mesh().build()),
592        Some(TORUS.mesh().build()),
593        Some(TETRAHEDRON.mesh().build()),
594        None, // arc
595        None, // circular sector
596        None, // circular segment
597    ]
598    .into_iter()
599    .zip(PrimitiveSelected::ALL)
600    .for_each(|(maybe_mesh, state)| {
601        if let Some(mesh) = maybe_mesh {
602            commands.spawn((
603                MeshDim3,
604                PrimitiveData {
605                    camera_mode,
606                    primitive_state: state,
607                },
608                Mesh3d(meshes.add(mesh)),
609                MeshMaterial3d(material.clone()),
610                Transform::from_translation(POSITION),
611            ));
612        }
613    });
614}
615
616fn update_primitive_meshes(
617    camera_state: Res<State<CameraActive>>,
618    primitive_state: Res<State<PrimitiveSelected>>,
619    mut primitives: Query<(&mut Visibility, &PrimitiveData)>,
620) {
621    primitives.iter_mut().for_each(|(mut vis, primitive)| {
622        let visible = primitive.camera_mode == *camera_state.get()
623            && primitive.primitive_state == *primitive_state.get();
624        *vis = if visible {
625            Visibility::Inherited
626        } else {
627            Visibility::Hidden
628        };
629    });
630}
631
632fn rotate_primitive_2d_meshes(
633    mut primitives_2d: Query<
634        (&mut Transform, &ViewVisibility),
635        (With<PrimitiveData>, With<MeshDim2>),
636    >,
637    time: Res<Time>,
638) {
639    let rotation_2d = Quat::from_mat3(&Mat3::from_angle(time.elapsed_secs()));
640    primitives_2d
641        .iter_mut()
642        .filter(|(_, vis)| vis.get())
643        .for_each(|(mut transform, _)| {
644            transform.rotation = rotation_2d;
645        });
646}
647
648fn rotate_primitive_3d_meshes(
649    mut primitives_3d: Query<
650        (&mut Transform, &ViewVisibility),
651        (With<PrimitiveData>, With<MeshDim3>),
652    >,
653    time: Res<Time>,
654) {
655    let rotation_3d = Quat::from_rotation_arc(
656        Vec3::Z,
657        Vec3::new(
658            ops::sin(time.elapsed_secs()),
659            ops::cos(time.elapsed_secs()),
660            ops::sin(time.elapsed_secs()) * 0.5,
661        )
662        .try_normalize()
663        .unwrap_or(Vec3::Z),
664    );
665    primitives_3d
666        .iter_mut()
667        .filter(|(_, vis)| vis.get())
668        .for_each(|(mut transform, _)| {
669            transform.rotation = rotation_3d;
670        });
671}
672
673fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
674    const POSITION: Vec3 = Vec3::new(LEFT_RIGHT_OFFSET_3D, 0.0, 0.0);
675    let rotation = Quat::from_rotation_arc(
676        Vec3::Z,
677        Vec3::new(
678            ops::sin(time.elapsed_secs()),
679            ops::cos(time.elapsed_secs()),
680            ops::sin(time.elapsed_secs()) * 0.5,
681        )
682        .try_normalize()
683        .unwrap_or(Vec3::Z),
684    );
685    let isometry = Isometry3d::new(POSITION, rotation);
686    let color = Color::WHITE;
687    let resolution = 10;
688
689    #[expect(
690        clippy::match_same_arms,
691        reason = "Certain primitives don't have any 3D rendering support yet."
692    )]
693    match state.get() {
694        PrimitiveSelected::RectangleAndCuboid => {
695            gizmos.primitive_3d(&CUBOID, isometry, color);
696        }
697        PrimitiveSelected::CircleAndSphere => drop(
698            gizmos
699                .primitive_3d(&SPHERE, isometry, color)
700                .resolution(resolution),
701        ),
702        PrimitiveSelected::Ellipse => {}
703        PrimitiveSelected::Triangle => gizmos.primitive_3d(&TRIANGLE_3D, isometry, color),
704        PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, isometry, color)),
705        PrimitiveSelected::Line => gizmos.primitive_3d(&LINE_3D, isometry, color),
706        PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, isometry, color),
707        PrimitiveSelected::Polyline => gizmos.primitive_3d(
708            &Polyline3d {
709                vertices: POLYLINE_3D_VERTICES.to_vec(),
710            },
711            isometry,
712            color,
713        ),
714        PrimitiveSelected::Polygon => {}
715        PrimitiveSelected::ConvexPolygon => {}
716        PrimitiveSelected::RegularPolygon => {}
717        PrimitiveSelected::Capsule => drop(
718            gizmos
719                .primitive_3d(&CAPSULE_3D, isometry, color)
720                .resolution(resolution),
721        ),
722        PrimitiveSelected::Cylinder => drop(
723            gizmos
724                .primitive_3d(&CYLINDER, isometry, color)
725                .resolution(resolution),
726        ),
727        PrimitiveSelected::Cone => drop(
728            gizmos
729                .primitive_3d(&CONE, isometry, color)
730                .resolution(resolution),
731        ),
732        PrimitiveSelected::ConicalFrustum => {
733            gizmos.primitive_3d(&CONICAL_FRUSTUM, isometry, color);
734        }
735
736        PrimitiveSelected::Torus => drop(
737            gizmos
738                .primitive_3d(&TORUS, isometry, color)
739                .minor_resolution(resolution)
740                .major_resolution(resolution),
741        ),
742        PrimitiveSelected::Tetrahedron => {
743            gizmos.primitive_3d(&TETRAHEDRON, isometry, color);
744        }
745
746        PrimitiveSelected::Arc => {}
747        PrimitiveSelected::CircularSector => {}
748        PrimitiveSelected::CircularSegment => {}
749    }
750}
examples/app/headless_renderer.rs (line 439)
378fn receive_image_from_buffer(
379    image_copiers: Res<ImageCopiers>,
380    render_device: Res<RenderDevice>,
381    sender: Res<RenderWorldSender>,
382) {
383    for image_copier in image_copiers.0.iter() {
384        if !image_copier.enabled() {
385            continue;
386        }
387
388        // Finally time to get our data back from the gpu.
389        // First we get a buffer slice which represents a chunk of the buffer (which we
390        // can't access yet).
391        // We want the whole thing so use unbounded range.
392        let buffer_slice = image_copier.buffer.slice(..);
393
394        // Now things get complicated. WebGPU, for safety reasons, only allows either the GPU
395        // or CPU to access a buffer's contents at a time. We need to "map" the buffer which means
396        // flipping ownership of the buffer over to the CPU and making access legal. We do this
397        // with `BufferSlice::map_async`.
398        //
399        // The problem is that map_async is not an async function so we can't await it. What
400        // we need to do instead is pass in a closure that will be executed when the slice is
401        // either mapped or the mapping has failed.
402        //
403        // The problem with this is that we don't have a reliable way to wait in the main
404        // code for the buffer to be mapped and even worse, calling get_mapped_range or
405        // get_mapped_range_mut prematurely will cause a panic, not return an error.
406        //
407        // Using channels solves this as awaiting the receiving of a message from
408        // the passed closure will force the outside code to wait. It also doesn't hurt
409        // if the closure finishes before the outside code catches up as the message is
410        // buffered and receiving will just pick that up.
411        //
412        // It may also be worth noting that although on native, the usage of asynchronous
413        // channels is wholly unnecessary, for the sake of portability to Wasm
414        // we'll use async channels that work on both native and Wasm.
415
416        let (s, r) = crossbeam_channel::bounded(1);
417
418        // Maps the buffer so it can be read on the cpu
419        buffer_slice.map_async(MapMode::Read, move |r| match r {
420            // This will execute once the gpu is ready, so after the call to poll()
421            Ok(r) => s.send(r).expect("Failed to send map update"),
422            Err(err) => panic!("Failed to map buffer {err}"),
423        });
424
425        // In order for the mapping to be completed, one of three things must happen.
426        // One of those can be calling `Device::poll`. This isn't necessary on the web as devices
427        // are polled automatically but natively, we need to make sure this happens manually.
428        // `Maintain::Wait` will cause the thread to wait on native but not on WebGpu.
429
430        // This blocks until the gpu is done executing everything
431        render_device
432            .poll(PollType::wait_indefinitely())
433            .expect("Failed to poll device for map async");
434
435        // This blocks until the buffer is mapped
436        r.recv().expect("Failed to receive the map_async message");
437
438        // This could fail on app exit, if Main world clears resources (including receiver) while Render world still renders
439        let _ = sender.send(buffer_slice.get_mapped_range().unwrap().to_vec());
440
441        // We need to make sure all `BufferView`'s are dropped before we do what we're about
442        // to do.
443        // Unmap so that we can copy to the staging buffer in the next iteration.
444        image_copier.buffer.unmap();
445    }
446}
examples/ecs/dynamic.rs (line 208)
69fn main() {
70    let mut world = World::new();
71    let mut lines = std::io::stdin().lines();
72    let mut component_names = HashMap::<String, ComponentId>::new();
73    let mut component_info = HashMap::<ComponentId, ComponentInfo>::new();
74    let mut event_names = HashMap::<String, EventKey>::new();
75
76    println!("{PROMPT}");
77    loop {
78        print!("\n> ");
79        let _ = std::io::stdout().flush();
80        let Some(Ok(line)) = lines.next() else {
81            return;
82        };
83
84        if line.is_empty() {
85            return;
86        };
87
88        let Some((first, rest)) = line.trim().split_once(|c: char| c.is_whitespace()) else {
89            match &line.chars().next() {
90                Some('c') => println!("{COMPONENT_PROMPT}"),
91                Some('s') => println!("{ENTITY_PROMPT}"),
92                Some('q') => println!("{QUERY_PROMPT}"),
93                Some('e') => println!("{EVENT_PROMPT}"),
94                Some('t') => println!("{EMIT_PROMPT}"),
95                _ => println!("{PROMPT}"),
96            }
97            continue;
98        };
99
100        match &first[0..1] {
101            "c" => {
102                rest.split(',').for_each(|component| {
103                    let mut component = component.split_whitespace();
104                    let Some(name) = component.next() else {
105                        return;
106                    };
107                    let size = match component.next().map(str::parse) {
108                        Some(Ok(size)) => size,
109                        _ => 0,
110                    };
111                    // Register our new component to the world with a layout specified by its size
112                    // SAFETY: [u64] is Send + Sync
113                    let id = world.register_component_with_descriptor(unsafe {
114                        ComponentDescriptor::new_with_layout(
115                            name.to_string(),
116                            StorageType::Table,
117                            Layout::array::<u64>(size).unwrap(),
118                            None,
119                            true,
120                            false,
121                            ComponentCloneBehavior::Default,
122                            None,
123                        )
124                    });
125                    let Some(info) = world.components().get_info(id) else {
126                        return;
127                    };
128                    component_names.insert(name.to_string(), id);
129                    component_info.insert(id, info.clone());
130                    println!("Component {} created with id: {}", name, id.index());
131                });
132            }
133            "s" => {
134                let mut to_insert_ids = Vec::new();
135                let mut to_insert_data = Vec::new();
136                rest.split(',').for_each(|component| {
137                    let mut component = component.split_whitespace();
138                    let Some(name) = component.next() else {
139                        return;
140                    };
141
142                    // Get the id for the component with the given name
143                    let Some(&id) = component_names.get(name) else {
144                        println!("Component {name} does not exist");
145                        return;
146                    };
147
148                    // Calculate the length for the array based on the layout created for this component id
149                    let info = world.components().get_info(id).unwrap();
150                    let len = info.layout().size() / size_of::<u64>();
151                    let mut values: Vec<u64> = component
152                        .take(len)
153                        .filter_map(|value| value.parse::<u64>().ok())
154                        .collect();
155                    values.resize(len, 0);
156
157                    // Collect the id and array to be inserted onto our entity
158                    to_insert_ids.push(id);
159                    to_insert_data.push(values);
160                });
161
162                let mut entity = world.spawn_empty();
163
164                // Construct an `OwningPtr` for each component in `to_insert_data`
165                let to_insert_ptr = to_owning_ptrs(&mut to_insert_data);
166
167                // SAFETY:
168                // - Component ids have been taken from the same world
169                // - Each array is created to the layout specified in the world
170                unsafe {
171                    entity.insert_by_ids(&to_insert_ids, to_insert_ptr.into_iter());
172                }
173
174                println!("Entity spawned with id: {}", entity.id());
175            }
176            "q" => {
177                let mut builder = QueryBuilder::<FilteredEntityMut>::new(&mut world);
178                parse_query(rest, &mut builder, &component_names);
179                let mut query = builder.build();
180                query.iter_mut(&mut world).for_each(|filtered_entity| {
181                    let terms = filtered_entity
182                        .access()
183                        .try_iter_access()
184                        .unwrap()
185                        .map(|component_access| {
186                            let id = *component_access.index();
187                            let ptr = filtered_entity.get_by_id(id).unwrap();
188                            let info = component_info.get(&id).unwrap();
189                            let len = info.layout().size() / size_of::<u64>();
190
191                            // SAFETY:
192                            // - All components are created with layout [u64]
193                            // - len is calculated from the component descriptor
194                            let data = unsafe {
195                                std::slice::from_raw_parts_mut(
196                                    ptr.assert_unique().as_ptr().cast::<u64>(),
197                                    len,
198                                )
199                            };
200
201                            // If we have write access, increment each value once
202                            if matches!(component_access, ComponentAccessKind::Exclusive(_)) {
203                                data.iter_mut().for_each(|data| {
204                                    *data += 1;
205                                });
206                            }
207
208                            format!("{}: {:?}", info.name(), data[0..len].to_vec())
209                        })
210                        .collect::<Vec<_>>()
211                        .join(", ");
212
213                    println!("{}: {}", filtered_entity.id(), terms);
214                });
215            }
216            "e" => {
217                rest.split(',').for_each(|event| {
218                    let name = event.trim();
219                    if name.is_empty() {
220                        return;
221                    }
222
223                    // Register a ComponentId for this event, no Rust type needed.
224                    // SAFETY: ZST with no drop
225                    let event_component_id = world.register_component_with_descriptor(unsafe {
226                        ComponentDescriptor::new_with_layout(
227                            format!("event:{name}"),
228                            StorageType::Table,
229                            Layout::new::<()>(),
230                            None,
231                            false,
232                            false,
233                            ComponentCloneBehavior::Ignore,
234                            None,
235                        )
236                    });
237                    // SAFETY: event_component_id was just registered for this event
238                    let event_key = unsafe { EventKey::new(event_component_id) };
239                    event_names.insert(name.to_string(), event_key);
240
241                    // Build a dynamic observer that prints when the event fires.
242                    let runner: ObserverRunner = |mut world, _observer, ctx, _event, _trigger| {
243                        println!("  Observer fired!");
244                        if let Some(mut counts) = world.get_resource_mut::<EventFireCount>() {
245                            *counts.0.entry(ctx.event_key).or_insert(0) += 1;
246                        }
247                    };
248
249                    // SAFETY: event_key was just registered, runner ignores pointers
250                    let observer =
251                        unsafe { Observer::with_dynamic_runner(runner).with_event_key(event_key) };
252                    world.spawn(observer);
253
254                    println!(
255                        "Event '{name}' registered (key: {}) with a dynamic observer",
256                        event_component_id.index()
257                    );
258                });
259
260                // Ensure the counter resource exists.
261                world.init_resource::<EventFireCount>();
262            }
263            "t" => {
264                let name = rest.trim();
265                let Some(&event_key) = event_names.get(name) else {
266                    println!(
267                        "Event '{name}' does not exist. Register it first with 'event {name}'"
268                    );
269                    continue;
270                };
271
272                let mut event_data = ();
273                let mut trigger_data = ();
274                // SAFETY: event_key was registered in this world, both pointers are valid ZSTs
275                unsafe {
276                    world.trigger_dynamic(
277                        event_key,
278                        PtrMut::from(&mut event_data),
279                        PtrMut::from(&mut trigger_data),
280                    );
281                }
282
283                let count = world
284                    .get_resource::<EventFireCount>()
285                    .map_or(0, |c| c.0.get(&event_key).copied().unwrap_or(0));
286                println!("Event '{name}' triggered ({count} fires)");
287            }
288            _ => continue,
289        }
290    }
291}
Source

pub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A>
where A: Allocator, T: Clone,

🔬This is a nightly-only experimental API. (allocator_ext)
Available on non-no_global_oom_handling only.

Copies self into a new Vec with an allocator.

§Examples
#![feature(allocator_ext)]

use std::alloc::System;

let s = [10, 40, 30];
let x = s.to_vec_in(System);
// Here, `s` and `x` can be modified independently.
1.40.0 · Source

pub fn repeat(&self, n: usize) -> Vec<T>
where T: Copy,

Available on non-no_global_oom_handling only.

Creates a vector by copying a slice n times.

§Panics

This function will panic if the capacity would overflow.

§Examples
assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);

A panic upon overflow:

ⓘ
// this will panic at runtime
b"0123456789abcdef".repeat(usize::MAX);
1.0.0 · Source

pub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output ⓘ
where [T]: Concat<Item>, Item: ?Sized,

Flattens a slice of T into a single value Self::Output.

§Examples
assert_eq!(["hello", "world"].concat(), "helloworld");
assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
1.3.0 · Source

pub fn join<Separator>( &self, sep: Separator, ) -> <[T] as Join<Separator>>::Output ⓘ
where [T]: Join<Separator>,

Flattens a slice of T into a single value Self::Output, placing a given separator between each.

§Examples
assert_eq!(["hello", "world"].join(" "), "hello world");
assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
Examples found in repository?
examples/gltf/load_gltf_extras.rs (line 89)
52fn check_for_gltf_extras(
53    gltf_extras_per_entity: Query<(
54        Entity,
55        Option<&Name>,
56        Option<&GltfSceneExtras>,
57        Option<&GltfExtras>,
58        Option<&GltfMeshExtras>,
59        Option<&GltfMaterialExtras>,
60    )>,
61    mut display: Single<&mut Text, With<ExampleDisplay>>,
62) {
63    let mut gltf_extra_infos_lines: Vec<String> = vec![];
64
65    for (id, name, scene_extras, extras, mesh_extras, material_extras) in
66        gltf_extras_per_entity.iter()
67    {
68        if scene_extras.is_some()
69            || extras.is_some()
70            || mesh_extras.is_some()
71            || material_extras.is_some()
72        {
73            let formatted_extras = format!(
74                "Extras per entity {} ('Name: {}'):
75    - scene extras:     {:?}
76    - primitive extras: {:?}
77    - mesh extras:      {:?}
78    - material extras:  {:?}
79                ",
80                id,
81                name.unwrap_or(&Name::default()),
82                scene_extras,
83                extras,
84                mesh_extras,
85                material_extras
86            );
87            gltf_extra_infos_lines.push(formatted_extras);
88        }
89        display.0 = gltf_extra_infos_lines.join("\n");
90    }
91}
More examples
Hide additional examples
examples/ecs/relationships.rs (line 97)
78    fn debug_relationships(
79        // Not all of our entities are targeted by something, so we use `Option` in our query to handle this case.
80        relations_query: Query<(&Name, &Targeting, Option<&TargetedBy>)>,
81        name_query: Query<&Name>,
82    ) {
83        let mut relationships = String::new();
84
85        for (name, targeting, maybe_targeted_by) in relations_query.iter() {
86            let targeting_name = name_query.get(targeting.0).unwrap();
87            let targeted_by_string = if let Some(targeted_by) = maybe_targeted_by {
88                let mut vec_of_names = Vec::<&Name>::new();
89
90                for entity in targeted_by.iter() {
91                    let name = name_query.get(entity).unwrap();
92                    vec_of_names.push(name);
93                }
94
95                // Convert this to a nice string for printing.
96                let vec_of_str: Vec<&str> = vec_of_names.iter().map(|name| name.as_str()).collect();
97                vec_of_str.join(", ")
98            } else {
99                "nobody".to_string()
100            };
101
102            relationships.push_str(&format!(
103                "{name} is targeting {targeting_name}, and is targeted by {targeted_by_string}\n",
104            ));
105        }
106
107        println!("{relationships}");
108    }
examples/testbed/ui.rs (line 937)
887    pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
888        commands.spawn((Camera2d, DespawnOnExit(super::Scene::FontLists)));
889        commands.insert_resource(LoadedFontAssets {
890            _handles: FONT_ASSETS
891                .iter()
892                .map(|font_asset| asset_server.load(*font_asset))
893                .collect(),
894        });
895        commands.spawn((
896            Node {
897                flex_direction: FlexDirection::Column,
898                align_self: AlignSelf::Center,
899                justify_self: JustifySelf::Center,
900                row_gap: px(25),
901                ..default()
902            },
903            DespawnOnExit(super::Scene::FontLists),
904            children![
905                (
906                    Text::new("Font Lists"),
907                    TextFont::from_font_size(FontSize::Px(32.)),
908                    Underline,
909                ),
910                (
911                    Node {
912                        flex_direction: FlexDirection::Column,
913                        row_gap: px(6),
914                        ..default()
915                    },
916                    children![
917                        Text::new("FontSource::Families"),
918                        (
919                            Node {
920                                flex_direction: FlexDirection::Row,
921                                flex_wrap: FlexWrap::Wrap,
922                                padding: px(16).left(),
923                                column_gap: px(30),
924                                row_gap: px(30),
925                                ..default()
926                            },
927                            Children::spawn(SpawnIter(
928                                (0..FONT_NAMES.len())
929                                    .map(|start| {
930                                        FONT_NAMES
931                                            .iter()
932                                            .copied()
933                                            .cycle()
934                                            .skip(start)
935                                            .take(FONT_NAMES.len())
936                                            .collect::<Vec<_>>()
937                                            .join(", ")
938                                    })
939                                    .map(|list| {
940                                        (
941                                            Text::new(list.replace(", ", "\n")),
942                                            TextFont {
943                                                font: FontSource::families(list),
944                                                font_size: FontSize::Px(16.),
945                                                ..default()
946                                            },
947                                            Node {
948                                                padding: px(4.).all(),
949                                                ..default()
950                                            },
951                                            TextLayout::no_wrap(),
952                                            Outline::default(),
953                                        )
954                                    }),
955                            )),
956                        )
957                    ]
958                ),
959                (
960                    Node {
961                        flex_direction: FlexDirection::Column,
962                        row_gap: px(6),
963                        ..default()
964                    },
965                    children![
966                        Text::new("FontSource::List"),
967                        (
968                            Node {
969                                flex_direction: FlexDirection::Row,
970                                flex_wrap: FlexWrap::Wrap,
971                                padding: px(16).left(),
972                                column_gap: px(30),
973                                row_gap: px(30),
974                                ..default()
975                            },
976                            Children::spawn(SpawnIter(
977                                (0..FONT_NAMES.len())
978                                    .map(|start| {
979                                        FONT_NAMES
980                                            .iter()
981                                            .copied()
982                                            .cycle()
983                                            .skip(start)
984                                            .take(FONT_NAMES.len())
985                                            .collect::<Vec<_>>()
986                                    })
987                                    .map(|list| {
988                                        (
989                                            Text::new(list.join("\n")),
990                                            TextFont {
991                                                font: FontSource::list(list.iter().copied()),
992                                                font_size: FontSize::Px(16.),
993                                                ..default()
994                                            },
995                                            Node {
996                                                padding: px(4.).all(),
997                                                ..default()
998                                            },
999                                            TextLayout::no_wrap(),
1000                                            Outline::default(),
1001                                        )
1002                                    }),
1003                            )),
1004                        )
1005                    ]
1006                ),
1007            ],
1008        ));
1009    }
examples/ecs/dynamic.rs (line 211)
69fn main() {
70    let mut world = World::new();
71    let mut lines = std::io::stdin().lines();
72    let mut component_names = HashMap::<String, ComponentId>::new();
73    let mut component_info = HashMap::<ComponentId, ComponentInfo>::new();
74    let mut event_names = HashMap::<String, EventKey>::new();
75
76    println!("{PROMPT}");
77    loop {
78        print!("\n> ");
79        let _ = std::io::stdout().flush();
80        let Some(Ok(line)) = lines.next() else {
81            return;
82        };
83
84        if line.is_empty() {
85            return;
86        };
87
88        let Some((first, rest)) = line.trim().split_once(|c: char| c.is_whitespace()) else {
89            match &line.chars().next() {
90                Some('c') => println!("{COMPONENT_PROMPT}"),
91                Some('s') => println!("{ENTITY_PROMPT}"),
92                Some('q') => println!("{QUERY_PROMPT}"),
93                Some('e') => println!("{EVENT_PROMPT}"),
94                Some('t') => println!("{EMIT_PROMPT}"),
95                _ => println!("{PROMPT}"),
96            }
97            continue;
98        };
99
100        match &first[0..1] {
101            "c" => {
102                rest.split(',').for_each(|component| {
103                    let mut component = component.split_whitespace();
104                    let Some(name) = component.next() else {
105                        return;
106                    };
107                    let size = match component.next().map(str::parse) {
108                        Some(Ok(size)) => size,
109                        _ => 0,
110                    };
111                    // Register our new component to the world with a layout specified by its size
112                    // SAFETY: [u64] is Send + Sync
113                    let id = world.register_component_with_descriptor(unsafe {
114                        ComponentDescriptor::new_with_layout(
115                            name.to_string(),
116                            StorageType::Table,
117                            Layout::array::<u64>(size).unwrap(),
118                            None,
119                            true,
120                            false,
121                            ComponentCloneBehavior::Default,
122                            None,
123                        )
124                    });
125                    let Some(info) = world.components().get_info(id) else {
126                        return;
127                    };
128                    component_names.insert(name.to_string(), id);
129                    component_info.insert(id, info.clone());
130                    println!("Component {} created with id: {}", name, id.index());
131                });
132            }
133            "s" => {
134                let mut to_insert_ids = Vec::new();
135                let mut to_insert_data = Vec::new();
136                rest.split(',').for_each(|component| {
137                    let mut component = component.split_whitespace();
138                    let Some(name) = component.next() else {
139                        return;
140                    };
141
142                    // Get the id for the component with the given name
143                    let Some(&id) = component_names.get(name) else {
144                        println!("Component {name} does not exist");
145                        return;
146                    };
147
148                    // Calculate the length for the array based on the layout created for this component id
149                    let info = world.components().get_info(id).unwrap();
150                    let len = info.layout().size() / size_of::<u64>();
151                    let mut values: Vec<u64> = component
152                        .take(len)
153                        .filter_map(|value| value.parse::<u64>().ok())
154                        .collect();
155                    values.resize(len, 0);
156
157                    // Collect the id and array to be inserted onto our entity
158                    to_insert_ids.push(id);
159                    to_insert_data.push(values);
160                });
161
162                let mut entity = world.spawn_empty();
163
164                // Construct an `OwningPtr` for each component in `to_insert_data`
165                let to_insert_ptr = to_owning_ptrs(&mut to_insert_data);
166
167                // SAFETY:
168                // - Component ids have been taken from the same world
169                // - Each array is created to the layout specified in the world
170                unsafe {
171                    entity.insert_by_ids(&to_insert_ids, to_insert_ptr.into_iter());
172                }
173
174                println!("Entity spawned with id: {}", entity.id());
175            }
176            "q" => {
177                let mut builder = QueryBuilder::<FilteredEntityMut>::new(&mut world);
178                parse_query(rest, &mut builder, &component_names);
179                let mut query = builder.build();
180                query.iter_mut(&mut world).for_each(|filtered_entity| {
181                    let terms = filtered_entity
182                        .access()
183                        .try_iter_access()
184                        .unwrap()
185                        .map(|component_access| {
186                            let id = *component_access.index();
187                            let ptr = filtered_entity.get_by_id(id).unwrap();
188                            let info = component_info.get(&id).unwrap();
189                            let len = info.layout().size() / size_of::<u64>();
190
191                            // SAFETY:
192                            // - All components are created with layout [u64]
193                            // - len is calculated from the component descriptor
194                            let data = unsafe {
195                                std::slice::from_raw_parts_mut(
196                                    ptr.assert_unique().as_ptr().cast::<u64>(),
197                                    len,
198                                )
199                            };
200
201                            // If we have write access, increment each value once
202                            if matches!(component_access, ComponentAccessKind::Exclusive(_)) {
203                                data.iter_mut().for_each(|data| {
204                                    *data += 1;
205                                });
206                            }
207
208                            format!("{}: {:?}", info.name(), data[0..len].to_vec())
209                        })
210                        .collect::<Vec<_>>()
211                        .join(", ");
212
213                    println!("{}: {}", filtered_entity.id(), terms);
214                });
215            }
216            "e" => {
217                rest.split(',').for_each(|event| {
218                    let name = event.trim();
219                    if name.is_empty() {
220                        return;
221                    }
222
223                    // Register a ComponentId for this event, no Rust type needed.
224                    // SAFETY: ZST with no drop
225                    let event_component_id = world.register_component_with_descriptor(unsafe {
226                        ComponentDescriptor::new_with_layout(
227                            format!("event:{name}"),
228                            StorageType::Table,
229                            Layout::new::<()>(),
230                            None,
231                            false,
232                            false,
233                            ComponentCloneBehavior::Ignore,
234                            None,
235                        )
236                    });
237                    // SAFETY: event_component_id was just registered for this event
238                    let event_key = unsafe { EventKey::new(event_component_id) };
239                    event_names.insert(name.to_string(), event_key);
240
241                    // Build a dynamic observer that prints when the event fires.
242                    let runner: ObserverRunner = |mut world, _observer, ctx, _event, _trigger| {
243                        println!("  Observer fired!");
244                        if let Some(mut counts) = world.get_resource_mut::<EventFireCount>() {
245                            *counts.0.entry(ctx.event_key).or_insert(0) += 1;
246                        }
247                    };
248
249                    // SAFETY: event_key was just registered, runner ignores pointers
250                    let observer =
251                        unsafe { Observer::with_dynamic_runner(runner).with_event_key(event_key) };
252                    world.spawn(observer);
253
254                    println!(
255                        "Event '{name}' registered (key: {}) with a dynamic observer",
256                        event_component_id.index()
257                    );
258                });
259
260                // Ensure the counter resource exists.
261                world.init_resource::<EventFireCount>();
262            }
263            "t" => {
264                let name = rest.trim();
265                let Some(&event_key) = event_names.get(name) else {
266                    println!(
267                        "Event '{name}' does not exist. Register it first with 'event {name}'"
268                    );
269                    continue;
270                };
271
272                let mut event_data = ();
273                let mut trigger_data = ();
274                // SAFETY: event_key was registered in this world, both pointers are valid ZSTs
275                unsafe {
276                    world.trigger_dynamic(
277                        event_key,
278                        PtrMut::from(&mut event_data),
279                        PtrMut::from(&mut trigger_data),
280                    );
281                }
282
283                let count = world
284                    .get_resource::<EventFireCount>()
285                    .map_or(0, |c| c.0.get(&event_key).copied().unwrap_or(0));
286                println!("Event '{name}' triggered ({count} fires)");
287            }
288            _ => continue,
289        }
290    }
291}
1.0.0 · Source

pub fn connect<Separator>( &self, sep: Separator, ) -> <[T] as Join<Separator>>::Output ⓘ
where [T]: Join<Separator>,

👎Deprecated since 1.3.0:

renamed to join

Flattens a slice of T into a single value Self::Output, placing a given separator between each.

§Examples
assert_eq!(["hello", "world"].connect(" "), "hello world");
assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);

Trait Implementations§

Source§

impl<'b, const N: usize> Deref for BindGroupEntries<'b, N>

Source§

type Target = [BindGroupEntry<'b>]

The resulting type after dereferencing.
Source§

fn deref(&self) -> &[BindGroupEntry<'b>]

Dereferences the value.

Auto Trait Implementations§

§

impl<'b, const N: usize = 1> !RefUnwindSafe for BindGroupEntries<'b, N>

§

impl<'b, const N: usize = 1> !UnwindSafe for BindGroupEntries<'b, N>

§

impl<'b, const N: usize> Freeze for BindGroupEntries<'b, N>
where [BindGroupEntry<'b>; N]: Freeze,

§

impl<'b, const N: usize> Send for BindGroupEntries<'b, N>
where [BindGroupEntry<'b>; N]: Send,

§

impl<'b, const N: usize> Sync for BindGroupEntries<'b, N>
where [BindGroupEntry<'b>; N]: Sync,

§

impl<'b, const N: usize> Unpin for BindGroupEntries<'b, N>
where [BindGroupEntry<'b>; N]: Unpin,

§

impl<'b, const N: usize> UnsafeUnpin for BindGroupEntries<'b, N>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

Source§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ConditionalSend for T
where T: Send,

Source§

impl<T> Conv for T

Source§

fn conv<T>(self) -> T
where Self: Into<T>,

Converts self into T using Into<T>. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Converts Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Converts Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Converts &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Converts &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSend for T
where T: Any + Send,

Source§

fn into_any_send(self: Box<T>) -> Box<dyn Any + Send>

Converts Box<Trait> (where Trait: DowncastSend) to Box<dyn Any + Send>, which can then be downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> FmtForward for T

Source§

fn fmt_binary(self) -> FmtBinary<Self>
where Self: Binary,

Causes self to use its Binary implementation when Debug-formatted.
Source§

fn fmt_display(self) -> FmtDisplay<Self>
where Self: Display,

Causes self to use its Display implementation when Debug-formatted.
Source§

fn fmt_lower_exp(self) -> FmtLowerExp<Self>
where Self: LowerExp,

Causes self to use its LowerExp implementation when Debug-formatted.
Source§

fn fmt_lower_hex(self) -> FmtLowerHex<Self>
where Self: LowerHex,

Causes self to use its LowerHex implementation when Debug-formatted.
Source§

fn fmt_octal(self) -> FmtOctal<Self>
where Self: Octal,

Causes self to use its Octal implementation when Debug-formatted.
Source§

fn fmt_pointer(self) -> FmtPointer<Self>
where Self: Pointer,

Causes self to use its Pointer implementation when Debug-formatted.
Source§

fn fmt_upper_exp(self) -> FmtUpperExp<Self>
where Self: UpperExp,

Causes self to use its UpperExp implementation when Debug-formatted.
Source§

fn fmt_upper_hex(self) -> FmtUpperHex<Self>
where Self: UpperHex,

Causes self to use its UpperHex implementation when Debug-formatted.
Source§

fn fmt_list(self) -> FmtList<Self>
where &'a Self: for<'a> IntoIterator,

Formats each item in a sequence. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, W> HasTypeWitness<W> for T
where W: MakeTypeWitness<Arg = T>, T: ?Sized,

Source§

const WITNESS: W = W::MAKE

A constant of the type witness
Source§

impl<T> Identity for T
where T: ?Sized,

Source§

const TYPE_EQ: TypeEq<T, <T as Identity>::Type> = TypeEq::NEW

Proof that Self is the same type as Self::Type, provides methods for casting between Self and Self::Type.
Source§

type Type = T

The same type as Self, used to emulate type equality bounds (T == U) with associated type equality constraints (T: Identity<Type = U>).
Source§

impl<T> InitializeFromFunction<T> for T

Source§

fn initialize_from_function(f: fn() -> T) -> T

Create an instance of this type from an initialization function
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoResult<T> for T

Source§

fn into_result(self) -> Result<T, RunSystemError>

Converts this type into the system output type.
Source§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

Source§

fn into_sample(self) -> T

Source§

impl<A> Is for A
where A: Any,

Source§

fn is<T>() -> bool
where T: Any,

Checks if the current type “is” another type, using a TypeId equality comparison. This is most useful in the context of generic logic. Read more
Source§

impl<T> Pipe for T
where T: ?Sized,

Source§

fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> R
where Self: Sized,

Pipes by value. This is generally the method you want to use. Read more
Source§

fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> R
where R: 'a,

Borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> R
where R: 'a,

Mutably borrows self and passes that borrow into the pipe function. Read more
Source§

fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
where Self: Borrow<B>, B: 'a + ?Sized, R: 'a,

Borrows self, then passes self.borrow() into the pipe function. Read more
Source§

fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
where Self: BorrowMut<B>, B: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.borrow_mut() into the pipe function. Read more
Source§

fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
where Self: AsRef<U>, U: 'a + ?Sized, R: 'a,

Borrows self, then passes self.as_ref() into the pipe function.
Source§

fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
where Self: AsMut<U>, U: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.as_mut() into the pipe function.
Source§

fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
where Self: Deref<Target = T>, T: 'a + ?Sized, R: 'a,

Borrows self, then passes self.deref() into the pipe function.
Source§

fn pipe_deref_mut<'a, T, R>( &'a mut self, func: impl FnOnce(&'a mut T) -> R, ) -> R
where Self: DerefMut<Target = T> + Deref, T: 'a + ?Sized, R: 'a,

Mutably borrows self, then passes self.deref_mut() into the pipe function.
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Settings for T
where T: 'static + Send + Sync,

Source§

impl<Ret> SpawnIfAsync<(), Ret> for Ret

Source§

fn spawn(self) -> Ret

Spawn the value into the dioxus runtime if it is an async block
Source§

impl<T, O> SuperFrom<T> for O
where O: From<T>,

Source§

fn super_from(input: T) -> O

Convert from a type to another type.
Source§

impl<T, O, M> SuperInto<O, M> for T
where O: SuperFrom<T, M>,

Source§

fn super_into(self) -> O

Convert from a type to another type.
Source§

impl<T> Tap for T

Source§

fn tap(self, func: impl FnOnce(&Self)) -> Self

Immutable access to a value. Read more
Source§

fn tap_mut(self, func: impl FnOnce(&mut Self)) -> Self

Mutable access to a value. Read more
Source§

fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Immutable access to the Borrow<B> of a value. Read more
Source§

fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Mutable access to the BorrowMut<B> of a value. Read more
Source§

fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Immutable access to the AsRef<R> view of a value. Read more
Source§

fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Mutable access to the AsMut<R> view of a value. Read more
Source§

fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Immutable access to the Deref::Target of a value. Read more
Source§

fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Mutable access to the Deref::Target of a value. Read more
Source§

fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self

Calls .tap() only in debug builds, and is erased in release builds.
Source§

fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self

Calls .tap_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
where Self: Borrow<B>, B: ?Sized,

Calls .tap_borrow() only in debug builds, and is erased in release builds.
Source§

fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
where Self: BorrowMut<B>, B: ?Sized,

Calls .tap_borrow_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
where Self: AsRef<R>, R: ?Sized,

Calls .tap_ref() only in debug builds, and is erased in release builds.
Source§

fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
where Self: AsMut<R>, R: ?Sized,

Calls .tap_ref_mut() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
where Self: Deref<Target = T>, T: ?Sized,

Calls .tap_deref() only in debug builds, and is erased in release builds.
Source§

fn tap_deref_mut_dbg<T>(self, func: impl FnOnce(&mut T)) -> Self
where Self: DerefMut<Target = T> + Deref, T: ?Sized,

Calls .tap_deref_mut() only in debug builds, and is erased in release builds.
Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T> TryConv for T

Source§

fn try_conv<T>(self) -> Result<T, Self::Error>
where Self: TryInto<T>,

Attempts to convert self into T using TryInto<T>. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more