allsorts_subset_browser/binary/
write.rs

1#![deny(missing_docs)]
2
3//! Write binary data
4
5use std::iter;
6use std::marker::PhantomData;
7
8use crate::binary::read::{ReadArray, ReadArrayCow, ReadScope, ReadUnchecked};
9use crate::binary::{I16Be, I32Be, I64Be, U16Be, U24Be, U32Be, I8, U8};
10use crate::error::WriteError;
11
12/// An in-memory buffer that implements `WriteContext`.
13pub struct WriteBuffer {
14    data: Vec<u8>,
15}
16
17struct WriteSlice<'a> {
18    offset: usize,
19    data: &'a mut [u8],
20}
21
22/// A `WriteContext` implementation that just counts the bytes written.
23pub struct WriteCounter {
24    count: usize,
25}
26
27/// A `WriteContext` implementation that writes nothing.
28struct NullWriter;
29
30/// A placeholder for a value that will be filled in later using WriteContext::write_placeholder
31pub struct Placeholder<T, HostType>
32where
33    T: WriteBinaryDep<HostType>,
34{
35    offset: usize,
36    length: usize,
37    marker: PhantomData<T>,
38    host: PhantomData<HostType>,
39}
40
41/// Trait that describes a type that can be written to a `WriteContext` in binary form.
42pub trait WriteBinary<HostType = Self> {
43    /// The type of the value returned by `write`.
44    type Output;
45
46    /// Write the binary representation of Self to `ctxt`.
47    fn write<C: WriteContext>(ctxt: &mut C, val: HostType) -> Result<Self::Output, WriteError>;
48}
49
50/// Trait that describes a type that can be written to a `WriteContext` in binary form with
51/// dependent arguments.
52pub trait WriteBinaryDep<HostType = Self> {
53    /// The type of the arguments supplied to `write_dep`.
54    type Args;
55    /// The type of the value returned by `write_dep`.
56    type Output;
57
58    /// Write the binary representation of Self to `ctxt`.
59    fn write_dep<C: WriteContext>(
60        ctxt: &mut C,
61        val: HostType,
62        args: Self::Args,
63    ) -> Result<Self::Output, WriteError>;
64}
65
66/// Trait for types that can have binary data written to them.
67pub trait WriteContext {
68    /// Write a `ReadArray` instance to a `WriteContext`.
69    fn write_array<'a, T>(&mut self, array: &ReadArray<'a, T>) -> Result<(), WriteError>
70    where
71        Self: Sized,
72        T: ReadUnchecked + WriteBinary<<T as ReadUnchecked>::HostType>,
73    {
74        <&ReadArray<'_, _>>::write(self, array)
75    }
76
77    /// Write a `Vec` into a `WriteContext`.
78    fn write_vec<T, HostType>(&mut self, vec: Vec<HostType>) -> Result<(), WriteError>
79    where
80        Self: Sized,
81        T: WriteBinary<HostType>,
82    {
83        for val in vec {
84            T::write(self, val)?;
85        }
86
87        Ok(())
88    }
89
90    /// Write a slice of values into a `WriteContext`.
91    fn write_iter<T, HostType>(
92        &mut self,
93        iter: impl Iterator<Item = HostType>,
94    ) -> Result<(), WriteError>
95    where
96        Self: Sized,
97        T: WriteBinary<HostType>,
98    {
99        for val in iter {
100            T::write(self, val)?;
101        }
102
103        Ok(())
104    }
105
106    /// Write a slice of bytes to a `WriteContext`.
107    fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError>;
108
109    /// Write the specified number of zero bytes to the `WriteContext`.
110    fn write_zeros(&mut self, count: usize) -> Result<(), WriteError>;
111
112    /// The total number of bytes written so far.
113    fn bytes_written(&self) -> usize;
114
115    /// Return a placeholder to `T` in the context for filling in later.
116    fn placeholder<'a, T, HostType>(&mut self) -> Result<Placeholder<T, HostType>, WriteError>
117    where
118        T: WriteBinary<HostType> + ReadUnchecked,
119    {
120        let offset = self.bytes_written();
121        self.write_zeros(T::SIZE)?;
122
123        Ok(Placeholder {
124            offset,
125            length: T::SIZE,
126            marker: PhantomData,
127            host: PhantomData,
128        })
129    }
130
131    /// Reserve space for `count` bytes in the context for filling in later.
132    fn reserve<'a, T, HostType>(
133        &mut self,
134        count: usize,
135    ) -> Result<Placeholder<T, &'a HostType>, WriteError>
136    where
137        T: WriteBinaryDep<&'a HostType>,
138    {
139        let offset = self.bytes_written();
140        self.write_zeros(count)?;
141
142        Ok(Placeholder {
143            offset,
144            length: count,
145            marker: PhantomData,
146            host: PhantomData,
147        })
148    }
149
150    /// Return a `Vec` of `count` placeholders of type `T`.
151    fn placeholder_array<'a, T, HostType>(
152        &mut self,
153        count: usize,
154    ) -> Result<Vec<Placeholder<T, HostType>>, WriteError>
155    where
156        T: WriteBinary<HostType> + ReadUnchecked,
157    {
158        (0..count)
159            .map(|_| self.placeholder::<T, HostType>())
160            .collect()
161    }
162
163    /// Consumes the placeholder and writes the supplied value into it
164    fn write_placeholder<T, HostType>(
165        &mut self,
166        placeholder: Placeholder<T, HostType>,
167        val: HostType,
168    ) -> Result<T::Output, WriteError>
169    where
170        T: WriteBinary<HostType>;
171
172    /// Consumes the placeholder and writes the supplied value into it.
173    /// `WriteBinaryDep` version
174    fn write_placeholder_dep<T, HostType>(
175        &mut self,
176        placeholder: Placeholder<T, HostType>,
177        val: HostType,
178        args: T::Args,
179    ) -> Result<T::Output, WriteError>
180    where
181        T: WriteBinaryDep<HostType>;
182}
183
184/// Write `T` into a `WriteBuffer` and return it
185pub fn buffer<HostType, T: WriteBinaryDep<HostType>>(
186    writeable: HostType,
187    args: T::Args,
188) -> Result<(T::Output, WriteBuffer), WriteError> {
189    let mut buffer = WriteBuffer::new();
190    let output = T::write_dep(&mut buffer, writeable, args)?;
191    Ok((output, buffer))
192}
193
194impl<T, HostType> WriteBinaryDep<HostType> for T
195where
196    T: WriteBinary<HostType>,
197{
198    type Args = ();
199    type Output = T::Output;
200
201    fn write_dep<C: WriteContext>(
202        ctxt: &mut C,
203        val: HostType,
204        (): Self::Args,
205    ) -> Result<Self::Output, WriteError> {
206        T::write(ctxt, val)
207    }
208}
209
210impl<T> WriteBinary<T> for U8
211where
212    T: Into<u8>,
213{
214    type Output = ();
215
216    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
217        let val: u8 = t.into();
218        ctxt.write_bytes(&[val])
219    }
220}
221
222impl<T> WriteBinary<T> for I8
223where
224    T: Into<i8>,
225{
226    type Output = ();
227
228    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
229        let val: i8 = t.into();
230        ctxt.write_bytes(&val.to_be_bytes())
231    }
232}
233
234impl<T> WriteBinary<T> for I16Be
235where
236    T: Into<i16>,
237{
238    type Output = ();
239
240    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
241        let val: i16 = t.into();
242        ctxt.write_bytes(&val.to_be_bytes())
243    }
244}
245
246impl<T> WriteBinary<T> for U16Be
247where
248    T: Into<u16>,
249{
250    type Output = ();
251
252    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
253        let val: u16 = t.into();
254        ctxt.write_bytes(&val.to_be_bytes())
255    }
256}
257
258impl<T> WriteBinary<T> for U24Be
259where
260    T: Into<u32>,
261{
262    type Output = ();
263
264    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
265        let val: u32 = t.into();
266        if val > 0xFF_FFFF {
267            return Err(WriteError::BadValue);
268        }
269        ctxt.write_bytes(&val.to_be_bytes()[1..4])
270    }
271}
272
273impl<T> WriteBinary<T> for I32Be
274where
275    T: Into<i32>,
276{
277    type Output = ();
278
279    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
280        let val: i32 = t.into();
281        ctxt.write_bytes(&val.to_be_bytes())
282    }
283}
284
285impl<T> WriteBinary<T> for U32Be
286where
287    T: Into<u32>,
288{
289    type Output = ();
290
291    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
292        let val: u32 = t.into();
293        ctxt.write_bytes(&val.to_be_bytes())
294    }
295}
296
297impl<T> WriteBinary<T> for I64Be
298where
299    T: Into<i64>,
300{
301    type Output = ();
302
303    fn write<C: WriteContext>(ctxt: &mut C, t: T) -> Result<(), WriteError> {
304        let val: i64 = t.into();
305        ctxt.write_bytes(&val.to_be_bytes())
306    }
307}
308
309impl WriteContext for WriteBuffer {
310    fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
311        self.data.extend(data.iter());
312        Ok(())
313    }
314
315    fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
316        let zeros = iter::repeat(0).take(count);
317        self.data.extend(zeros);
318        Ok(())
319    }
320
321    fn bytes_written(&self) -> usize {
322        self.data.len()
323    }
324
325    fn write_placeholder<T, HostType>(
326        &mut self,
327        placeholder: Placeholder<T, HostType>,
328        val: HostType,
329    ) -> Result<T::Output, WriteError>
330    where
331        T: WriteBinary<HostType>,
332    {
333        let data = &mut self.data[placeholder.offset..];
334        let data = &mut data[0..placeholder.length];
335        let mut slice = WriteSlice { offset: 0, data };
336        T::write(&mut slice, val)
337    }
338
339    fn write_placeholder_dep<T, HostType>(
340        &mut self,
341        placeholder: Placeholder<T, HostType>,
342        val: HostType,
343        args: T::Args,
344    ) -> Result<T::Output, WriteError>
345    where
346        T: WriteBinaryDep<HostType>,
347    {
348        let data = &mut self.data[placeholder.offset..];
349        let data = &mut data[0..placeholder.length];
350        let mut slice = WriteSlice { offset: 0, data };
351        T::write_dep(&mut slice, val, args)
352    }
353}
354
355impl<'a> WriteContext for WriteSlice<'a> {
356    fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
357        let data_len = data.len();
358        let self_len = self.data.len();
359
360        if data_len <= self_len {
361            let subslice = &mut self.data[self.offset..][0..data_len];
362            subslice.copy_from_slice(data);
363            self.offset += data_len;
364            Ok(())
365        } else {
366            Err(WriteError::PlaceholderMismatch)
367        }
368    }
369
370    fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
371        for i in 0..count.min(self.data.len()) {
372            self.data[i] = 0;
373        }
374
375        Ok(())
376    }
377
378    fn bytes_written(&self) -> usize {
379        self.data.len()
380    }
381
382    fn write_placeholder<T, HostType>(
383        &mut self,
384        _placeholder: Placeholder<T, HostType>,
385        _val: HostType,
386    ) -> Result<T::Output, WriteError>
387    where
388        T: WriteBinary<HostType>,
389    {
390        unimplemented!()
391    }
392
393    fn write_placeholder_dep<T, HostType>(
394        &mut self,
395        _placeholder: Placeholder<T, HostType>,
396        _val: HostType,
397        _args: T::Args,
398    ) -> Result<T::Output, WriteError>
399    where
400        T: WriteBinaryDep<HostType>,
401    {
402        unimplemented!()
403    }
404}
405
406impl WriteContext for WriteCounter {
407    fn write_bytes(&mut self, data: &[u8]) -> Result<(), WriteError> {
408        self.count += data.len();
409        Ok(())
410    }
411
412    fn write_zeros(&mut self, count: usize) -> Result<(), WriteError> {
413        self.count += count;
414        Ok(())
415    }
416
417    fn bytes_written(&self) -> usize {
418        self.count
419    }
420
421    fn write_placeholder<T, HostType>(
422        &mut self,
423        _placeholder: Placeholder<T, HostType>,
424        val: HostType,
425    ) -> Result<T::Output, WriteError>
426    where
427        T: WriteBinary<HostType>,
428    {
429        let mut null = NullWriter;
430        T::write(&mut null, val)
431    }
432
433    fn write_placeholder_dep<T, HostType>(
434        &mut self,
435        _placeholder: Placeholder<T, HostType>,
436        val: HostType,
437        args: T::Args,
438    ) -> Result<T::Output, WriteError>
439    where
440        T: WriteBinaryDep<HostType>,
441    {
442        let mut null = NullWriter;
443        T::write_dep(&mut null, val, args)
444    }
445}
446
447impl WriteContext for NullWriter {
448    fn write_bytes(&mut self, _data: &[u8]) -> Result<(), WriteError> {
449        Ok(())
450    }
451
452    fn write_zeros(&mut self, _count: usize) -> Result<(), WriteError> {
453        Ok(())
454    }
455
456    fn bytes_written(&self) -> usize {
457        0
458    }
459
460    fn write_placeholder<T, HostType>(
461        &mut self,
462        _placeholder: Placeholder<T, HostType>,
463        _val: HostType,
464    ) -> Result<T::Output, WriteError>
465    where
466        T: WriteBinary<HostType>,
467    {
468        unimplemented!()
469    }
470
471    fn write_placeholder_dep<T, HostType>(
472        &mut self,
473        _placeholder: Placeholder<T, HostType>,
474        _val: HostType,
475        _args: T::Args,
476    ) -> Result<T::Output, WriteError>
477    where
478        T: WriteBinaryDep<HostType>,
479    {
480        unimplemented!()
481    }
482}
483
484impl<'a, T> WriteBinary for &ReadArray<'a, T>
485where
486    T: ReadUnchecked + WriteBinary<<T as ReadUnchecked>::HostType>,
487{
488    type Output = ();
489
490    fn write<C: WriteContext>(ctxt: &mut C, array: Self) -> Result<(), WriteError> {
491        for val in array.into_iter() {
492            T::write(ctxt, val)?;
493        }
494
495        Ok(())
496    }
497}
498
499impl<'a, T> WriteBinary<&Self> for ReadArrayCow<'a, T>
500where
501    T: ReadUnchecked + WriteBinary<<T as ReadUnchecked>::HostType>,
502    T::HostType: Copy,
503{
504    type Output = ();
505
506    fn write<C: WriteContext>(ctxt: &mut C, array: &Self) -> Result<(), WriteError> {
507        for val in array.iter() {
508            T::write(ctxt, val)?;
509        }
510
511        Ok(())
512    }
513}
514
515impl<'a> WriteBinary for ReadScope<'a> {
516    type Output = ();
517
518    fn write<C: WriteContext>(ctxt: &mut C, scope: Self) -> Result<(), WriteError> {
519        ctxt.write_bytes(scope.data())
520    }
521}
522
523impl WriteBuffer {
524    /// Create a new, empty `WriteBuffer`
525    pub fn new() -> Self {
526        WriteBuffer { data: Vec::new() }
527    }
528
529    /// Retrieve a slice of the data held by this buffer
530    pub fn bytes(&self) -> &[u8] {
531        &self.data
532    }
533
534    /// Clear the internal data so that this buffer can be reused
535    pub fn clear(&mut self) {
536        self.data.clear();
537    }
538
539    /// Returns the current size of the data held by this buffer
540    pub fn len(&self) -> usize {
541        self.data.len()
542    }
543
544    /// Consume `self` and return the inner buffer
545    pub fn into_inner(self) -> Vec<u8> {
546        self.data
547    }
548}
549
550impl WriteCounter {
551    /// Create a new, empty `WriteCounter`
552    pub fn new() -> Self {
553        WriteCounter { count: 0 }
554    }
555}
556
557#[cfg(test)]
558mod tests {
559    use super::*;
560    use crate::tag;
561
562    struct TestTable {
563        tag: u32,
564    }
565
566    struct BigStruct {
567        tag: u32,
568    }
569
570    impl WriteBinary<Self> for TestTable {
571        type Output = ();
572
573        fn write<C: WriteContext>(ctxt: &mut C, val: Self) -> Result<(), WriteError> {
574            U32Be::write(ctxt, val.tag)
575        }
576    }
577
578    impl WriteBinary<&Self> for BigStruct {
579        type Output = ();
580
581        fn write<C: WriteContext>(ctxt: &mut C, val: &Self) -> Result<(), WriteError> {
582            U32Be::write(ctxt, val.tag)
583        }
584    }
585
586    #[test]
587    fn test_basic() {
588        let mut ctxt = WriteBuffer::new();
589        let table = TestTable { tag: tag::GLYF };
590        let big = BigStruct { tag: tag::BLOC };
591
592        TestTable::write(&mut ctxt, table).unwrap();
593        BigStruct::write(&mut ctxt, &big).unwrap();
594
595        assert_eq!(ctxt.bytes(), b"glyfbloc")
596    }
597
598    #[test]
599    fn test_write_u24be() {
600        let mut ctxt = WriteBuffer::new();
601        U24Be::write(&mut ctxt, 0x10203u32).unwrap();
602        assert_eq!(ctxt.bytes(), &[1, 2, 3]);
603
604        // Check out of range value
605        match U24Be::write(&mut ctxt, std::u32::MAX) {
606            Err(WriteError::BadValue) => {}
607            _ => panic!("Expected WriteError::BadValue"),
608        }
609    }
610
611    #[test]
612    fn test_write_placeholder() {
613        let mut ctxt = WriteBuffer::new();
614        U8::write(&mut ctxt, 1).unwrap();
615        let placeholder = ctxt.placeholder::<U16Be, u16>().unwrap();
616        U8::write(&mut ctxt, 3).unwrap();
617        ctxt.write_placeholder(placeholder, 2).unwrap();
618        assert_eq!(ctxt.bytes(), &[1, 0, 2, 3]);
619    }
620
621    #[test]
622    fn test_write_placeholder_overflow() {
623        // Test that trying to write more data than reserved results in an error
624        let mut ctxt = WriteBuffer::new();
625        let placeholder = ctxt.reserve::<BigStruct, _>(1).unwrap();
626        let value = BigStruct { tag: 1234 };
627        assert!(ctxt.write_placeholder(placeholder, &value).is_err());
628    }
629}