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 your selection bundles
let selection_bundles = vec![
SelectionBundle::<GaussianPod>::create_sphere_bundle(&device), // The built-in sphere selection bundle as example
];
struct MyCustomModifier(ComputeBundle);
impl MyCustomModifier {
pub fn new(device: &wgpu::Device, /* Your buffers */, selection: &SelectionBuffer) -> Self {
// Build your compute bundle here,
// and include the selection buffer to only modify selected Gaussians
let compute_bundle = ComputeBundleBuilder::new().build(&device, /* Your buffers */);
Self(compute_bundle)
}
}
impl Modifier<GaussianPod> for MyCustomModifier {
fn apply(
&self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &GaussiansBuffer<GaussianPod>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
) {
self.0.dispatch(encoder, gaussians.len() as u32);
}
}
let selection_modifier = SelectionModifier::new(
&device,
&gaussians_buffer,
selection_bundles,
|selection_buffer| { // The factory closure
BasicModifier::new_with_selection(
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::<GaussianPod>::new(
&device,
&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 = ComputeBundleBuilder::new().build(&device, /* Your buffers */);
// This function signature has blanket impl of the modifier trait
move |_device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
gaussians: &gs::core::GaussiansBuffer<GaussianPod>,
_model_transform: &gs::core::ModelTransformBuffer,
_gaussian_transform: &gs::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?
53async fn main() {
54 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
55
56 let args = Args::parse();
57 let model_path = &args.model;
58 let pos = Vec3::from_slice(&args.pos);
59 let radius = args.radius;
60
61 log::debug!("Creating wgpu instance");
62 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
63
64 log::debug!("Requesting adapter");
65 let adapter = instance
66 .request_adapter(&wgpu::RequestAdapterOptions::default())
67 .await
68 .expect("adapter");
69
70 log::debug!("Requesting device");
71 let (device, queue) = adapter
72 .request_device(&wgpu::DeviceDescriptor {
73 label: Some("Device"),
74 required_features: wgpu::Features::empty(),
75 required_limits: adapter.limits(),
76 memory_hints: wgpu::MemoryHints::default(),
77 trace: wgpu::Trace::Off,
78 })
79 .await
80 .expect("device");
81
82 log::debug!("Creating gaussians");
83 let f = std::fs::File::open(model_path).expect("ply file");
84 let mut reader = std::io::BufReader::new(f);
85 let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
86
87 log::debug!("Creating editor");
88 let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
89
90 log::debug!("Creating buffers");
91 let pos_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
92 label: Some("Position Buffer"),
93 contents: bytemuck::bytes_of(&pos),
94 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
95 });
96
97 let radius_buffer = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
98 label: Some("Radius Buffer"),
99 contents: bytemuck::bytes_of(&radius),
100 usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
101 });
102
103 const BIND_GROUP_LAYOUT_DESCRIPTOR: wgpu::BindGroupLayoutDescriptor =
104 wgpu::BindGroupLayoutDescriptor {
105 label: Some("Bind Group Layout"),
106 entries: &[
107 // Position uniform buffer
108 wgpu::BindGroupLayoutEntry {
109 binding: 0,
110 visibility: wgpu::ShaderStages::COMPUTE,
111 ty: wgpu::BindingType::Buffer {
112 ty: wgpu::BufferBindingType::Uniform,
113 has_dynamic_offset: false,
114 min_binding_size: None,
115 },
116 count: None,
117 },
118 // Radius uniform buffer
119 wgpu::BindGroupLayoutEntry {
120 binding: 1,
121 visibility: wgpu::ShaderStages::COMPUTE,
122 ty: wgpu::BindingType::Buffer {
123 ty: wgpu::BufferBindingType::Uniform,
124 has_dynamic_offset: false,
125 min_binding_size: None,
126 },
127 count: None,
128 },
129 // Selection buffer (only in modifier pipeline)
130 wgpu::BindGroupLayoutEntry {
131 binding: 2,
132 visibility: wgpu::ShaderStages::COMPUTE,
133 ty: wgpu::BindingType::Buffer {
134 ty: wgpu::BufferBindingType::Storage { read_only: true },
135 has_dynamic_offset: false,
136 min_binding_size: None,
137 },
138 count: None,
139 },
140 ],
141 };
142
143 log::debug!("Creating cylinder selection compute bundle");
144 let cylinder_selection_bundle = gs::core::ComputeBundleBuilder::new()
145 .label("Selection")
146 .bind_group_layouts([
147 &gs::SelectionBundle::<GaussianPod>::GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
148 &wgpu::BindGroupLayoutDescriptor {
149 entries: &BIND_GROUP_LAYOUT_DESCRIPTOR.entries[..2],
150 ..BIND_GROUP_LAYOUT_DESCRIPTOR
151 },
152 ])
153 .main_shader("package::selection".parse().unwrap())
154 .entry_point("main")
155 .wesl_compile_options(wesl::CompileOptions {
156 features: GaussianPod::wesl_features(),
157 ..Default::default()
158 })
159 .resolver({
160 let mut resolver =
161 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
162 resolver.add_package(&gs::core::shader::PACKAGE);
163 resolver
164 })
165 .build_without_bind_groups(&device)
166 .map_err(|e| log::error!("{e}"))
167 .expect("selection bundle");
168
169 log::debug!("Creating custom modifier");
170 #[allow(dead_code)]
171 let modifier_factory = |selection_buffer: &gs::SelectionBuffer| /* -> impl gs::Modifier<GaussianPod> */ {
172 log::debug!("Creating custom modifier compute bundle");
173 let modifier_bundle = gs::core::ComputeBundleBuilder::new()
174 .label("Modifier")
175 .bind_group_layouts([
176 &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
177 &BIND_GROUP_LAYOUT_DESCRIPTOR,
178 ])
179 .resolver({
180 let mut resolver =
181 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
182 resolver.add_package(&gs::core::shader::PACKAGE);
183 resolver.add_package(&gs::shader::PACKAGE);
184 resolver
185 })
186 .main_shader("package::modifier".parse().unwrap())
187 .entry_point("main")
188 .wesl_compile_options(wesl::CompileOptions {
189 features: GaussianPod::wesl_features(),
190 ..Default::default()
191 })
192 .build(
193 &device,
194 [
195 vec![
196 editor.gaussians_buffer.buffer().as_entire_binding(),
197 editor.model_transform_buffer.buffer().as_entire_binding(),
198 editor
199 .gaussian_transform_buffer
200 .buffer()
201 .as_entire_binding(),
202 ],
203 vec![
204 pos_buffer.as_entire_binding(),
205 radius_buffer.as_entire_binding(),
206 selection_buffer.buffer().as_entire_binding(),
207 ],
208 ],
209 )
210 .map_err(|e| log::error!("{e}"))
211 .expect("modifier bundle");
212
213 // This is a modifier closure because this function signature has blanket impl of the modifier trait
214 move |_device: &wgpu::Device,
215 encoder: &mut wgpu::CommandEncoder,
216 gaussians: &gs::core::GaussiansBuffer<GaussianPod>,
217 _model_transform: &gs::core::ModelTransformBuffer,
218 _gaussian_transform: &gs::core::GaussianTransformBuffer| {
219 modifier_bundle.dispatch(encoder, gaussians.len() as u32);
220 }
221 };
222
223 #[allow(dead_code)]
224 struct Modifier<G: gs::core::GaussianPod>(gs::core::ComputeBundle, std::marker::PhantomData<G>);
225
226 impl<G: gs::core::GaussianPod> Modifier<G> {
227 #[allow(dead_code)]
228 fn new(
229 device: &wgpu::Device,
230 editor: &gs::Editor<G>,
231 pos_buffer: &wgpu::Buffer,
232 radius_buffer: &wgpu::Buffer,
233 selection_buffer: &gs::SelectionBuffer,
234 ) -> Self {
235 log::debug!("Creating custom modifier compute bundle");
236 let modifier_bundle = gs::core::ComputeBundleBuilder::new()
237 .label("Modifier")
238 .bind_group_layouts([
239 &gs::MODIFIER_GAUSSIANS_BIND_GROUP_LAYOUT_DESCRIPTOR,
240 &BIND_GROUP_LAYOUT_DESCRIPTOR,
241 ])
242 .resolver({
243 let mut resolver =
244 wesl::StandardResolver::new("examples/shader/custom_modify_selection");
245 resolver.add_package(&gs::core::shader::PACKAGE);
246 resolver.add_package(&gs::shader::PACKAGE);
247 resolver
248 })
249 .main_shader("package::modifier".parse().unwrap())
250 .entry_point("main")
251 .wesl_compile_options(wesl::CompileOptions {
252 features: GaussianPod::wesl_features(),
253 ..Default::default()
254 })
255 .build(
256 &device,
257 [
258 vec![
259 editor.gaussians_buffer.buffer().as_entire_binding(),
260 editor.model_transform_buffer.buffer().as_entire_binding(),
261 editor
262 .gaussian_transform_buffer
263 .buffer()
264 .as_entire_binding(),
265 ],
266 vec![
267 pos_buffer.as_entire_binding(),
268 radius_buffer.as_entire_binding(),
269 selection_buffer.buffer().as_entire_binding(),
270 ],
271 ],
272 )
273 .map_err(|e| log::error!("{e}"))
274 .expect("modifier bundle");
275
276 Self(modifier_bundle, std::marker::PhantomData)
277 }
278 }
279
280 impl<G: gs::core::GaussianPod> gs::Modifier<G> for Modifier<G> {
281 fn apply(
282 &self,
283 _device: &wgpu::Device,
284 encoder: &mut wgpu::CommandEncoder,
285 gaussians: &gs::core::GaussiansBuffer<G>,
286 _model_transform: &gs::core::ModelTransformBuffer,
287 _gaussian_transform: &gs::core::GaussianTransformBuffer,
288 ) {
289 self.0.dispatch(encoder, gaussians.len() as u32);
290 }
291 }
292
293 log::debug!("Creating selection modifier");
294 let mut selection_modifier = gs::SelectionModifier::<GaussianPod, _>::new(
295 &device,
296 &editor.gaussians_buffer,
297 vec![cylinder_selection_bundle],
298 modifier_factory,
299 // Uncomment the following line to use modifier struct instead of closure
300 // |selection_buffer| {
301 // Modifier::new(
302 // &device,
303 // &editor,
304 // &pos_buffer,
305 // &radius_buffer,
306 // selection_buffer,
307 // )
308 // },
309 );
310
311 log::debug!("Creating selection expression");
312 selection_modifier.selection_expr = gs::SelectionExpr::selection(
313 0,
314 vec![
315 selection_modifier.selection.bundles[0]
316 .create_bind_group(
317 &device,
318 1, // index 0 is the Gaussians buffer, so we use 1,
319 [
320 pos_buffer.as_entire_binding(),
321 radius_buffer.as_entire_binding(),
322 ],
323 )
324 .expect("selection expr bind group"),
325 ],
326 );
327
328 log::info!("Starting editing process");
329 let time = std::time::Instant::now();
330
331 log::debug!("Editing Gaussians");
332 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
333 label: Some("Edit Encoder"),
334 });
335
336 editor.apply(
337 &device,
338 &mut encoder,
339 [&selection_modifier as &dyn gs::Modifier<GaussianPod>],
340 );
341
342 queue.submit(Some(encoder.finish()));
343
344 #[allow(unused_must_use)]
345 device.poll(wgpu::PollType::Wait);
346
347 log::info!("Editing process completed in {:?}", time.elapsed());
348
349 log::debug!("Downloading Gaussians");
350 let modified_gaussians = gs::core::Gaussians {
351 gaussians: editor
352 .gaussians_buffer
353 .download_gaussians(&device, &queue)
354 .await
355 .expect("gaussians download"),
356 };
357
358 log::debug!("Writing modified Gaussians to output file");
359 let output_file = std::fs::File::create(&args.output).expect("output file");
360 let mut writer = std::io::BufWriter::new(output_file);
361 modified_gaussians
362 .write_ply(&mut writer)
363 .expect("write modified Gaussians to output file");
364
365 log::info!("Modified Gaussians written to {}", args.output);
366}Sourcepub fn apply_with(
&self,
device: &Device,
encoder: &mut CommandEncoder,
gaussians: &GaussiansBuffer<G>,
model_transform: &ModelTransformBuffer,
gaussian_transform: &GaussianTransformBuffer,
selection_expr: &SelectionExpr,
selection_buffer: &SelectionBuffer,
)
pub fn apply_with( &self, device: &Device, encoder: &mut CommandEncoder, gaussians: &GaussiansBuffer<G>, model_transform: &ModelTransformBuffer, gaussian_transform: &GaussianTransformBuffer, selection_expr: &SelectionExpr, selection_buffer: &SelectionBuffer, )
Apply the selection and the modifier with the given expression and buffer.
SelectionModifier::apply is the equivalent of applying this function with
SelectionModifier::selection_expr and SelectionModifier::selection_buffer.
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?
125async fn main() {
126 env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();
127
128 let args = Args::parse();
129 let model_path = &args.model;
130 let pos = Vec3::from_slice(&args.pos);
131 let rot = Quat::from_slice(&args.rot);
132 let scale = Vec3::from_slice(&args.scale);
133 let shape = match args.shape {
134 Shape::Sphere => gs::SelectionBundle::<GaussianPod>::create_sphere_bundle,
135 Shape::Box => gs::SelectionBundle::<GaussianPod>::create_box_bundle,
136 };
137 let repeat = args.repeat;
138 let offset = Vec3::from_slice(&args.offset);
139
140 log::debug!("Creating wgpu instance");
141 let instance = wgpu::Instance::new(&wgpu::InstanceDescriptor::default());
142
143 log::debug!("Requesting adapter");
144 let adapter = instance
145 .request_adapter(&wgpu::RequestAdapterOptions::default())
146 .await
147 .expect("adapter");
148
149 log::debug!("Requesting device");
150 let (device, queue) = adapter
151 .request_device(&wgpu::DeviceDescriptor {
152 label: Some("Device"),
153 required_features: wgpu::Features::empty(),
154 required_limits: adapter.limits(),
155 memory_hints: wgpu::MemoryHints::default(),
156 trace: wgpu::Trace::Off,
157 })
158 .await
159 .expect("device");
160
161 log::debug!("Creating gaussians");
162 let f = std::fs::File::open(model_path).expect("ply file");
163 let mut reader = std::io::BufReader::new(f);
164 let gaussians = gs::core::Gaussians::read_ply(&mut reader).expect("gaussians");
165
166 log::debug!("Creating editor");
167 let editor = gs::Editor::<GaussianPod>::new(&device, &gaussians);
168
169 log::debug!("Creating shape selection compute bundle");
170 let shape_selection = shape(&device);
171
172 log::debug!("Creating basic selection modifier");
173 let mut basic_selection_modifier = gs::SelectionModifier::new_with_basic_modifier(
174 &device,
175 &editor.gaussians_buffer,
176 &editor.model_transform_buffer,
177 &editor.gaussian_transform_buffer,
178 vec![shape_selection],
179 );
180
181 log::debug!("Configuring modifiers");
182 match args.override_rgb {
183 true => basic_selection_modifier
184 .modifier
185 .basic_color_modifiers_buffer
186 .update_with_override_rgb(
187 &queue,
188 Vec3::from_slice(&args.rgb_or_hsv),
189 args.alpha,
190 args.contrast,
191 args.exposure,
192 args.gamma,
193 ),
194 false => basic_selection_modifier
195 .modifier
196 .basic_color_modifiers_buffer
197 .update_with_hsv_modifiers(
198 &queue,
199 Vec3::from_slice(&args.rgb_or_hsv),
200 args.alpha,
201 args.contrast,
202 args.exposure,
203 args.gamma,
204 ),
205 }
206
207 log::debug!("Creating shape selection buffers");
208 let shape_selection_buffers = (0..repeat)
209 .map(|i| {
210 let offset_pos = pos + offset * i as f32;
211 let buffer = gs::InvTransformBuffer::new(&device);
212 buffer.update_with_scale_rot_pos(&queue, scale, rot, offset_pos);
213 buffer
214 })
215 .collect::<Vec<_>>();
216
217 log::debug!("Creating shape selection bind groups");
218 let shape_selection_bind_groups = shape_selection_buffers
219 .iter()
220 .map(|buffer| {
221 basic_selection_modifier.selection.bundles[0]
222 .create_bind_group(
223 &device,
224 // index 0 is the Gaussians buffer, so we use 1,
225 // see docs of create_sphere_bundle or create_box_bundle
226 1,
227 [buffer.buffer().as_entire_binding()],
228 )
229 .expect("bind group")
230 })
231 .collect::<Vec<_>>();
232
233 log::debug!("Creating selection expression");
234 basic_selection_modifier.selection_expr = shape_selection_bind_groups.into_iter().fold(
235 gs::SelectionExpr::Identity,
236 |acc, bind_group| {
237 acc.union(gs::SelectionExpr::selection(
238 0, // the 0 here is the bundle index in the selection bundle
239 vec![bind_group],
240 ))
241 },
242 );
243
244 log::info!("Starting editing process");
245 let time = std::time::Instant::now();
246
247 log::debug!("Editing Gaussians");
248 let mut encoder = device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
249 label: Some("Edit Encoder"),
250 });
251
252 editor.apply(
253 &device,
254 &mut encoder,
255 [&basic_selection_modifier as &dyn gs::Modifier<GaussianPod>],
256 );
257
258 queue.submit(Some(encoder.finish()));
259
260 #[allow(unused_must_use)]
261 device.poll(wgpu::PollType::Wait);
262
263 log::info!("Editing process completed in {:?}", time.elapsed());
264
265 log::debug!("Downloading Gaussians");
266 let modified_gaussians = gs::core::Gaussians {
267 gaussians: editor
268 .gaussians_buffer
269 .download_gaussians(&device, &queue)
270 .await
271 .expect("gaussians download"),
272 };
273
274 log::debug!("Writing modified Gaussians to output file");
275 let output_file = std::fs::File::create(&args.output).expect("output file");
276 let mut writer = std::io::BufWriter::new(output_file);
277 modified_gaussians
278 .write_ply(&mut writer)
279 .expect("write modified Gaussians to output file");
280
281 log::info!("Modified Gaussians written to {}", args.output);
282}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> !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