1use std::io::Write;
19
20use pdfboss_core::source::BoxFuture;
21
22use crate::error::{Error, Result};
23
24pub trait AsyncByteSink {
31 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> BoxFuture<'a, Result<()>>;
33}
34
35impl<S: AsyncByteSink + ?Sized> AsyncByteSink for &mut S {
40 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> BoxFuture<'a, Result<()>> {
41 (**self).write_all(buf)
42 }
43}
44
45impl AsyncByteSink for Vec<u8> {
48 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> BoxFuture<'a, Result<()>> {
49 self.extend_from_slice(buf);
50 Box::pin(std::future::ready(Ok(())))
51 }
52}
53
54#[derive(Debug, Clone)]
64pub struct Immediate<W>(pub W);
65
66impl<W: Write> AsyncByteSink for Immediate<W> {
67 fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> BoxFuture<'a, Result<()>> {
68 let outcome = self.0.write_all(buf).map_err(Error::from);
69 Box::pin(std::future::ready(outcome))
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use std::cell::RefCell;
76 use std::io::Write;
77 use std::rc::Rc;
78
79 use pdfboss_core::block_on;
80
81 use super::{AsyncByteSink, Immediate};
82
83 #[test]
84 fn a_vec_is_a_sink() {
85 let mut sink = Vec::new();
86 block_on(AsyncByteSink::write_all(&mut sink, b"abc")).expect("a Vec accepts everything");
87 block_on(AsyncByteSink::write_all(&mut sink, b"def")).expect("a Vec accepts everything");
88 assert_eq!(sink, b"abcdef");
89 }
90
91 #[test]
92 fn a_reference_to_a_sink_is_a_sink() {
93 fn feed<S: AsyncByteSink>(mut sink: S) -> S {
94 block_on(sink.write_all(b"xy")).expect("the test sinks accept everything");
95 sink
96 }
97
98 let mut sink = Vec::new();
99 feed(&mut sink);
100 let sink = feed(sink);
101 assert_eq!(sink, b"xyxy");
102 }
103
104 #[test]
105 fn immediate_writes_through_to_the_writer() {
106 let mut sink = Immediate(Vec::new());
107 block_on(sink.write_all(b"hello")).expect("a Vec accepts everything");
108 assert_eq!(sink.0, b"hello");
109 }
110
111 struct SharedWriter(Rc<RefCell<Vec<u8>>>);
115
116 impl Write for SharedWriter {
117 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
118 self.0.borrow_mut().extend_from_slice(buf);
119 Ok(buf.len())
120 }
121
122 fn flush(&mut self) -> std::io::Result<()> {
123 Ok(())
124 }
125 }
126
127 #[test]
128 fn immediate_futures_are_send_even_over_a_non_send_writer() {
129 fn assert_send<T: Send>(_: &T) {}
130
131 let shared = Rc::new(RefCell::new(Vec::new()));
132 let mut sink = Immediate(SharedWriter(Rc::clone(&shared)));
133 let future = sink.write_all(b"eager");
134 assert_send(&future);
135 block_on(future).expect("the shared writer accepts everything");
136 assert_eq!(*shared.borrow(), b"eager");
137 }
138
139 #[test]
143 fn immediate_writes_eagerly() {
144 let shared = Rc::new(RefCell::new(Vec::new()));
145 let mut sink = Immediate(SharedWriter(Rc::clone(&shared)));
146 let unpolled = sink.write_all(b"already there");
147 assert_eq!(*shared.borrow(), b"already there");
148 drop(unpolled);
149 }
150
151 struct Refusing;
153
154 impl Write for Refusing {
155 fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
156 Err(std::io::Error::other("refused"))
157 }
158
159 fn flush(&mut self) -> std::io::Result<()> {
160 Ok(())
161 }
162 }
163
164 #[test]
165 fn immediate_surfaces_write_errors() {
166 let mut sink = Immediate(Refusing);
167 let err = block_on(sink.write_all(b"x")).unwrap_err();
168 assert!(matches!(err, crate::error::Error::Io(_)));
169 }
170}