1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{fmt, io, marker::PhantomData, mem, ptr, u64, usize};
4
5use crate::{
6 buffer::{Readable, Writable},
7 Buffer, BufferRef,
8};
9
10pub struct BufferCursor<T> {
11 buffer: Option<Buffer>,
12 size: u64,
13 num_mem: u32,
14 cur_mem_idx: u32,
15 cur_offset: u64,
16 cur_mem_offset: usize,
17 map_info: ffi::GstMapInfo,
18 phantom: PhantomData<T>,
19}
20
21pub struct BufferRefCursor<T> {
22 buffer: T,
23 size: u64,
24 num_mem: u32,
25 cur_mem_idx: u32,
26 cur_offset: u64,
27 cur_mem_offset: usize,
28 map_info: ffi::GstMapInfo,
29}
30
31macro_rules! define_seek_impl(
32 ($get_buffer_ref:expr) => {
33 fn seek(&mut self, pos: io::SeekFrom) -> Result<u64, io::Error> {
34 match pos {
35 io::SeekFrom::Start(off) => {
36 self.cur_offset = std::cmp::min(self.size, off);
37 }
38 io::SeekFrom::End(off) if off <= 0 => {
39 self.cur_offset = self.size;
40 }
41 io::SeekFrom::End(off) => {
42 self.cur_offset = self.size.checked_sub(off as u64).ok_or_else(|| {
43 io::Error::new(io::ErrorKind::InvalidInput, "Seek before start of buffer")
44 })?;
45 }
46 io::SeekFrom::Current(std::i64::MIN) => {
47 return Err(io::Error::new(
48 io::ErrorKind::InvalidInput,
49 "Seek before start of buffer",
50 ));
51 }
52 io::SeekFrom::Current(off) => {
53 if off <= 0 {
54 self.cur_offset =
55 self.cur_offset.checked_sub((-off) as u64).ok_or_else(|| {
56 io::Error::new(
57 io::ErrorKind::InvalidInput,
58 "Seek before start of buffer",
59 )
60 })?;
61 } else {
62 self.cur_offset = std::cmp::min(
63 self.size,
64 self.cur_offset.checked_add(off as u64).unwrap_or(self.size),
65 );
66 }
67 }
68 }
69
70 // Work around lifetime annotation issues with closures
71 let buffer_ref: fn(&Self) -> &BufferRef = $get_buffer_ref;
72 let (idx, _, skip) = buffer_ref(self)
73 .find_memory(self.cur_offset as usize, None)
74 .expect("Failed to find memory");
75
76 if idx != self.cur_mem_idx && !self.map_info.memory.is_null() {
77 unsafe {
78 ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info);
79 self.map_info.memory = ptr::null_mut();
80 }
81 }
82
83 self.cur_mem_idx = idx;
84 self.cur_mem_offset = skip;
85
86 Ok(self.cur_offset)
87 }
88
89 // Once stabilized
90 // fn stream_len(&mut self) -> Result<u64, io::Error> {
91 // Ok(self.size)
92 // }
93 //
94 // fn stream_position(&mut self) -> Result<u64, io::Error> {
95 // Ok(self.current_offset)
96 // }
97 }
98);
99
100macro_rules! define_read_write_fn_impl(
101 ($self:ident, $data:ident, $data_type:ty, $get_buffer_ref:expr, $map_flags:path, $copy:expr, $split:expr) => {
102 #[allow(clippy::redundant_closure_call)]
103 {
104 let mut copied = 0;
105
106 while !$data.is_empty() && $self.cur_mem_idx < $self.num_mem {
107 // Map memory if needed. cur_mem_idx, cur_mem_offset and cur_offset are required to be
108 // set correctly here already (from constructor, seek and the bottom of the loop)
109 if $self.map_info.memory.is_null() {
110 unsafe {
111 // Work around lifetime annotation issues with closures
112 let buffer_ref: fn(&Self) -> &BufferRef = $get_buffer_ref;
113 let memory = ffi::gst_buffer_peek_memory(
114 buffer_ref($self).as_mut_ptr(),
115 $self.cur_mem_idx,
116 );
117 debug_assert!(!memory.is_null());
118
119 if ffi::gst_memory_map(memory, &mut $self.map_info, $map_flags)
120 == glib::ffi::GFALSE
121 {
122 return Err(io::Error::new(
123 io::ErrorKind::InvalidData,
124 "Failed to map memory readable",
125 ));
126 }
127 }
128
129 debug_assert!($self.cur_mem_offset < $self.map_info.size);
130 }
131
132 debug_assert!(!$self.map_info.memory.is_null());
133
134 // Copy all data we can currently copy
135 let data_left = $self.map_info.size - $self.cur_mem_offset;
136 let to_copy = std::cmp::min($data.len(), data_left);
137 $copy(&$self.map_info, $self.cur_mem_offset, $data, to_copy);
138 copied += to_copy;
139 $self.cur_offset += to_copy as u64;
140 $self.cur_mem_offset += to_copy;
141 // Work around lifetime annotation issues with closures
142 let split: fn($data_type, usize) -> $data_type = $split;
143 #[allow(clippy::redundant_closure_call)]
144 {
145 $data = split($data, to_copy);
146 }
147
148 // If we're at the end of the current memory, unmap and advance to the next memory
149 if $self.cur_mem_offset == $self.map_info.size {
150 unsafe {
151 ffi::gst_memory_unmap($self.map_info.memory, &mut $self.map_info);
152 }
153 $self.map_info.memory = ptr::null_mut();
154 $self.cur_mem_idx += 1;
155 $self.cur_mem_offset = 0;
156 }
157 }
158
159 Ok(copied)
160 }}
161);
162
163macro_rules! define_read_impl(
164 ($get_buffer_ref:expr) => {
165 fn read(&mut self, mut data: &mut [u8]) -> Result<usize, io::Error> {
166 define_read_write_fn_impl!(
167 self,
168 data,
169 &mut [u8],
170 $get_buffer_ref,
171 ffi::GST_MAP_READ,
172 |map_info: &ffi::GstMapInfo, off, data: &mut [u8], to_copy| unsafe {
173 ptr::copy_nonoverlapping(
174 (map_info.data as *const u8).add(off),
175 data.as_mut_ptr(),
176 to_copy,
177 );
178 },
179 |data, to_copy| &mut data[to_copy..]
180 )
181 }
182 }
183);
184
185macro_rules! define_write_impl(
186 ($get_buffer_ref:expr) => {
187 fn write(&mut self, mut data: &[u8]) -> Result<usize, io::Error> {
188 define_read_write_fn_impl!(
189 self,
190 data,
191 &[u8],
192 $get_buffer_ref,
193 ffi::GST_MAP_WRITE,
194 |map_info: &ffi::GstMapInfo, off, data: &[u8], to_copy| unsafe {
195 ptr::copy_nonoverlapping(
196 data.as_ptr(),
197 (map_info.data as *mut u8).add(off),
198 to_copy,
199 );
200 },
201 |data, to_copy| &data[to_copy..]
202 )
203 }
204
205 fn flush(&mut self) -> Result<(), io::Error> {
206 if !self.map_info.memory.is_null() {
207 unsafe {
208 ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info);
209 self.map_info.memory = ptr::null_mut();
210 }
211 }
212
213 Ok(())
214 }
215 }
216);
217
218impl<T> fmt::Debug for BufferCursor<T> {
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 f&mut DebugStruct<'_, '_>.debug_struct("BufferCursor")
221 .field("buffer", &self.buffer)
222 .field("size", &self.size)
223 .field("num_mem", &self.num_mem)
224 .field("cur_mem_idx", &self.cur_mem_idx)
225 .field("cur_offset", &self.cur_offset)
226 .field("cur_mem_offset", &self.cur_mem_offset)
227 .field(name:"map_info", &self.map_info)
228 .finish()
229 }
230}
231
232impl<T> Drop for BufferCursor<T> {
233 fn drop(&mut self) {
234 if !self.map_info.memory.is_null() {
235 unsafe {
236 ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info);
237 }
238 }
239 }
240}
241
242impl io::Read for BufferCursor<Readable> {
243 define_read_impl!(|s| s.buffer.as_ref().unwrap());
244}
245
246impl io::Write for BufferCursor<Writable> {
247 define_write_impl!(|s| s.buffer.as_ref().unwrap());
248}
249
250impl<T> io::Seek for BufferCursor<T> {
251 define_seek_impl!(|s| s.buffer.as_ref().unwrap());
252}
253
254impl<T> BufferCursor<T> {
255 pub fn stream_len(&mut self) -> Result<u64, io::Error> {
256 Ok(self.size)
257 }
258
259 pub fn stream_position(&mut self) -> Result<u64, io::Error> {
260 Ok(self.cur_offset)
261 }
262
263 #[doc(alias = "get_buffer")]
264 pub fn buffer(&self) -> &BufferRef {
265 self.buffer.as_ref().unwrap().as_ref()
266 }
267
268 pub fn into_buffer(mut self) -> Buffer {
269 self.buffer.take().unwrap()
270 }
271}
272
273impl BufferCursor<Readable> {
274 pub(crate) fn new_readable(buffer: Buffer) -> BufferCursor<Readable> {
275 skip_assert_initialized!();
276 let size: u64 = buffer.size() as u64;
277 let num_mem: u32 = buffer.n_memory();
278
279 BufferCursor {
280 buffer: Some(buffer),
281 size,
282 num_mem,
283 cur_mem_idx: 0,
284 cur_offset: 0,
285 cur_mem_offset: 0,
286 map_info: unsafe { mem::zeroed() },
287 phantom: PhantomData,
288 }
289 }
290}
291
292impl BufferCursor<Writable> {
293 pub(crate) fn new_writable(buffer: Buffer) -> Result<BufferCursor<Writable>, glib::BoolError> {
294 skip_assert_initialized!();
295 if !buffer.is_writable() || !buffer.is_all_memory_writable() {
296 return Err(glib::bool_error!("Not all memories are writable"));
297 }
298
299 let size: u64 = buffer.size() as u64;
300 let num_mem: u32 = buffer.n_memory();
301
302 Ok(BufferCursor {
303 buffer: Some(buffer),
304 size,
305 num_mem,
306 cur_mem_idx: 0,
307 cur_offset: 0,
308 cur_mem_offset: 0,
309 map_info: unsafe { mem::zeroed() },
310 phantom: PhantomData,
311 })
312 }
313}
314
315unsafe impl<T> Send for BufferCursor<T> {}
316unsafe impl<T> Sync for BufferCursor<T> {}
317
318impl<T: fmt::Debug> fmt::Debug for BufferRefCursor<T> {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 f&mut DebugStruct<'_, '_>.debug_struct("BufferRefCursor")
321 .field("buffer", &self.buffer)
322 .field("size", &self.size)
323 .field("num_mem", &self.num_mem)
324 .field("cur_mem_idx", &self.cur_mem_idx)
325 .field("cur_offset", &self.cur_offset)
326 .field("cur_mem_offset", &self.cur_mem_offset)
327 .field(name:"map_info", &self.map_info)
328 .finish()
329 }
330}
331
332impl<T> Drop for BufferRefCursor<T> {
333 fn drop(&mut self) {
334 if !self.map_info.memory.is_null() {
335 unsafe {
336 ffi::gst_memory_unmap(self.map_info.memory, &mut self.map_info);
337 }
338 }
339 }
340}
341
342impl<'a> io::Read for BufferRefCursor<&'a BufferRef> {
343 define_read_impl!(|s| s.buffer);
344}
345
346impl<'a> io::Write for BufferRefCursor<&'a mut BufferRef> {
347 define_write_impl!(|s| s.buffer);
348}
349
350impl<'a> io::Seek for BufferRefCursor<&'a BufferRef> {
351 define_seek_impl!(|s| s.buffer);
352}
353
354impl<'a> io::Seek for BufferRefCursor<&'a mut BufferRef> {
355 define_seek_impl!(|s| s.buffer);
356}
357
358impl<T> BufferRefCursor<T> {
359 pub fn stream_len(&mut self) -> Result<u64, io::Error> {
360 Ok(self.size)
361 }
362
363 pub fn stream_position(&mut self) -> Result<u64, io::Error> {
364 Ok(self.cur_offset)
365 }
366}
367
368impl<'a> BufferRefCursor<&'a BufferRef> {
369 #[doc(alias = "get_buffer")]
370 pub fn buffer(&self) -> &BufferRef {
371 self.buffer
372 }
373
374 pub(crate) fn new_readable(buffer: &'a BufferRef) -> BufferRefCursor<&'a BufferRef> {
375 skip_assert_initialized!();
376 let size: u64 = buffer.size() as u64;
377 let num_mem: u32 = buffer.n_memory();
378
379 BufferRefCursor {
380 buffer,
381 size,
382 num_mem,
383 cur_mem_idx: 0,
384 cur_offset: 0,
385 cur_mem_offset: 0,
386 map_info: unsafe { mem::zeroed() },
387 }
388 }
389}
390
391impl<'a> BufferRefCursor<&'a mut BufferRef> {
392 #[doc(alias = "get_buffer")]
393 pub fn buffer(&self) -> &BufferRef {
394 self.buffer
395 }
396
397 pub(crate) fn new_writable(
398 buffer: &'a mut BufferRef,
399 ) -> Result<BufferRefCursor<&'a mut BufferRef>, glib::BoolError> {
400 skip_assert_initialized!();
401 if !buffer.is_all_memory_writable() {
402 return Err(glib::bool_error!("Not all memories are writable"));
403 }
404
405 let size = buffer.size() as u64;
406 let num_mem = buffer.n_memory();
407
408 Ok(BufferRefCursor {
409 buffer,
410 size,
411 num_mem,
412 cur_mem_idx: 0,
413 cur_offset: 0,
414 cur_mem_offset: 0,
415 map_info: unsafe { mem::zeroed() },
416 })
417 }
418}
419
420unsafe impl<T> Send for BufferRefCursor<T> {}
421unsafe impl<T> Sync for BufferRefCursor<T> {}
422
423#[cfg(test)]
424mod tests {
425 use super::*;
426
427 #[test]
428 #[allow(clippy::cognitive_complexity)]
429 fn test_buffer_cursor() {
430 use std::io::{self, Read, Seek, Write};
431
432 crate::init().unwrap();
433
434 let mut buffer = Buffer::new();
435 {
436 let buffer = buffer.get_mut().unwrap();
437 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
438 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
439 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
440 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
441 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 10]));
442 }
443
444 assert!(buffer.is_all_memory_writable());
445 assert_eq!(buffer.n_memory(), 5);
446 assert_eq!(buffer.size(), 30);
447
448 let mut cursor = buffer.into_cursor_writable().unwrap();
449 assert_eq!(cursor.stream_position().unwrap(), 0);
450 cursor.write_all(b"01234567").unwrap();
451 assert_eq!(cursor.stream_position().unwrap(), 8);
452 cursor.write_all(b"890123").unwrap();
453 assert_eq!(cursor.stream_position().unwrap(), 14);
454 cursor.write_all(b"456").unwrap();
455 assert_eq!(cursor.stream_position().unwrap(), 17);
456 cursor.write_all(b"78901234567").unwrap();
457 assert_eq!(cursor.stream_position().unwrap(), 28);
458 cursor.write_all(b"89").unwrap();
459 assert_eq!(cursor.stream_position().unwrap(), 30);
460 assert!(cursor.write_all(b"0").is_err());
461
462 assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5);
463 assert_eq!(cursor.stream_position().unwrap(), 5);
464 cursor.write_all(b"A").unwrap();
465
466 assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25);
467 assert_eq!(cursor.stream_position().unwrap(), 25);
468 cursor.write_all(b"B").unwrap();
469
470 assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25);
471 assert_eq!(cursor.stream_position().unwrap(), 25);
472 cursor.write_all(b"C").unwrap();
473
474 assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27);
475 assert_eq!(cursor.stream_position().unwrap(), 27);
476 cursor.write_all(b"D").unwrap();
477
478 let buffer = cursor.into_buffer();
479
480 let mut cursor = buffer.into_cursor_readable();
481 let mut data = [0; 30];
482
483 assert_eq!(cursor.stream_position().unwrap(), 0);
484 cursor.read_exact(&mut data[0..7]).unwrap();
485 assert_eq!(cursor.stream_position().unwrap(), 7);
486 assert_eq!(&data[0..7], b"01234A6");
487 cursor.read_exact(&mut data[0..5]).unwrap();
488 assert_eq!(cursor.stream_position().unwrap(), 12);
489 assert_eq!(&data[0..5], b"78901");
490 cursor.read_exact(&mut data[0..10]).unwrap();
491 assert_eq!(cursor.stream_position().unwrap(), 22);
492 assert_eq!(&data[0..10], b"2345678901");
493 cursor.read_exact(&mut data[0..8]).unwrap();
494 assert_eq!(cursor.stream_position().unwrap(), 30);
495 assert_eq!(&data[0..8], b"234C6D89");
496 assert!(cursor.read_exact(&mut data[0..1]).is_err());
497
498 assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5);
499 assert_eq!(cursor.stream_position().unwrap(), 5);
500 cursor.read_exact(&mut data[0..1]).unwrap();
501 assert_eq!(&data[0..1], b"A");
502
503 assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25);
504 assert_eq!(cursor.stream_position().unwrap(), 25);
505 cursor.read_exact(&mut data[0..1]).unwrap();
506 assert_eq!(&data[0..1], b"C");
507
508 assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25);
509 assert_eq!(cursor.stream_position().unwrap(), 25);
510 cursor.read_exact(&mut data[0..1]).unwrap();
511 assert_eq!(&data[0..1], b"C");
512
513 assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27);
514 assert_eq!(cursor.stream_position().unwrap(), 27);
515 cursor.read_exact(&mut data[0..1]).unwrap();
516 assert_eq!(&data[0..1], b"D");
517 }
518
519 #[test]
520 #[allow(clippy::cognitive_complexity)]
521 fn test_buffer_cursor_ref() {
522 use std::io::{self, Read, Seek, Write};
523
524 crate::init().unwrap();
525
526 let mut buffer = Buffer::new();
527 {
528 let buffer = buffer.get_mut().unwrap();
529 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
530 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
531 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
532 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 5]));
533 buffer.append_memory(crate::Memory::from_mut_slice(vec![0; 10]));
534 }
535
536 assert!(buffer.is_all_memory_writable());
537 assert_eq!(buffer.n_memory(), 5);
538 assert_eq!(buffer.size(), 30);
539
540 {
541 let buffer = buffer.get_mut().unwrap();
542
543 let mut cursor = buffer.as_cursor_writable().unwrap();
544 assert_eq!(cursor.stream_position().unwrap(), 0);
545 cursor.write_all(b"01234567").unwrap();
546 assert_eq!(cursor.stream_position().unwrap(), 8);
547 cursor.write_all(b"890123").unwrap();
548 assert_eq!(cursor.stream_position().unwrap(), 14);
549 cursor.write_all(b"456").unwrap();
550 assert_eq!(cursor.stream_position().unwrap(), 17);
551 cursor.write_all(b"78901234567").unwrap();
552 assert_eq!(cursor.stream_position().unwrap(), 28);
553 cursor.write_all(b"89").unwrap();
554 assert_eq!(cursor.stream_position().unwrap(), 30);
555 assert!(cursor.write_all(b"0").is_err());
556
557 assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5);
558 assert_eq!(cursor.stream_position().unwrap(), 5);
559 cursor.write_all(b"A").unwrap();
560
561 assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25);
562 assert_eq!(cursor.stream_position().unwrap(), 25);
563 cursor.write_all(b"B").unwrap();
564
565 assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25);
566 assert_eq!(cursor.stream_position().unwrap(), 25);
567 cursor.write_all(b"C").unwrap();
568
569 assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27);
570 assert_eq!(cursor.stream_position().unwrap(), 27);
571 cursor.write_all(b"D").unwrap();
572 }
573
574 let mut cursor = buffer.as_cursor_readable();
575 let mut data = [0; 30];
576
577 assert_eq!(cursor.stream_position().unwrap(), 0);
578 cursor.read_exact(&mut data[0..7]).unwrap();
579 assert_eq!(cursor.stream_position().unwrap(), 7);
580 assert_eq!(&data[0..7], b"01234A6");
581 cursor.read_exact(&mut data[0..5]).unwrap();
582 assert_eq!(cursor.stream_position().unwrap(), 12);
583 assert_eq!(&data[0..5], b"78901");
584 cursor.read_exact(&mut data[0..10]).unwrap();
585 assert_eq!(cursor.stream_position().unwrap(), 22);
586 assert_eq!(&data[0..10], b"2345678901");
587 cursor.read_exact(&mut data[0..8]).unwrap();
588 assert_eq!(cursor.stream_position().unwrap(), 30);
589 assert_eq!(&data[0..8], b"234C6D89");
590 assert!(cursor.read_exact(&mut data[0..1]).is_err());
591
592 assert_eq!(cursor.seek(io::SeekFrom::Start(5)).unwrap(), 5);
593 assert_eq!(cursor.stream_position().unwrap(), 5);
594 cursor.read_exact(&mut data[0..1]).unwrap();
595 assert_eq!(&data[0..1], b"A");
596
597 assert_eq!(cursor.seek(io::SeekFrom::End(5)).unwrap(), 25);
598 assert_eq!(cursor.stream_position().unwrap(), 25);
599 cursor.read_exact(&mut data[0..1]).unwrap();
600 assert_eq!(&data[0..1], b"C");
601
602 assert_eq!(cursor.seek(io::SeekFrom::Current(-1)).unwrap(), 25);
603 assert_eq!(cursor.stream_position().unwrap(), 25);
604 cursor.read_exact(&mut data[0..1]).unwrap();
605 assert_eq!(&data[0..1], b"C");
606
607 assert_eq!(cursor.seek(io::SeekFrom::Current(1)).unwrap(), 27);
608 assert_eq!(cursor.stream_position().unwrap(), 27);
609 cursor.read_exact(&mut data[0..1]).unwrap();
610 assert_eq!(&data[0..1], b"D");
611 }
612}
613