pub struct Buffer { /* private fields */ }Expand description
Device backing with allocation-budget ownership.
Implementations§
Source§impl Buffer
impl Buffer
Sourcepub fn binding(&self) -> View<'_>
pub fn binding(&self) -> View<'_>
Whole allocation as a logical binding.
Examples found in repository?
examples/queue_pool_bench.rs (line 20)
16 fn new(device: &Device, bytes: usize) -> Result<Self> {
17 let mut stream = device.stream()?;
18 let source = stream.allocate(bytes)?;
19 let destination = stream.allocate(bytes)?;
20 stream.fill(source.binding(), 0x3c)?;
21 stream.copy(destination.binding(), source.binding())?;
22 stream.synchronize()?;
23 Ok(Self {
24 stream,
25 source,
26 destination,
27 })
28 }
29 fn enqueue(&self) -> Result<()> {
30 self.stream
31 .copy(self.destination.binding(), self.source.binding())
32 }More examples
examples/graph_prepare.rs (line 21)
4fn main() -> hrx::Result<()> {
5 let runtime = Runtime::new()?;
6 let buffer = runtime.allocate(4096, MemoryPlacement::GpuLocal)?;
7 let stream = Stream::open()?;
8 let raw = stream.allocate(4096)?;
9 for count in [128, 512, 1024, 2048] {
10 let begin = Instant::now();
11 let mut graph = runtime.graph();
12 for _ in 0..count {
13 graph.fill(buffer.view(), 0)?;
14 }
15 let graph = graph.prepare()?;
16 let inferred = begin.elapsed();
17 let begin = Instant::now();
18 let mut native = stream.graph()?;
19 let mut last = None;
20 for _ in 0..count {
21 last = Some(native.fill(last.as_slice(), raw.binding(), 0)?);
22 }
23 let _native = native.finish()?;
24 println!(
25 "nodes={count} inferred_us={} explicit_us={}",
26 inferred.as_micros(),
27 begin.elapsed().as_micros()
28 );
29 graph.submit()?.wait()?;
30 }
31 Ok(())
32}examples/patch_bench.rs (line 296)
279fn prepare(
280 stream: &mut Stream,
281 compiler: &Compiler,
282 case: &Case,
283 shared: Option<std::sync::Arc<Vec<Buffer>>>,
284) -> Result<Arm> {
285 let artifact = compiler.module(case.source).compile(&case.spec)?;
286 let kernel = unsafe { stream.load_artifact(&artifact) }?;
287 let constants = Constants::indices(&kernel, &case.indices)?;
288 let buffers = if let Some(buffers) = shared {
289 buffers
290 } else {
291 std::sync::Arc::new(
292 case.data
293 .iter()
294 .map(|data| {
295 let buffer = stream.allocate(data.len())?;
296 stream.upload_blocking(buffer.binding(), data)?;
297 Ok(buffer)
298 })
299 .collect::<Result<Vec<_>>>()?,
300 )
301 };
302 let bindings: Vec<_> = buffers.iter().map(Buffer::binding).collect();
303 let mut graph = stream.graph()?;
304 let mut prior = None;
305 for _ in 0..32 {
306 prior = Some(unsafe {
307 graph.dispatch(
308 prior.as_slice(),
309 &kernel,
310 case.grid,
311 case.block,
312 &constants,
313 &bindings,
314 )
315 }?);
316 }
317 let identity = serde_json::json!({"compiler":artifact.compiler_identity(), "artifact":hrx::bundle::digest(artifact.bytes()),
318 "report":artifact.report().map(|report| report.json())});
319 Ok(Arm {
320 graph: graph.finish()?,
321 buffers,
322 identity,
323 })
324}
325fn check(stream: &mut Stream, arm: &Arm, case: &Case) -> Result<f64> {
326 let mut bytes = vec![0; case.expected.len() * 2];
327 stream.read_blocking(arm.buffers[case.output].binding(), &mut bytes)?;
328 let mut maximum = 0f64;
329 for (index, (value, expected)) in bytes
330 .as_chunks::<2>()
331 .0
332 .iter()
333 .zip(&case.expected)
334 .enumerate()
335 {
336 let value = float(u16::from_le_bytes(*value));
337 let error = (value - expected).abs();
338 if !value.is_finite() || error > case.tolerance {
339 return Err(hrx::Error::Message(format!(
340 "{} output {index}: {value} vs {expected}, error {error}, limit {}",
341 case.name, case.tolerance
342 )));
343 }
344 maximum = maximum.max(error);
345 }
346 Ok(maximum)
347}examples/prepare_weights.rs (line 40)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let mut args: Vec<_> = std::env::args().skip(1).collect();
8 let upload = args.last().is_some_and(|arg| arg == "--upload");
9 if upload {
10 args.pop();
11 }
12 if args.len() != 3 || !matches!(args[2].as_str(), "none" | "advice" | "populate") {
13 return Err("usage: prepare_weights FILE TENSOR none|advice|populate [--upload]".into());
14 }
15 // The command requires an immutable checkpoint for the mapping's lifetime.
16 let file = unsafe { FileView::map(&args[0]) }?;
17 let tensor = file.get(&args[1])?;
18 let mut stream = if upload {
19 Some(hrx::Stream::open()?)
20 } else {
21 None
22 };
23 let buffer = stream
24 .as_ref()
25 .map(|stream| stream.allocate(tensor.bytes.len()))
26 .transpose()?;
27 let start = Instant::now();
28 let prepared = match args[2].as_str() {
29 "populate" => format!("{:?}", file.prepare_bytes(tensor.bytes)?),
30 "advice" => {
31 file.will_need(tensor);
32 "Advised".into()
33 }
34 _ => "None".into(),
35 };
36 let preparation_ms = start.elapsed().as_secs_f64() * 1000.;
37 let checksum: u64;
38 let total_ms;
39 if let (Some(stream), Some(buffer)) = (&mut stream, &buffer) {
40 stream.upload_blocking(buffer.binding(), tensor.bytes)?;
41 total_ms = start.elapsed().as_secs_f64() * 1000.;
42 // Validation is outside timing, after the upload fence has retired.
43 let mut actual = vec![0; tensor.bytes.len()];
44 stream.read_blocking(buffer.binding(), &mut actual)?;
45 if actual != tensor.bytes {
46 return Err("upload bytes differ from checkpoint".into());
47 }
48 checksum = actual.iter().map(|&v| u64::from(v)).sum();
49 } else {
50 checksum = tensor.bytes.iter().map(|&v| u64::from(v)).sum();
51 total_ms = start.elapsed().as_secs_f64() * 1000.;
52 }
53 println!(
54 "{}",
55 serde_json::json!({"mode":args[2], "preparation":prepared,
56 "bytes":tensor.bytes.len(), "preparation_ms":preparation_ms,
57 "total_ms":total_ms, "checksum":checksum, "upload":upload,
58 "allocation_policy":"preallocated destination; fresh process",
59 "timed_scope":if upload { "page preparation plus completed upload" } else { "page preparation plus complete host read" }, "cache_state":"externally controlled"})
60 );
61 Ok(())
62}examples/gpu_load.rs (line 101)
88fn main() -> Result<()> {
89 let options = match parse() {
90 Ok(options) => options,
91 Err(message) => {
92 eprintln!("gpu_load: {message}");
93 std::process::exit(2);
94 }
95 };
96 let size = options.mib * 1024 * 1024;
97 let mut stream = Stream::open()?;
98 let source = stream.allocate(size)?;
99 let destination = stream.allocate(size)?;
100 // Touch both allocations so the steady-state loop never pays first-use faults.
101 stream.fill(source.binding(), 0x3c)?;
102 stream.fill(destination.binding(), 0)?;
103 stream.synchronize()?;
104
105 let run_batch = |stream: &mut Stream| -> Result<()> {
106 for _ in 0..options.batch {
107 match options.mode {
108 Mode::Copy => stream.copy(destination.binding(), source.binding())?,
109 Mode::Fill => stream.fill(destination.binding(), 0x5a)?,
110 }
111 }
112 stream.synchronize()
113 };
114
115 // Warm up outside the measured window: the first batch pays queue and paging costs.
116 run_batch(&mut stream)?;
117
118 let window = Duration::from_secs_f64(options.seconds);
119 let start = Instant::now();
120 let mut iterations = 0usize;
121 // Per-batch rates, so the harness can see whether contention was steady or bursty.
122 let mut batch_rates = Vec::new();
123 while start.elapsed() < window {
124 let batch_start = Instant::now();
125 run_batch(&mut stream)?;
126 let seconds = batch_start.elapsed().as_secs_f64();
127 iterations += options.batch;
128 let bytes = options.mode.traffic(size) * options.batch;
129 batch_rates.push(bytes as f64 / seconds / 1e9);
130 }
131 let elapsed = start.elapsed().as_secs_f64();
132 let total = options.mode.traffic(size) as f64 * iterations as f64;
133 let mean = total / elapsed / 1e9;
134 batch_rates.sort_by(f64::total_cmp);
135 let median = batch_rates[batch_rates.len() / 2];
136 let low = batch_rates[batch_rates.len() / 20];
137
138 println!(
139 concat!(
140 r#"{{"device":"gpu","mode":"{}","buffer_mib":{},"batch":{},"#,
141 r#""seconds":{:.4},"iterations":{},"gb_s_mean":{:.3},"#,
142 r#""gb_s_median":{:.3},"gb_s_p5":{:.3}}}"#
143 ),
144 options.mode.name(),
145 options.mib,
146 options.batch,
147 elapsed,
148 iterations,
149 mean,
150 median,
151 low
152 );
153 eprintln!(
154 "gpu_load: {} {:.1} GB/s mean over {:.1}s ({} iterations)",
155 options.mode.name(),
156 mean,
157 elapsed,
158 iterations
159 );
160 Ok(())
161}examples/stream_bench.rs (line 60)
30fn main() -> Result<()> {
31 let mut stream = Stream::open()?;
32 let mut metrics = BTreeMap::new();
33 let samples = std::env::var("HRX_BENCH_SAMPLES")
34 .ok()
35 .and_then(|value| value.parse::<usize>().ok())
36 .filter(|&value| value > 0)
37 .unwrap_or(9);
38 let (ns, _) = measure(&mut stream, samples, 50_000, |stream| {
39 for _ in 0..50_000 {
40 let buffer = stream.scratch(1024 * 1024)?;
41 black_box(&buffer);
42 stream.recycle(buffer)?;
43 }
44 Ok(())
45 })?;
46 metrics.insert("scratch_reuse_ns", ns);
47 let (ns, _) = measure(&mut stream, samples, 2_000, |stream| {
48 for _ in 0..2_000 {
49 black_box(stream.allocate(1024 * 1024)?);
50 }
51 Ok(())
52 })?;
53 metrics.insert("allocate_drop_ns", ns);
54
55 let bytes = 256 * 1024 * 1024;
56 let chunk = vec![0x3cu8; 4 * 1024 * 1024];
57 let weights = stream.allocate(bytes)?;
58 let (_, ns) = measure(&mut stream, samples, 1, |stream| {
59 for offset in (0..bytes).step_by(chunk.len()) {
60 stream.upload(weights.binding().slice(offset, chunk.len())?, &chunk)?;
61 }
62 Ok(())
63 })?;
64 metrics.insert(
65 "queued_upload_gib_s",
66 bytes as f64 / (1024f64.powi(3) * ns * 1e-9),
67 );
68 let mut check = [0u8; 16];
69 stream.read_blocking(
70 weights.try_slice(bytes - check.len(), check.len())?,
71 &mut check,
72 )?;
73 assert_eq!(check, [0x3c; 16]);
74 drop(weights);
75
76 let compiler = hrx::loom::Compiler::for_stream(None, &stream)?;
77 let module = compiler.module(include_str!("../tests/kernels/euler.loom"));
78 let mut spec = hrx::loom::Specialization::new("krea2_euler");
79 spec.set_config("krea2.euler.grid_x", "1");
80 spec.set_config("krea2.euler.grid_y", "1");
81 let artifact = module.compile(&spec)?;
82 // This repository owns the source; use its exact dimensions and scalar layout.
83 let kernel = unsafe { stream.load_artifact(&artifact)? };
84 let sample = stream.allocate(512)?;
85 let velocity = stream.allocate(512)?;
86 let ones: Vec<u8> = (0..256).flat_map(|_| 0x3f80u16.to_le_bytes()).collect();
87 stream.upload_blocking(sample.binding(), &ones)?;
88 stream.upload_blocking(velocity.binding(), &ones)?;
89 let mut constants = Constants::new();
90 match kernel.info().constant_byte_length {
91 8 => constants.push(256u32)?,
92 12 => constants.push(256u64)?,
93 n => return Err(hrx::Error::Message(format!("unexpected constant size {n}"))),
94 }
95 constants.push(0f32)?;
96 let bindings = [sample.binding(), velocity.binding()];
97 let (enqueue, complete) = measure(&mut stream, samples, 2048, |stream| {
98 for _ in 0..2048 {
99 // The source accesses exactly the 256 bf16 elements in each buffer.
100 unsafe {
101 stream.dispatch(&kernel, [1; 3], [256, 1, 1], &constants, &bindings)?;
102 }
103 }
104 Ok(())
105 })?;
106 metrics.insert("dispatch_enqueue_ns", enqueue);
107 metrics.insert("dispatch_complete_ns", complete);
108
109 // Use disjoint allocations in both graphs. Even an idempotent store is a
110 // write: concurrent Euler dispatches cannot share their in/out buffer.
111 let mut graph_buffers = Vec::new();
112 for _ in 0..32 {
113 let sample = stream.allocate(512)?;
114 let velocity = stream.allocate(512)?;
115 stream.upload(sample.binding(), &ones)?;
116 stream.upload(velocity.binding(), &ones)?;
117 graph_buffers.push((sample, velocity));
118 }
119 stream.synchronize()?;
120 let mut builder = stream.graph()?;
121 let mut previous = None;
122 for (sample, velocity) in &graph_buffers {
123 let after = previous.as_slice();
124 previous = Some(unsafe {
125 builder.dispatch(
126 after,
127 &kernel,
128 [1; 3],
129 [256, 1, 1],
130 &constants,
131 &[sample.binding(), velocity.binding()],
132 )?
133 });
134 }
135 let chained = builder.finish()?;
136
137 // The same disjoint workloads, this time allowing concurrent scheduling.
138 let mut builder = stream.graph()?;
139 for (sample, velocity) in &graph_buffers {
140 unsafe {
141 builder.dispatch(
142 &[],
143 &kernel,
144 [1; 3],
145 [256, 1, 1],
146 &constants,
147 &[sample.binding(), velocity.binding()],
148 )?;
149 }
150 }
151 let independent = builder.finish()?;
152 let mut graphs = [chained, independent];
153 let mut enqueue = [Vec::new(), Vec::new()];
154 let mut complete = [Vec::new(), Vec::new()];
155 for round in 0..samples + 3 {
156 for arm in if round % 2 == 0 { [0, 1] } else { [1, 0] } {
157 stream.synchronize()?;
158 let start = Instant::now();
159 for _ in 0..256 {
160 stream.launch(&mut graphs[arm])?;
161 }
162 let submitted = start.elapsed();
163 stream.synchronize()?;
164 let elapsed = start.elapsed();
165 if round >= 3 {
166 enqueue[arm].push(submitted.as_secs_f64() * 1e9 / 256.0);
167 complete[arm].push(elapsed.as_secs_f64() * 1e9 / (256.0 * 32.0));
168 }
169 }
170 }
171 for values in enqueue.iter_mut().chain(complete.iter_mut()) {
172 values.sort_by(f64::total_cmp);
173 }
174 let ns = complete[0][samples / 2];
175 let ns_free = complete[1][samples / 2];
176 metrics.insert("graph_enqueue_ns_per_replay", enqueue[0][samples / 2]);
177 metrics.insert("graph_complete_ns_per_kernel", ns);
178 metrics.insert("graph_independent_ns_per_kernel", ns_free);
179 metrics.insert("graph_scheduling_difference_ns_per_kernel", ns - ns_free);
180 for (sample, _) in &graph_buffers {
181 let mut output = vec![0; 512];
182 stream.read_blocking(sample.binding(), &mut output)?;
183 assert_eq!(output, ones);
184 }
185 let mut output = vec![0; 512];
186 stream.read_blocking(sample.binding(), &mut output)?;
187 assert_eq!(output, ones);
188 println!("{}", serde_json::to_string(&metrics)?);
189 Ok(())
190}Sourcepub fn try_slice(&self, offset: usize, length: usize) -> Result<View<'_>>
pub fn try_slice(&self, offset: usize, length: usize) -> Result<View<'_>>
Checked subrange.
Examples found in repository?
examples/stream_bench.rs (line 70)
30fn main() -> Result<()> {
31 let mut stream = Stream::open()?;
32 let mut metrics = BTreeMap::new();
33 let samples = std::env::var("HRX_BENCH_SAMPLES")
34 .ok()
35 .and_then(|value| value.parse::<usize>().ok())
36 .filter(|&value| value > 0)
37 .unwrap_or(9);
38 let (ns, _) = measure(&mut stream, samples, 50_000, |stream| {
39 for _ in 0..50_000 {
40 let buffer = stream.scratch(1024 * 1024)?;
41 black_box(&buffer);
42 stream.recycle(buffer)?;
43 }
44 Ok(())
45 })?;
46 metrics.insert("scratch_reuse_ns", ns);
47 let (ns, _) = measure(&mut stream, samples, 2_000, |stream| {
48 for _ in 0..2_000 {
49 black_box(stream.allocate(1024 * 1024)?);
50 }
51 Ok(())
52 })?;
53 metrics.insert("allocate_drop_ns", ns);
54
55 let bytes = 256 * 1024 * 1024;
56 let chunk = vec![0x3cu8; 4 * 1024 * 1024];
57 let weights = stream.allocate(bytes)?;
58 let (_, ns) = measure(&mut stream, samples, 1, |stream| {
59 for offset in (0..bytes).step_by(chunk.len()) {
60 stream.upload(weights.binding().slice(offset, chunk.len())?, &chunk)?;
61 }
62 Ok(())
63 })?;
64 metrics.insert(
65 "queued_upload_gib_s",
66 bytes as f64 / (1024f64.powi(3) * ns * 1e-9),
67 );
68 let mut check = [0u8; 16];
69 stream.read_blocking(
70 weights.try_slice(bytes - check.len(), check.len())?,
71 &mut check,
72 )?;
73 assert_eq!(check, [0x3c; 16]);
74 drop(weights);
75
76 let compiler = hrx::loom::Compiler::for_stream(None, &stream)?;
77 let module = compiler.module(include_str!("../tests/kernels/euler.loom"));
78 let mut spec = hrx::loom::Specialization::new("krea2_euler");
79 spec.set_config("krea2.euler.grid_x", "1");
80 spec.set_config("krea2.euler.grid_y", "1");
81 let artifact = module.compile(&spec)?;
82 // This repository owns the source; use its exact dimensions and scalar layout.
83 let kernel = unsafe { stream.load_artifact(&artifact)? };
84 let sample = stream.allocate(512)?;
85 let velocity = stream.allocate(512)?;
86 let ones: Vec<u8> = (0..256).flat_map(|_| 0x3f80u16.to_le_bytes()).collect();
87 stream.upload_blocking(sample.binding(), &ones)?;
88 stream.upload_blocking(velocity.binding(), &ones)?;
89 let mut constants = Constants::new();
90 match kernel.info().constant_byte_length {
91 8 => constants.push(256u32)?,
92 12 => constants.push(256u64)?,
93 n => return Err(hrx::Error::Message(format!("unexpected constant size {n}"))),
94 }
95 constants.push(0f32)?;
96 let bindings = [sample.binding(), velocity.binding()];
97 let (enqueue, complete) = measure(&mut stream, samples, 2048, |stream| {
98 for _ in 0..2048 {
99 // The source accesses exactly the 256 bf16 elements in each buffer.
100 unsafe {
101 stream.dispatch(&kernel, [1; 3], [256, 1, 1], &constants, &bindings)?;
102 }
103 }
104 Ok(())
105 })?;
106 metrics.insert("dispatch_enqueue_ns", enqueue);
107 metrics.insert("dispatch_complete_ns", complete);
108
109 // Use disjoint allocations in both graphs. Even an idempotent store is a
110 // write: concurrent Euler dispatches cannot share their in/out buffer.
111 let mut graph_buffers = Vec::new();
112 for _ in 0..32 {
113 let sample = stream.allocate(512)?;
114 let velocity = stream.allocate(512)?;
115 stream.upload(sample.binding(), &ones)?;
116 stream.upload(velocity.binding(), &ones)?;
117 graph_buffers.push((sample, velocity));
118 }
119 stream.synchronize()?;
120 let mut builder = stream.graph()?;
121 let mut previous = None;
122 for (sample, velocity) in &graph_buffers {
123 let after = previous.as_slice();
124 previous = Some(unsafe {
125 builder.dispatch(
126 after,
127 &kernel,
128 [1; 3],
129 [256, 1, 1],
130 &constants,
131 &[sample.binding(), velocity.binding()],
132 )?
133 });
134 }
135 let chained = builder.finish()?;
136
137 // The same disjoint workloads, this time allowing concurrent scheduling.
138 let mut builder = stream.graph()?;
139 for (sample, velocity) in &graph_buffers {
140 unsafe {
141 builder.dispatch(
142 &[],
143 &kernel,
144 [1; 3],
145 [256, 1, 1],
146 &constants,
147 &[sample.binding(), velocity.binding()],
148 )?;
149 }
150 }
151 let independent = builder.finish()?;
152 let mut graphs = [chained, independent];
153 let mut enqueue = [Vec::new(), Vec::new()];
154 let mut complete = [Vec::new(), Vec::new()];
155 for round in 0..samples + 3 {
156 for arm in if round % 2 == 0 { [0, 1] } else { [1, 0] } {
157 stream.synchronize()?;
158 let start = Instant::now();
159 for _ in 0..256 {
160 stream.launch(&mut graphs[arm])?;
161 }
162 let submitted = start.elapsed();
163 stream.synchronize()?;
164 let elapsed = start.elapsed();
165 if round >= 3 {
166 enqueue[arm].push(submitted.as_secs_f64() * 1e9 / 256.0);
167 complete[arm].push(elapsed.as_secs_f64() * 1e9 / (256.0 * 32.0));
168 }
169 }
170 }
171 for values in enqueue.iter_mut().chain(complete.iter_mut()) {
172 values.sort_by(f64::total_cmp);
173 }
174 let ns = complete[0][samples / 2];
175 let ns_free = complete[1][samples / 2];
176 metrics.insert("graph_enqueue_ns_per_replay", enqueue[0][samples / 2]);
177 metrics.insert("graph_complete_ns_per_kernel", ns);
178 metrics.insert("graph_independent_ns_per_kernel", ns_free);
179 metrics.insert("graph_scheduling_difference_ns_per_kernel", ns - ns_free);
180 for (sample, _) in &graph_buffers {
181 let mut output = vec![0; 512];
182 stream.read_blocking(sample.binding(), &mut output)?;
183 assert_eq!(output, ones);
184 }
185 let mut output = vec![0; 512];
186 stream.read_blocking(sample.binding(), &mut output)?;
187 assert_eq!(output, ones);
188 println!("{}", serde_json::to_string(&metrics)?);
189 Ok(())
190}Sourcepub fn slice(&self, offset: usize, length: usize) -> View<'_>
pub fn slice(&self, offset: usize, length: usize) -> View<'_>
Checked subrange, panicking on invalid bounds.
Sourcepub fn device_ptr(&self) -> Result<*mut c_void>
pub fn device_ptr(&self) -> Result<*mut c_void>
Mapped host address. Dereferencing requires external synchronization.
Ordinary allocations additionally require cache_control before host
reads (including partial cache-line updates) and after host writes;
allocate_shared omits that requirement.
Sourcepub unsafe fn cache_control(
&self,
flush: bool,
offset: usize,
length: usize,
) -> Result<()>
pub unsafe fn cache_control( &self, flush: bool, offset: usize, length: usize, ) -> Result<()>
Publish host writes (flush = true) or acquire device writes (false).
Stream upload/read operations perform these transitions automatically.
§Safety
The caller must exclude conflicting host/device access for the entire transition and retain the allocation until all accesses have completed.
Trait Implementations§
Auto Trait Implementations§
impl Freeze for Buffer
impl RefUnwindSafe for Buffer
impl Send for Buffer
impl Sync for Buffer
impl Unpin for Buffer
impl UnsafeUnpin for Buffer
impl UnwindSafe for Buffer
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
Mutably borrows from an owned value. Read more
Source§impl<T> DropFlavorWrapper<T> for T
impl<T> DropFlavorWrapper<T> for T
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> 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> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read 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> ⓘ
Converts
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more