pub struct BindGroupEntries<'b, const N: usize = 1> { /* private fields */ }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>
impl<'b, const N: usize> BindGroupEntries<'b, N>
Sourcepub fn sequential(
resources: impl IntoBindingArray<'b, N>,
) -> BindGroupEntries<'b, N>
pub fn sequential( resources: impl IntoBindingArray<'b, N>, ) -> BindGroupEntries<'b, N>
Examples found in repository?
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
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}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}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 }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}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}pub fn with_indices( indexed_resources: impl IntoIndexedBindingArray<'b, N>, ) -> BindGroupEntries<'b, N>
Source§impl<'b> BindGroupEntries<'b>
impl<'b> BindGroupEntries<'b>
pub fn single(resource: impl IntoBinding<'b>) -> [BindGroupEntry<'b>; 1]
Methods from Deref<Target = [BindGroupEntry<'b>]>§
1.0.0 · Sourcepub fn is_empty(&self) -> bool
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 · Sourcepub fn first(&self) -> Option<&T>
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 · Sourcepub fn split_first(&self) -> Option<(&T, &[T])>
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 · Sourcepub fn split_last(&self) -> Option<(&T, &[T])>
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 · Sourcepub fn last(&self) -> Option<&T>
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 · Sourcepub fn first_chunk<const N: usize>(&self) -> Option<&[T; N]>
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 · Sourcepub fn split_first_chunk<const N: usize>(&self) -> Option<(&[T; N], &[T])>
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 · Sourcepub fn split_last_chunk<const N: usize>(&self) -> Option<(&[T], &[T; N])>
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 · Sourcepub fn last_chunk<const N: usize>(&self) -> Option<&[T; N]>
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 · Sourcepub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>where
I: SliceIndex<[T]>,
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
Noneif out of bounds. - If given a range, returns the subslice corresponding to that range,
or
Noneif 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 · Sourcepub unsafe fn get_unchecked<I>(
&self,
index: I,
) -> &<I as SliceIndex<[T]>>::Outputwhere
I: SliceIndex<[T]>,
pub unsafe fn get_unchecked<I>(
&self,
index: I,
) -> &<I as SliceIndex<[T]>>::Outputwhere
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 · Sourcepub fn as_ptr(&self) -> *const T
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 · Sourcepub fn as_ptr_range(&self) -> Range<*const T> ⓘ
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 · Sourcepub fn as_array<const N: usize>(&self) -> Option<&[T; N]>
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 · Sourcepub fn iter(&self) -> Iter<'_, T> ⓘ
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 · Sourcepub fn windows(&self, size: usize) -> Windows<'_, T> ⓘ
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 · Sourcepub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> ⓘ
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 · Sourcepub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> ⓘ
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 · Sourcepub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]]
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 (akaself.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 allowed1.88.0 · Sourcepub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T])
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()equalsslice.len() / N,remainder.len()equalsslice.len() % N, andslice.len()equalschunks.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 · Sourcepub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]])
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()equalsslice.len() % N,chunks.len()equalsslice.len() / N, andslice.len()equalschunks.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 · Sourcepub fn array_windows<const N: usize>(&self) -> ArrayWindows<'_, T, N> ⓘ
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 · Sourcepub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> ⓘ
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 · Sourcepub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> ⓘ
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 · Sourcepub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F> ⓘ
pub fn chunk_by<F>(&self, pred: F) -> ChunkBy<'_, T, F> ⓘ
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 · Sourcepub fn split_at(&self, mid: usize) -> (&[T], &[T])
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 · Sourcepub unsafe fn split_at_unchecked(&self, mid: usize) -> (&[T], &[T])
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 · Sourcepub fn split_at_checked(&self, mid: usize) -> Option<(&[T], &[T])>
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 · Sourcepub fn split<F>(&self, pred: F) -> Split<'_, T, F> ⓘ
pub fn split<F>(&self, pred: F) -> Split<'_, T, F> ⓘ
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 · Sourcepub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F> ⓘ
pub fn split_inclusive<F>(&self, pred: F) -> SplitInclusive<'_, T, F> ⓘ
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 · Sourcepub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F> ⓘ
pub fn rsplit<F>(&self, pred: F) -> RSplit<'_, T, F> ⓘ
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 · Sourcepub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F> ⓘ
pub fn splitn<F>(&self, n: usize, pred: F) -> SplitN<'_, T, F> ⓘ
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 · Sourcepub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F> ⓘ
pub fn rsplitn<F>(&self, n: usize, pred: F) -> RSplitN<'_, T, F> ⓘ
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:?}");
}Sourcepub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
🔬This is a nightly-only experimental API. (slice_split_once)
pub fn split_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
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);Sourcepub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
🔬This is a nightly-only experimental API. (slice_split_once)
pub fn rsplit_once<F>(&self, pred: F) -> Option<(&[T], &[T])>
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 · Sourcepub fn contains(&self, x: &T) -> boolwhere
T: PartialEq,
pub fn contains(&self, x: &T) -> boolwhere
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 · Sourcepub fn starts_with(&self, needle: &[T]) -> boolwhere
T: PartialEq,
pub fn starts_with(&self, needle: &[T]) -> boolwhere
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 · Sourcepub fn ends_with(&self, needle: &[T]) -> boolwhere
T: PartialEq,
pub fn ends_with(&self, needle: &[T]) -> boolwhere
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 · Sourcepub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]>
pub fn strip_prefix<P>(&self, prefix: &P) -> Option<&[T]>
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 · Sourcepub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]>
pub fn strip_suffix<P>(&self, suffix: &P) -> Option<&[T]>
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 · Sourcepub fn strip_circumfix<S, P>(&self, prefix: &P, suffix: &S) -> Option<&[T]>
pub fn strip_circumfix<S, P>(&self, prefix: &P, suffix: &S) -> Option<&[T]>
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 · Sourcepub fn trim_prefix<P>(&self, prefix: &P) -> &[T]
pub fn trim_prefix<P>(&self, prefix: &P) -> &[T]
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 · Sourcepub fn trim_suffix<P>(&self, suffix: &P) -> &[T]
pub fn trim_suffix<P>(&self, suffix: &P) -> &[T]
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][..]);1.0.0 · Sourcepub fn binary_search(&self, x: &T) -> Result<usize, usize>where
T: Ord,
pub fn binary_search(&self, x: &T) -> Result<usize, usize>where
T: Ord,
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 · Sourcepub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result<usize, usize>
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 · Sourcepub fn binary_search_by_key<'a, B, F>(
&'a self,
b: &B,
f: F,
) -> Result<usize, usize>
pub fn binary_search_by_key<'a, B, F>( &'a self, b: &B, f: F, ) -> Result<usize, usize>
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 · Sourcepub unsafe fn align_to<U>(&self) -> (&[T], &[U], &[T])
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);
}Sourcepub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
🔬This is a nightly-only experimental API. (portable_simd)
pub fn as_simd<const LANES: usize>(&self) -> (&[T], &[Simd<T, LANES>], &[T])
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 · Sourcepub fn is_sorted(&self) -> boolwhere
T: PartialOrd,
pub fn is_sorted(&self) -> boolwhere
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 · Sourcepub fn is_sorted_by<'a, F>(&'a self, compare: F) -> bool
pub fn is_sorted_by<'a, F>(&'a self, compare: F) -> 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 · Sourcepub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
pub fn is_sorted_by_key<'a, F, K>(&'a self, f: F) -> bool
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 · Sourcepub fn partition_point<P>(&self, pred: P) -> usize
pub fn partition_point<P>(&self, pred: P) -> usize
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 · Sourcepub fn element_offset(&self, element: &T) -> Option<usize>
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 11.98.0 · Sourcepub fn subslice_range(&self, subslice: &[T]) -> Option<Range<usize>>
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 }));Sourcepub fn as_slice(&self) -> &[T]
🔬This is a nightly-only experimental API. (str_as_str)
pub fn as_slice(&self) -> &[T]
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 · Sourcepub fn to_vec(&self) -> Vec<T>where
T: Clone,
Available on non-no_global_oom_handling only.
pub fn to_vec(&self) -> Vec<T>where
T: Clone,
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?
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
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 }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(®ULAR_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}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}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}Sourcepub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A>
🔬This is a nightly-only experimental API. (allocator_ext)Available on non-no_global_oom_handling only.
pub fn to_vec_in<A>(&self, alloc: A) -> Vec<T, A>
allocator_ext)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 · Sourcepub fn repeat(&self, n: usize) -> Vec<T>where
T: Copy,
Available on non-no_global_oom_handling only.
pub fn repeat(&self, n: usize) -> Vec<T>where
T: Copy,
no_global_oom_handling only.1.0.0 · Sourcepub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output ⓘ
pub fn concat<Item>(&self) -> <[T] as Concat<Item>>::Output ⓘ
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 · Sourcepub fn join<Separator>(
&self,
sep: Separator,
) -> <[T] as Join<Separator>>::Output ⓘ
pub fn join<Separator>( &self, sep: Separator, ) -> <[T] as Join<Separator>>::Output ⓘ
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?
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
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 }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 }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 · Sourcepub fn connect<Separator>(
&self,
sep: Separator,
) -> <[T] as Join<Separator>>::Output ⓘ
👎Deprecated since 1.3.0: renamed to join
pub fn connect<Separator>( &self, sep: Separator, ) -> <[T] as Join<Separator>>::Output ⓘ
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>
impl<'b, const N: usize> Deref for BindGroupEntries<'b, N>
Source§type Target = [BindGroupEntry<'b>]
type Target = [BindGroupEntry<'b>]
Source§fn deref(&self) -> &[BindGroupEntry<'b>]
fn deref(&self) -> &[BindGroupEntry<'b>]
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>
impl<'b, const N: usize> Send for BindGroupEntries<'b, N>
impl<'b, const N: usize> Sync for BindGroupEntries<'b, N>
impl<'b, const N: usize> Unpin for BindGroupEntries<'b, N>
impl<'b, const N: usize> UnsafeUnpin for BindGroupEntries<'b, N>
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T ShaderType for self. When used in AsBindGroup
derives, it is safe to assume that all images in self exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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 Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
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)
fn as_any(&self) -> &(dyn Any + 'static)
&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)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&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
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
impl<S, T> Duplex<S> for Twhere
T: FromSample<S> + ToSample<S>,
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
impl<T, W> HasTypeWitness<W> for Twhere
W: MakeTypeWitness<Arg = T>,
T: ?Sized,
Source§impl<T> Identity for Twhere
T: ?Sized,
impl<T> Identity for Twhere
T: ?Sized,
Source§impl<T> InitializeFromFunction<T> for T
impl<T> InitializeFromFunction<T> for T
Source§fn initialize_from_function(f: fn() -> T) -> T
fn initialize_from_function(f: fn() -> T) -> T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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 moreSource§impl<T> IntoResult<T> for T
impl<T> IntoResult<T> for T
Source§fn into_result(self) -> Result<T, RunSystemError>
fn into_result(self) -> Result<T, RunSystemError>
Source§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
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
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
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
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Settings for T
Source§impl<Ret> SpawnIfAsync<(), Ret> for Ret
impl<Ret> SpawnIfAsync<(), Ret> for Ret
Source§impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
impl<T, O> SuperFrom<T> for Owhere
O: From<T>,
Source§fn super_from(input: T) -> O
fn super_from(input: T) -> O
Source§impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
impl<T, O, M> SuperInto<O, M> for Twhere
O: SuperFrom<T, M>,
Source§fn super_into(self) -> O
fn super_into(self) -> O
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.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
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.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
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.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
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.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
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.