pub struct SelectionModifier<G: GaussianPod, M: Modifier<G>> {
pub selection_expr: SelectionExpr,
pub selection_buffer: SelectionBuffer,
pub selection: SelectionBundle<G>,
pub modifier: M,
}Expand description
A struct to handle custom selection and custom modifier together.
§Overview
This modifier holdes a SelectionBundle and a Modifier along with necessary
buffers, and applies the selection followed by the basic modifier in order.
The Modifier can use the SelectionModifier::selection_buffer to determine which
Gaussians to modify.
§Usage
You can supply your own selection bundles and modifier when creating a
SelectionModifier.
The creation expects a modifier factory function instead of a modifier, so that the modifier can be created with a reference to the selection buffer.
// Create an editor that holds the buffers for the Gaussians and will apply the modifier
let editor = Editor::new(
&device,
&vec![core::Gaussian {
rot: Quat::IDENTITY,
pos: Vec3::ZERO,
color: U8Vec4::ZERO,
sh: [Vec3::ZERO; 15],
scale: Vec3::ONE,
}],
);
// Create your selection bundles
let selection_bundles = vec![
// The built-in sphere selection bundle as example
SelectionBundle::<GaussianPod>::create_sphere_bundle(&device),
];
struct MyCustomModifier(core::ComputeBundle);
impl MyCustomModifier {
pub fn new(
device: &wgpu::Device,
// My buffers,
selection: &SelectionBuffer,
) -> Self {
// Build your compute bundle here,
// and include the selection buffer to only modify selected Gaussians
let compute_bundle = core::ComputeBundleBuilder::new()
// Configure the modifier compute bundle here
.build(
&device,
[
[selection.buffer().as_entire_binding()].to_vec(),
[/* Your buffers */].to_vec(),
],
)
.unwrap();
Self(compute_bundle)
}
}
impl Modifier<GaussianPod> for MyCustomModifier {
fn apply(
&self,
_device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &core::GaussiansBuffer<GaussianPod>,
_model_transform: &core::ModelTransformBuffer,
_gaussian_transform: &core::GaussianTransformBuffer,
) {
self.0.dispatch(encoder, gaussians.len() as u32);
}
}
let selection_modifier = SelectionModifier::new(
&device,
&editor.gaussians_buffer,
selection_bundles,
|selection_buffer| {
// The factory closure
MyCustomModifier::new(
&device,
// Your buffers,
selection_buffer,
)
},
);Alternatively, you can use a modifier closure instead of a struct (but be reminded this could harm readability of your code).
let selection_modifier = SelectionModifier::new(
&device,
&editor.gaussians_buffer,
selection_bundles,
|selection_buffer| {
// The factory closure
// Build your compute bundle here,
// and include the selection buffer to only modify selected Gaussians
let modifier_bundle = core::ComputeBundleBuilder::new()
.build(
&device,
[
[selection_buffer.buffer().as_entire_binding()].to_vec(),
[/* Your buffers */].to_vec(),
],
)
.unwrap();
// This function signature has blanket impl of the modifier trait
move |_device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &core::GaussiansBuffer<GaussianPod>,
_model_transform: &core::ModelTransformBuffer,
_gaussian_transform: &core::GaussianTransformBuffer| {
modifier_bundle.dispatch(encoder, gaussians.len() as u32);
}
},
);Fields§
§selection_expr: SelectionExpr§selection_buffer: SelectionBuffer§selection: SelectionBundle<G>§modifier: MImplementations§
Source§impl<G: GaussianPod, M: Modifier<G>> SelectionModifier<G, M>
impl<G: GaussianPod, M: Modifier<G>> SelectionModifier<G, M>
Sourcepub fn new(
device: &Device,
gaussians_buffer: &GaussiansBuffer<G>,
selection_bundles: Vec<ComputeBundle<()>>,
modifier: impl FnOnce(&SelectionBuffer) -> M,
) -> Self
pub fn new( device: &Device, gaussians_buffer: &GaussiansBuffer<G>, selection_bundles: Vec<ComputeBundle<()>>, modifier: impl FnOnce(&SelectionBuffer) -> M, ) -> Self
Create a new selection modifier.
bundles are used for SelectionExpr::Unary, SelectionExpr::Binary, or
SelectionExpr::Selection, they must have the same bind group 0 as the
SelectionBundle::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR, see documentation of
SelectionBundle for more details.
Examples found in repository?
68async fn main() {
69 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
70
71 let args = Args::parse();
72 let model_path = &args.model;
73 let pos = Vec3::from_slice(&args.pos);
74 let radius = args.radius;
75
76 log::debug!("Creating wgpu instance");
77 let instance =
78 wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
79
80 log::debug!("Requesting adapter");
81 let adapter = instance
82 .request_adapter(&wgpu::RequestAdapterOptions::default())
83 .await
84 .expect("adapter");
85
86 log::debug!("Requesting device");
87 let (device, queue) = adapter
88 .request_device(&wgpu::DeviceDescriptor {
89 label: Some("Device"),
90 required_limits: adapter.limits(),
91 ..Default::default()
92 })
93 .await
94 .expect("device");
95
96 log::debug!("Creating gaussians");
97 let gaussians = [
98 gs::core::GaussiansSource::Ply,
99 gs::core::GaussiansSource::Spz,
100 ]
101 .into_iter()
102 .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
103 .expect("gaussians");
104
105 log::debug!("Creating editor");
106 let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
107
108 log::debug!("Creating buffers");
109 let pos_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
110 label: Some("Position Buffer"),
111 contents: bytemuck::bytes_of(&pos),
112 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
113 });
114
115 let radius_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
116 label: Some("Radius Buffer"),
117 contents: bytemuck::bytes_of(&radius),
118 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
119 });
120
121 const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
122 wgpu::BindGroupLayoutDescriptor {
123 label: Some("Bind Group Layout"),
124 entries: &[
125 // Position uniform buffer
126 wgpu::BindGroupLayoutEntry {
127 binding: 0,
128 visibility: wgpu::ShaderStages::COMPUTE,
129 ty: wgpu::BindingType::Buffer {
130 ty: wgpu::BufferBindingType::Uniform,
131 has_dynamic_offset: false,
132 min_binding_size: None,
133 },
134 count: None,
135 },
136 // Radius uniform buffer
137 wgpu::BindGroupLayoutEntry {
138 binding: 1,
139 visibility: wgpu::ShaderStages::COMPUTE,
140 ty: wgpu::BindingType::Buffer {
141 ty: wgpu::BufferBindingType::Uniform,
142 has_dynamic_offset: false,
143 min_binding_size: None,
144 },
145 count: None,
146 },
147 // Selection buffer (only in modifier pipeline)
148 wgpu::BindGroupLayoutEntry {
149 binding: 2,
150 visibility: wgpu::ShaderStages::COMPUTE,
151 ty: wgpu::BindingType::Buffer {
152 ty: wgpu::BufferBindingType::Storage { read_only: true },
153 has_dynamic_offset: false,
154 min_binding_size: None,
155 },
156 count: None,
157 },
158 ],
159 };
160
161 log::debug!("Creating cylinder selection compute bundle");
162 let cylinder_selection_bundle = gs::core::ComputeBundleBuilder::new()
163 .label("Selection")
164 .bind_group_layouts([
165 &gs::SelectionBundle::<GaussianPod>::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
166 &wgpu::BindGroupLayoutDescriptor {
167 entries: &BIND_GROUP_LAYOUT_DESCRIPTOR.entries[..2],
168 ..BIND_GROUP_LAYOUT_DESCRIPTOR
169 },
170 ])
171 .main_shader("package::selection".parse().unwrap())
172 .entry_point("main")
173 .wesl_compile_options(wesl::CompileOptions {
174 features: GaussianPod::wesl_features(),
175 ..Default::default()
176 })
177 .resolver({
178 let mut resolver =
179 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
180 resolver.add_package(&gs::core::shader::PACKAGE);
181 resolver
182 })
183 .build_without_bind_groups(&device)
184 .map_err(|e| log::error!("{e}"))
185 .expect("selection bundle");
186
187 log::debug!("Creating custom modifier");
188 #[allow(dead_code)]
189 let modifier_factory = |selection_buffer: &gs::SelectionBuffer| /* -> impl gs::Modifier<GaussianPod> */ {
190 log::debug!("Creating custom modifier compute bundle");
191 let modifier_bundle = gs::core::ComputeBundleBuilder::new()
192 .label("Modifier")
193 .bind_group_layouts([
194 &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
195 &BIND_GROUP_LAYOUT_DESCRIPTOR,
196 ])
197 .resolver({
198 let mut resolver =
199 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
200 resolver.add_package(&gs::core::shader::PACKAGE);
201 resolver.add_package(&gs::shader::PACKAGE);
202 resolver
203 })
204 .main_shader("package::modifier".parse().unwrap())
205 .entry_point("main")
206 .wesl_compile_options(wesl::CompileOptions {
207 features: GaussianPod::wesl_features(),
208 ..Default::default()
209 })
210 .build(
211 &device,
212 [
213 vec![
214 editor.gaussians_buffer.buffer().as_entire_binding(),
215 editor.model_transform_buffer.buffer().as_entire_binding(),
216 editor
217 .gaussian_transform_buffer
218 .buffer()
219 .as_entire_binding(),
220 ],
221 vec![
222 pos_buffer.as_entire_binding(),
223 radius_buffer.as_entire_binding(),
224 selection_buffer.buffer().as_entire_binding(),
225 ],
226 ],
227 )
228 .map_err(|e| log::error!("{e}"))
229 .expect("modifier bundle");
230
231 // This is a modifier closure because this function signature has blanket impl of the modifier trait
232 move |_device: &wgpu::Device,
233 encoder: &mut wgpu::CommandEncoder,
234 gaussians: &gs::core::GaussiansBuffer<GaussianPod>,
235 _model_transform: &gs::core::ModelTransformBuffer,
236 _gaussian_transform: &gs::core::GaussianTransformBuffer| {
237 modifier_bundle.dispatch(encoder, gaussians.len() as u32);
238 }
239 };
240
241 #[allow(dead_code)]
242 struct Modifier<G: gs::core::GaussianPod>(gs::core::ComputeBundle, std::marker::PhantomData<G>);
243
244 impl<G: gs::core::GaussianPod> Modifier<G> {
245 #[allow(dead_code)]
246 fn new(
247 device: &wgpu::Device,
248 editor: &gs::Editor<G>,
249 pos_buffer: &wgpu::Buffer,
250 radius_buffer: &wgpu::Buffer,
251 selection_buffer: &gs::SelectionBuffer,
252 ) -> Self {
253 log::debug!("Creating custom modifier compute bundle");
254 let modifier_bundle = gs::core::ComputeBundleBuilder::new()
255 .label("Modifier")
256 .bind_group_layouts([
257 &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
258 &BIND_GROUP_LAYOUT_DESCRIPTOR,
259 ])
260 .resolver({
261 let mut resolver =
262 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
263 resolver.add_package(&gs::core::shader::PACKAGE);
264 resolver.add_package(&gs::shader::PACKAGE);
265 resolver
266 })
267 .main_shader("package::modifier".parse().unwrap())
268 .entry_point("main")
269 .wesl_compile_options(wesl::CompileOptions {
270 features: GaussianPod::wesl_features(),
271 ..Default::default()
272 })
273 .build(
274 device,
275 [
276 vec![
277 editor.gaussians_buffer.buffer().as_entire_binding(),
278 editor.model_transform_buffer.buffer().as_entire_binding(),
279 editor
280 .gaussian_transform_buffer
281 .buffer()
282 .as_entire_binding(),
283 ],
284 vec![
285 pos_buffer.as_entire_binding(),
286 radius_buffer.as_entire_binding(),
287 selection_buffer.buffer().as_entire_binding(),
288 ],
289 ],
290 )
291 .map_err(|e| log::error!("{e}"))
292 .expect("modifier bundle");
293
294 Self(modifier_bundle, std::marker::PhantomData)
295 }
296 }
297
298 impl<G: gs::core::GaussianPod> gs::Modifier<G> for Modifier<G> {
299 fn apply(
300 &self,
301 _device: &wgpu::Device,
302 encoder: &mut wgpu::CommandEncoder,
303 gaussians: &gs::core::GaussiansBuffer<G>,
304 _model_transform: &gs::core::ModelTransformBuffer,
305 _gaussian_transform: &gs::core::GaussianTransformBuffer,
306 ) {
307 self.0.dispatch(encoder, gaussians.len() as u32);
308 }
309 }
310
311 log::debug!("Creating selection modifier");
312 let mut selection_modifier = gs::SelectionModifier::<GaussianPod, _>::new(
313 &device,
314 &editor.gaussians_buffer,
315 vec![cylinder_selection_bundle],
316 modifier_factory,
317 // Uncomment the following line to use modifier struct instead of closure
318 // |selection_buffer| {
319 // Modifier::new(
320 // &device,
321 // &editor,
322 // &pos_buffer,
323 // &radius_buffer,
324 // selection_buffer,
325 // )
326 // },
327 );
328
329 log::debug!("Creating selection expression");
330 selection_modifier.selection_expr = gs::SelectionExpr::selection(
331 0,
332 vec![
333 selection_modifier.selection.bundles[0]
334 .create_bind_group(
335 &device,
336 1, // index 0 is the Gaussians buffer, so we use 1,
337 [
338 pos_buffer.as_entire_binding(),
339 radius_buffer.as_entire_binding(),
340 ],
341 )
342 .expect("selection expr bind group"),
343 ],
344 );
345
346 log::info!("Starting editing process");
347 let time = std::time::Instant::now();
348
349 log::debug!("Editing Gaussians");
350 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
351 label: Some("Edit Encoder"),
352 });
353
354 editor.apply(
355 &device,
356 &mut encoder,
357 [&selection_modifier as &dyn gs::Modifier<GaussianPod>],
358 );
359
360 queue.submit(Some(encoder.finish()));
361
362 device
363 .poll(wgpu::PollType::wait_indefinitely())
364 .expect("poll");
365
366 log::info!("Editing process completed in {:?}", time.elapsed());
367
368 log::debug!("Downloading Gaussians");
369 let modified_gaussians = editor
370 .gaussians_buffer
371 .download_gaussians(&device, &queue)
372 .await
373 .map(|gs| {
374 match &args.output[args.output.len().saturating_sub(4)..] {
375 ".ply" => {
376 gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(gs.into_iter()))
377 }
378 ".spz" => {
379 gs::core::Gaussians::Spz(
380 gs::core::SpzGaussians::from_gaussians_with_options(
381 gs,
382 &gs::core::SpzGaussiansFromGaussianSliceOptions {
383 version: 2, // Version 2 is more widely supported as of now
384 ..Default::default()
385 },
386 )
387 .expect("SpzGaussians from gaussians"),
388 )
389 }
390 _ => panic!("Unsupported output file extension, expected .ply or .spz"),
391 }
392 })
393 .expect("gaussians download");
394
395 log::debug!("Writing modified Gaussians to output file");
396 modified_gaussians
397 .write_to_file(&args.output)
398 .expect("write modified Gaussians to output file");
399
400 log::info!("Modified Gaussians written to {}", args.output);
401}Source§impl<G: GaussianPod> SelectionModifier<G, BasicModifier<G, WithSelection>>
impl<G: GaussianPod> SelectionModifier<G, BasicModifier<G, WithSelection>>
Sourcepub fn new_with_basic_modifier(
device: &Device,
gaussians_buffer: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
selection_bundles: Vec<ComputeBundle<()>>,
) -> Self
pub fn new_with_basic_modifier( device: &Device, gaussians_buffer: &GaussiansBuffer<G>, model_transform: &ModelTransformBuffer, gaussian_transform: &GaussianTransformBuffer, selection_bundles: Vec<ComputeBundle<()>>, ) -> Self
Create a new selection modifier with BasicModifier.
bundles are used for SelectionExpr::Unary, SelectionExpr::Binary, or
SelectionExpr::Selection, they must have the same bind group 0 as the
SelectionBundle::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR, see documentation of
SelectionBundle for more details.
Examples found in repository?
137async fn main() {
138 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
139
140 let args = Args::parse();
141 let model_path = &args.model;
142 let pos = Vec3::from_slice(&args.pos);
143 let rot = Quat::from_slice(&args.rot);
144 let scale = Vec3::from_slice(&args.scale);
145 let shape = match args.shape {
146 Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
147 Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
148 };
149 let repeat = args.repeat;
150 let offset = Vec3::from_slice(&args.offset);
151
152 log::debug!("Creating wgpu instance");
153 let instance =
154 wgpu::Instance::new(wgpu::InstanceDescriptor::new_without_display_handle_from_env());
155
156 log::debug!("Requesting adapter");
157 let adapter = instance
158 .request_adapter(&wgpu::RequestAdapterOptions::default())
159 .await
160 .expect("adapter");
161
162 log::debug!("Requesting device");
163 let (device, queue) = adapter
164 .request_device(&wgpu::DeviceDescriptor {
165 label: Some("Device"),
166 required_limits: adapter.limits(),
167 ..Default::default()
168 })
169 .await
170 .expect("device");
171
172 log::debug!("Creating gaussians");
173 let gaussians = [
174 gs::core::GaussiansSource::Ply,
175 gs::core::GaussiansSource::Spz,
176 ]
177 .into_iter()
178 .find_map(|source| gs::core::Gaussians::read_from_file(model_path, source).ok())
179 .expect("gaussians");
180
181 log::debug!("Creating editor");
182 let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
183
184 log::debug!("Creating shape selection compute bundle");
185 let shape_selection = shape(&device);
186
187 log::debug!("Creating basic selection modifier");
188 let mut basic_selection_modifier = gs::SelectionModifier::new_with_basic_modifier(
189 &device,
190 &editor.gaussians_buffer,
191 &editor.model_transform_buffer,
192 &editor.gaussian_transform_buffer,
193 vec![shape_selection],
194 );
195
196 log::debug!("Configuring modifiers");
197 basic_selection_modifier
198 .modifier
199 .basic_color_modifiers_buffer
200 .update(
201 &queue,
202 match args.override_rgb {
203 true => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_rgb_override,
204 false => gs::BasicColorRgbOverrideOrHsvModifiersPod::new_hsv_modifiers,
205 }(Vec3::from_slice(&args.rgb_or_hsv)),
206 args.alpha,
207 args.contrast,
208 args.exposure,
209 args.gamma,
210 );
211
212 log::debug!("Creating shape selection buffers");
213 let shape_selection_buffers = (0..repeat)
214 .map(|i| {
215 let offset_pos = pos + offset * i as f32;
216 let buffer = gs::InvTransformBuffer::new(&device);
217 buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
218 buffer
219 })
220 .collect::<Vec<_>>();
221
222 log::debug!("Creating shape selection bind groups");
223 let shape_selection_bind_groups = shape_selection_buffers
224 .iter()
225 .map(|buffer| {
226 basic_selection_modifier.selection.bundles[0]
227 .create_bind_group(
228 &device,
229 // index 0 is the Gaussians buffer, so we use 1,
230 // see docs of create_sphere_bundle or create_box_bundle
231 1,
232 [buffer.buffer().as_entire_binding()],
233 )
234 .expect("bind group")
235 })
236 .collect::<Vec<_>>();
237
238 log::debug!("Creating selection expression");
239 basic_selection_modifier.selection_expr = shape_selection_bind_groups.into_iter().fold(
240 gs::SelectionExpr::Identity,
241 |acc, bind_group| {
242 acc.union(gs::SelectionExpr::selection(
243 0, // the 0 here is the bundle index in the selection bundle
244 vec![bind_group],
245 ))
246 },
247 );
248
249 log::info!("Starting editing process");
250 let time = std::time::Instant::now();
251
252 log::debug!("Editing Gaussians");
253 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
254 label: Some("Edit Encoder"),
255 });
256
257 editor.apply(
258 &device,
259 &mut encoder,
260 [&basic_selection_modifier as &dyn gs::Modifier<GaussianPod>],
261 );
262
263 queue.submit(Some(encoder.finish()));
264
265 device
266 .poll(wgpu::PollType::wait_indefinitely())
267 .expect("poll");
268
269 log::info!("Editing process completed in {:?}", time.elapsed());
270
271 log::debug!("Downloading Gaussians");
272 let modified_gaussians = editor
273 .gaussians_buffer
274 .download_gaussians(&device, &queue)
275 .await
276 .map(|gs| {
277 match &args.output[args.output.len().saturating_sub(4)..] {
278 ".ply" => {
279 gs::core::Gaussians::Ply(gs::core::PlyGaussians::from_iter(gs.into_iter()))
280 }
281 ".spz" => {
282 gs::core::Gaussians::Spz(
283 gs::core::SpzGaussians::from_gaussians_with_options(
284 gs,
285 &gs::core::SpzGaussiansFromGaussianSliceOptions {
286 version: 2, // Version 2 is more widely supported as of now
287 ..Default::default()
288 },
289 )
290 .expect("SpzGaussians from gaussians"),
291 )
292 }
293 _ => panic!("Unsupported output file extension, expected .ply or .spz"),
294 }
295 })
296 .expect("gaussians download");
297
298 log::debug!("Writing modified Gaussians to output file");
299 modified_gaussians
300 .write_to_file(&args.output)
301 .expect("write modified Gaussians to output file");
302
303 log::info!("Modified Gaussians written to {}", args.output);
304}Trait Implementations§
Source§impl<G: Debug + GaussianPod, M: Debug + Modifier<G>> Debug for SelectionModifier<G, M>
impl<G: Debug + GaussianPod, M: Debug + Modifier<G>> Debug for SelectionModifier<G, M>
Source§impl<G: GaussianPod, M: Modifier<G>> Modifier<G> for SelectionModifier<G, M>
impl<G: GaussianPod, M: Modifier<G>> Modifier<G> for SelectionModifier<G, M>
Source§fn apply(
&self,
device: &Device,
encoder: &mut CommandEncoder,
gaussians: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
)
fn apply( &self, device: &Device, encoder: &mut CommandEncoder, gaussians: &GaussiansBuffer<G>, model_transform: &ModelTransformBuffer, gaussian_transform: &GaussianTransformBuffer, )
Auto Trait Implementations§
impl<G, M> Freeze for SelectionModifier<G, M>where
M: Freeze,
impl<G, M> !RefUnwindSafe for SelectionModifier<G, M>
impl<G, M> Send for SelectionModifier<G, M>where
M: Send,
impl<G, M> Sync for SelectionModifier<G, M>where
M: Sync,
impl<G, M> Unpin for SelectionModifier<G, M>
impl<G, M> UnsafeUnpin for SelectionModifier<G, M>where
M: UnsafeUnpin,
impl<G, M> !UnwindSafe for SelectionModifier<G, M>
Blanket Implementations§
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
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 more