write_into/lib.rs
1//! Defines a trait built on top of [`io::Write`] to write things _into_ it.
2//!
3//! ```no_run
4//! use std::io;
5//!
6//! trait WriteInto {
7//! type Output;
8//! fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output>;
9//! }
10//! ```
11//!
12//! The crate also provides wrappers, such as [`BigEndian`] and [`LittleEndian`], to write values
13//! in particular formats.
14//!
15//! # Example
16//!
17//! ```
18//! use write_into::{BigEndian, write_into};
19//!
20//! let mut buffer = Vec::new();
21//! write_into(&mut buffer, BigEndian(0xCAFEBABEu32)).unwrap();
22//! assert_eq!(&buffer, &[0xCA, 0xFE, 0xBA, 0xBE]);
23//! ```
24
25mod endianness;
26mod leb128;
27mod plain;
28mod sequence;
29mod sized;
30
31use std::io;
32
33pub use endianness::BigEndian;
34pub use endianness::LittleEndian;
35pub use leb128::Sleb128;
36pub use leb128::Uleb128;
37pub use plain::Plain;
38pub use sequence::Sequence;
39pub use sequence::SizedSequence;
40pub use sized::Sized;
41
42/// Writes value into I/O sink.
43pub trait WriteInto {
44 /// Result of [`WriteInto::write_into`] function (e.g. `()` or [`usize`]).
45 type Output;
46
47 /// Writes value into I/O sink.
48 fn write_into(self, sink: &mut impl io::Write) -> io::Result<Self::Output>;
49}
50
51/// An alias for [`WriteInto::write_into`] for writing `write_into(sink, Wrapper(...))` instead of
52/// `Wrapper(...).write_into(sink)`.
53#[inline]
54pub fn write_into<T: WriteInto>(sink: &mut impl io::Write, value: T) -> io::Result<T::Output> {
55 value.write_into(sink)
56}
57
58/// Aligns position in the I/O sink to the given boundary and returns a new position.
59///
60/// # Example
61///
62/// ```
63/// use std::io;
64/// use write_into::{BigEndian, align_position, write_into};
65///
66/// let mut buffer = io::Cursor::new(Vec::new());
67/// write_into(&mut buffer, BigEndian(0xAABBu16)).unwrap();
68/// let aligned_position = align_position(&mut buffer, 4).unwrap();
69/// write_into(&mut buffer, BigEndian(0xCCDDu16)).unwrap();
70/// assert_eq!(aligned_position, 4);
71/// assert_eq!(buffer.get_ref(), &[0xAA, 0xBB, 0x00, 0x00, 0xCC, 0xDD]);
72/// ```
73pub fn align_position(sink: &mut impl io::Seek, boundary: u64) -> io::Result<u64> {
74 let position = sink.stream_position()?;
75 let alignment = boundary - (position + boundary) % boundary;
76 sink.seek(io::SeekFrom::Current(alignment as i64))
77}