epson/
async_tokio.rs

1// {{{ Copyright (c) Paul R. Tagliamonte <paultag@gmail.com>, 2016,2024
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE. }}}
20
21#![cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
22
23use super::{
24    Alignment, Barcode, CharacterSet, Command, Error as EpsonError, HriPosition, Model, Writer,
25};
26use tokio::io::{AsyncWrite, AsyncWriteExt};
27
28/// All possible errors that can be returned from the AsyncWriter struct.
29#[derive(Debug)]
30pub enum Error {
31    /// Raw Epson error, as defined in [EpsonError].
32    Epson(EpsonError),
33
34    /// Underlying Tokio i/o issue.
35    Tokio(tokio::io::Error),
36}
37
38impl From<EpsonError> for Error {
39    fn from(ee: EpsonError) -> Error {
40        Error::Epson(ee)
41    }
42}
43
44impl From<tokio::io::Error> for Error {
45    fn from(te: tokio::io::Error) -> Error {
46        Error::Tokio(te)
47    }
48}
49
50impl std::error::Error for Error {}
51
52impl std::fmt::Display for Error {
53    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
54        write!(f, "{self:?}")
55    }
56}
57
58/// Result alias for the AsyncWriter methods.
59type Result<T> = std::result::Result<T, Error>;
60
61/// Trait to add async epson methods.
62pub trait AsyncWriterExt
63where
64    Self: Sized,
65{
66    /// Inner type of the Async writer
67    type Write: AsyncWrite;
68
69    /// Create a new Writer, wrapping the provided `tokio::io::AsyncWrite`.
70    fn open(model: Model, w: Self::Write) -> impl Future<Output = Result<Self>>;
71
72    /// initialize the epson printer
73    fn init(&mut self) -> impl Future<Output = Result<()>>;
74
75    /// cut the printer paper
76    fn cut(&mut self) -> impl Future<Output = Result<()>>;
77
78    /// Set unicode mode on the printer, if supported.
79    fn set_unicode(&mut self) -> impl Future<Output = Result<()>>;
80
81    /// Set the specific [CharacterSet] to be used on bytes sent to the
82    /// printer. Some models do not support sets other than `Raw`, so
83    /// check your specific printer model.
84    fn character_set(&mut self, c: CharacterSet) -> impl Future<Output = Result<()>>;
85
86    /// If true, text printed after this command will be underlined. If false,
87    /// it will remove an underline if one was set.
88    fn underline(&mut self, state: bool) -> impl Future<Output = Result<()>>;
89
90    /// If true, emphasize the text printed after this command. if false,
91    /// remove emphasis on the text.
92    fn emphasize(&mut self, state: bool) -> impl Future<Output = Result<()>>;
93
94    /// If true, reverse the color of the text printed after this command.
95    /// if false, return the colors to normal.
96    fn reverse(&mut self, state: bool) -> impl Future<Output = Result<()>>;
97
98    /// If true, double-strike the text printed after this command.
99    /// If false, remove the double-strike.
100    fn double_strike(&mut self, state: bool) -> impl Future<Output = Result<()>>;
101
102    /// Set the horizontal justification of the text printed after this
103    /// command.
104    fn justify(&mut self, alignment: Alignment) -> impl Future<Output = Result<()>>;
105
106    /// Feed the specified number of lines out of the printer.
107    fn feed(&mut self, count: u8) -> impl Future<Output = Result<()>>;
108
109    /// Set the printer speed to the provided value.
110    fn speed(&mut self, speed: u8) -> impl Future<Output = Result<()>>;
111
112    /// Set the print position of HRI (Human Readable Interpretation) characters for barcodes.
113    fn set_hri_position(&mut self, position: HriPosition) -> impl Future<Output = Result<()>>;
114
115    /// Print a greyscale image.
116    ///
117    /// Currently, this image must have a width that's 8 bit aligned,
118    /// and the size may not be larger than a uint16 in height. The
119    /// width of the image is constrained by the underling printer model
120    /// provided to `Self::open`.
121    fn print_image(&mut self, img: image::GrayImage) -> impl Future<Output = Result<()>>;
122
123    /// Print a grayscale image, without any model checks. This will let you
124    /// do all sorts of invalid things. Don't use this if you can avoid it,
125    /// it may result in trash being printed.
126    fn print_image_unchecked(&mut self, img: image::GrayImage) -> impl Future<Output = Result<()>>;
127
128    /// Print a barcode.
129    ///
130    /// The barcode will be printed according to the currently set HRI position.
131    /// Use `set_hri_position` to control the position of the human-readable text.
132    fn print_barcode(&mut self, barcode: Barcode) -> impl Future<Output = Result<()>>;
133
134    /// Send a raw command to the Epson printer.
135    fn write_command(&mut self, cmd: Command) -> impl Future<Output = Result<()>>;
136
137    /// Write the full buffer `buf` to the underlying socket.
138    fn write_all(&mut self, buf: &[u8]) -> impl Future<Output = Result<()>>;
139}
140
141impl<WriteT> AsyncWriterExt for Writer<WriteT>
142where
143    WriteT: Unpin,
144    WriteT: Send,
145    WriteT: AsyncWrite,
146{
147    type Write = WriteT;
148
149    async fn open(model: Model, w: WriteT) -> Result<Self> {
150        let mut r = Self { w, model };
151        r.init().await?;
152        Ok(r)
153    }
154
155    async fn init(&mut self) -> Result<()> {
156        self.write_command(Command::Init).await
157    }
158
159    async fn cut(&mut self) -> Result<()> {
160        self.write_command(Command::Cut).await
161    }
162
163    async fn set_unicode(&mut self) -> Result<()> {
164        self.character_set(CharacterSet::Unicode).await
165    }
166
167    async fn character_set(&mut self, c: CharacterSet) -> Result<()> {
168        if !self.model.supports_character_set(c) {
169            return Err(EpsonError::Unsupported.into());
170        }
171        self.write_command(Command::CharacterSet(c)).await
172    }
173
174    async fn underline(&mut self, state: bool) -> Result<()> {
175        self.write_command(Command::Underline(state)).await
176    }
177
178    async fn emphasize(&mut self, state: bool) -> Result<()> {
179        self.write_command(Command::Emphasize(state)).await
180    }
181
182    async fn reverse(&mut self, state: bool) -> Result<()> {
183        self.write_command(Command::Reverse(state)).await
184    }
185
186    async fn double_strike(&mut self, state: bool) -> Result<()> {
187        self.write_command(Command::DoubleStrike(state)).await
188    }
189
190    async fn justify(&mut self, alignment: Alignment) -> Result<()> {
191        self.write_command(Command::Justification(alignment)).await
192    }
193
194    async fn feed(&mut self, count: u8) -> Result<()> {
195        self.write_command(Command::Feed(count)).await
196    }
197
198    async fn speed(&mut self, speed: u8) -> Result<()> {
199        self.write_command(Command::Speed(speed)).await
200    }
201
202    async fn set_hri_position(&mut self, position: HriPosition) -> Result<()> {
203        self.write_command(Command::SetHriPosition(position)).await
204    }
205
206    async fn print_image(&mut self, img: image::GrayImage) -> Result<()> {
207        self.model.check_image(&img)?;
208        self.print_image_unchecked(img).await
209    }
210
211    async fn print_image_unchecked(&mut self, img: image::GrayImage) -> Result<()> {
212        self.write_command(Command::Image(img)).await
213    }
214
215    async fn print_barcode(&mut self, barcode: Barcode) -> Result<()> {
216        self.write_command(Command::Barcode(barcode)).await
217    }
218
219    async fn write_command(&mut self, cmd: Command) -> Result<()> {
220        self.w.write_all(&cmd.as_bytes()?).await?;
221        Ok(())
222    }
223
224    async fn write_all(&mut self, buf: &[u8]) -> Result<()> {
225        self.w.write_all(buf).await?;
226        Ok(())
227    }
228}
229
230// vim: foldmethod=marker