From 6cc48b5c62bac287b8f9f1c79c1fb7486c51b18f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 Mar 2023 04:57:55 +0100 Subject: Move `Canvas` and `QRCode` to `iced` crate Rename `canvas` modules to `geometry` in graphics subcrates --- renderer/src/backend.rs | 4 +- renderer/src/geometry.rs | 168 ++++++++++++++++++++ renderer/src/geometry/cache.rs | 85 ++++++++++ renderer/src/lib.rs | 13 +- renderer/src/widget/canvas.rs | 177 --------------------- renderer/src/widget/canvas/cache.rs | 85 ---------- renderer/src/widget/qr_code.rs | 301 ------------------------------------ 7 files changed, 257 insertions(+), 576 deletions(-) create mode 100644 renderer/src/geometry.rs create mode 100644 renderer/src/geometry/cache.rs delete mode 100644 renderer/src/widget/canvas.rs delete mode 100644 renderer/src/widget/canvas/cache.rs delete mode 100644 renderer/src/widget/qr_code.rs (limited to 'renderer/src') diff --git a/renderer/src/backend.rs b/renderer/src/backend.rs index 6c0b4e5c..b0a409dc 100644 --- a/renderer/src/backend.rs +++ b/renderer/src/backend.rs @@ -1,4 +1,4 @@ -use crate::{Font, Geometry, Point, Size}; +use crate::{Font, Point, Size}; use iced_graphics::backend; use iced_graphics::text; @@ -12,8 +12,6 @@ pub enum Backend { } impl iced_graphics::Backend for Backend { - type Geometry = Geometry; - fn trim_measurements(&mut self) { match self { Self::Wgpu(backend) => backend.trim_measurements(), diff --git a/renderer/src/geometry.rs b/renderer/src/geometry.rs new file mode 100644 index 00000000..e491ea73 --- /dev/null +++ b/renderer/src/geometry.rs @@ -0,0 +1,168 @@ +mod cache; + +pub use cache::Cache; + +pub use iced_graphics::geometry::*; + +use crate::{Backend, Point, Rectangle, Size, Vector}; + +pub enum Frame { + Wgpu(iced_wgpu::geometry::Frame), + TinySkia(iced_tiny_skia::geometry::Frame), +} + +macro_rules! delegate { + ($frame:expr, $name:ident => $body:expr) => { + match $frame { + Self::Wgpu($name) => $body, + Self::TinySkia($name) => $body, + } + }; +} + +impl Frame { + pub fn new(renderer: &crate::Renderer, size: Size) -> Self { + match renderer.backend() { + Backend::Wgpu(_) => { + Frame::Wgpu(iced_wgpu::geometry::Frame::new(size)) + } + Backend::TinySkia(_) => { + Frame::TinySkia(iced_tiny_skia::geometry::Frame::new(size)) + } + } + } + + /// Returns the width of the [`Frame`]. + #[inline] + pub fn width(&self) -> f32 { + delegate!(self, frame => frame.width()) + } + + /// Returns the height of the [`Frame`]. + #[inline] + pub fn height(&self) -> f32 { + delegate!(self, frame => frame.height()) + } + + /// Returns the dimensions of the [`Frame`]. + #[inline] + pub fn size(&self) -> Size { + delegate!(self, frame => frame.size()) + } + + /// Returns the coordinate of the center of the [`Frame`]. + #[inline] + pub fn center(&self) -> Point { + delegate!(self, frame => frame.center()) + } + + /// Draws the given [`Path`] on the [`Frame`] by filling it with the + /// provided style. + pub fn fill(&mut self, path: &Path, fill: impl Into) { + delegate!(self, frame => frame.fill(path, fill)); + } + + /// Draws an axis-aligned rectangle given its top-left corner coordinate and + /// its `Size` on the [`Frame`] by filling it with the provided style. + pub fn fill_rectangle( + &mut self, + top_left: Point, + size: Size, + fill: impl Into, + ) { + delegate!(self, frame => frame.fill_rectangle(top_left, size, fill)); + } + + /// Draws the stroke of the given [`Path`] on the [`Frame`] with the + /// provided style. + pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { + delegate!(self, frame => frame.stroke(path, stroke)); + } + + /// Draws the characters of the given [`Text`] on the [`Frame`], filling + /// them with the given color. + /// + /// __Warning:__ Text currently does not work well with rotations and scale + /// transforms! The position will be correctly transformed, but the + /// resulting glyphs will not be rotated or scaled properly. + /// + /// Additionally, all text will be rendered on top of all the layers of + /// a [`Canvas`]. Therefore, it is currently only meant to be used for + /// overlays, which is the most common use case. + /// + /// Support for vectorial text is planned, and should address all these + /// limitations. + /// + /// [`Canvas`]: crate::widget::Canvas + pub fn fill_text(&mut self, text: impl Into) { + delegate!(self, frame => frame.fill_text(text)); + } + + /// Stores the current transform of the [`Frame`] and executes the given + /// drawing operations, restoring the transform afterwards. + /// + /// This method is useful to compose transforms and perform drawing + /// operations in different coordinate systems. + #[inline] + pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { + delegate!(self, frame => frame.push_transform()); + + f(self); + + delegate!(self, frame => frame.pop_transform()); + } + + /// Executes the given drawing operations within a [`Rectangle`] region, + /// clipping any geometry that overflows its bounds. Any transformations + /// performed are local to the provided closure. + /// + /// This method is useful to perform drawing operations that need to be + /// clipped. + #[inline] + pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) { + let mut frame = match self { + Self::Wgpu(_) => { + Self::Wgpu(iced_wgpu::geometry::Frame::new(region.size())) + } + Self::TinySkia(_) => Self::TinySkia( + iced_tiny_skia::geometry::Frame::new(region.size()), + ), + }; + + f(&mut frame); + + let translation = Vector::new(region.x, region.y); + + match (self, frame) { + (Self::Wgpu(target), Self::Wgpu(frame)) => { + target.clip(frame, translation); + } + (Self::TinySkia(target), Self::TinySkia(frame)) => { + target.clip(frame, translation); + } + _ => unreachable!(), + }; + } + + /// Applies a translation to the current transform of the [`Frame`]. + #[inline] + pub fn translate(&mut self, translation: Vector) { + delegate!(self, frame => frame.translate(translation)); + } + + /// Applies a rotation in radians to the current transform of the [`Frame`]. + #[inline] + pub fn rotate(&mut self, angle: f32) { + delegate!(self, frame => frame.rotate(angle)); + } + + /// Applies a scaling to the current transform of the [`Frame`]. + #[inline] + pub fn scale(&mut self, scale: f32) { + delegate!(self, frame => frame.scale(scale)); + } + + pub fn into_geometry(self) -> Geometry { + Geometry(delegate!(self, frame => frame.into_primitive())) + } +} diff --git a/renderer/src/geometry/cache.rs b/renderer/src/geometry/cache.rs new file mode 100644 index 00000000..1f1febdd --- /dev/null +++ b/renderer/src/geometry/cache.rs @@ -0,0 +1,85 @@ +use crate::geometry::{Frame, Geometry}; +use crate::{Primitive, Renderer, Size}; + +use std::cell::RefCell; +use std::sync::Arc; + +/// A simple cache that stores generated [`Geometry`] to avoid recomputation. +/// +/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer +/// change or it is explicitly cleared. +#[derive(Debug, Default)] +pub struct Cache { + state: RefCell, +} + +#[derive(Debug, Default)] +enum State { + #[default] + Empty, + Filled { + bounds: Size, + primitive: Arc, + }, +} + +impl Cache { + /// Creates a new empty [`Cache`]. + pub fn new() -> Self { + Cache { + state: Default::default(), + } + } + + /// Clears the [`Cache`], forcing a redraw the next time it is used. + pub fn clear(&self) { + *self.state.borrow_mut() = State::Empty; + } + + /// Draws [`Geometry`] using the provided closure and stores it in the + /// [`Cache`]. + /// + /// The closure will only be called when + /// - the bounds have changed since the previous draw call. + /// - the [`Cache`] is empty or has been explicitly cleared. + /// + /// Otherwise, the previously stored [`Geometry`] will be returned. The + /// [`Cache`] is not cleared in this case. In other words, it will keep + /// returning the stored [`Geometry`] if needed. + pub fn draw( + &self, + renderer: &Renderer, + bounds: Size, + draw_fn: impl FnOnce(&mut Frame), + ) -> Geometry { + use std::ops::Deref; + + if let State::Filled { + bounds: cached_bounds, + primitive, + } = self.state.borrow().deref() + { + if *cached_bounds == bounds { + return Geometry(Primitive::Cache { + content: primitive.clone(), + }); + } + } + + let mut frame = Frame::new(renderer, bounds); + draw_fn(&mut frame); + + let primitive = { + let geometry = frame.into_geometry(); + + Arc::new(geometry.0) + }; + + *self.state.borrow_mut() = State::Filled { + bounds, + primitive: primitive.clone(), + }; + + Geometry(Primitive::Cache { content: primitive }) + } +} diff --git a/renderer/src/lib.rs b/renderer/src/lib.rs index d9c85e82..aae3322d 100644 --- a/renderer/src/lib.rs +++ b/renderer/src/lib.rs @@ -1,6 +1,8 @@ -pub mod widget; pub mod window; +#[cfg(feature = "geometry")] +pub mod geometry; + mod backend; mod settings; @@ -19,12 +21,3 @@ pub use iced_graphics::{ /// [`iced`]: https://github.com/iced-rs/iced pub type Renderer = iced_graphics::Renderer; - -#[derive(Debug, Clone)] -pub struct Geometry(pub(crate) Primitive); - -impl From for Primitive { - fn from(geometry: Geometry) -> Self { - geometry.0 - } -} diff --git a/renderer/src/widget/canvas.rs b/renderer/src/widget/canvas.rs deleted file mode 100644 index 35c8fff9..00000000 --- a/renderer/src/widget/canvas.rs +++ /dev/null @@ -1,177 +0,0 @@ -mod cache; - -pub use cache::Cache; - -pub use iced_native::widget::canvas::event::{self, Event}; -pub use iced_native::widget::canvas::fill::{self, Fill}; -pub use iced_native::widget::canvas::gradient::{self, Gradient}; -pub use iced_native::widget::canvas::path::{self, Path}; -pub use iced_native::widget::canvas::stroke::{self, Stroke}; -pub use iced_native::widget::canvas::{ - Canvas, Cursor, LineCap, LineDash, LineJoin, Program, Renderer, Style, Text, -}; - -use crate::{Backend, Point, Rectangle, Size, Vector}; - -pub use crate::Geometry; - -pub enum Frame { - Wgpu(iced_wgpu::canvas::Frame), - TinySkia(iced_tiny_skia::canvas::Frame), -} - -macro_rules! delegate { - ($frame:expr, $name:ident => $body:expr) => { - match $frame { - Self::Wgpu($name) => $body, - Self::TinySkia($name) => $body, - } - }; -} - -impl Frame { - pub fn new(renderer: &crate::Renderer, size: Size) -> Self { - match renderer.backend() { - Backend::Wgpu(_) => { - Frame::Wgpu(iced_wgpu::canvas::Frame::new(size)) - } - Backend::TinySkia(_) => { - Frame::TinySkia(iced_tiny_skia::canvas::Frame::new(size)) - } - } - } - - /// Returns the width of the [`Frame`]. - #[inline] - pub fn width(&self) -> f32 { - delegate!(self, frame => frame.width()) - } - - /// Returns the height of the [`Frame`]. - #[inline] - pub fn height(&self) -> f32 { - delegate!(self, frame => frame.height()) - } - - /// Returns the dimensions of the [`Frame`]. - #[inline] - pub fn size(&self) -> Size { - delegate!(self, frame => frame.size()) - } - - /// Returns the coordinate of the center of the [`Frame`]. - #[inline] - pub fn center(&self) -> Point { - delegate!(self, frame => frame.center()) - } - - /// Draws the given [`Path`] on the [`Frame`] by filling it with the - /// provided style. - pub fn fill(&mut self, path: &Path, fill: impl Into) { - delegate!(self, frame => frame.fill(path, fill)); - } - - /// Draws an axis-aligned rectangle given its top-left corner coordinate and - /// its `Size` on the [`Frame`] by filling it with the provided style. - pub fn fill_rectangle( - &mut self, - top_left: Point, - size: Size, - fill: impl Into, - ) { - delegate!(self, frame => frame.fill_rectangle(top_left, size, fill)); - } - - /// Draws the stroke of the given [`Path`] on the [`Frame`] with the - /// provided style. - pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into>) { - delegate!(self, frame => frame.stroke(path, stroke)); - } - - /// Draws the characters of the given [`Text`] on the [`Frame`], filling - /// them with the given color. - /// - /// __Warning:__ Text currently does not work well with rotations and scale - /// transforms! The position will be correctly transformed, but the - /// resulting glyphs will not be rotated or scaled properly. - /// - /// Additionally, all text will be rendered on top of all the layers of - /// a [`Canvas`]. Therefore, it is currently only meant to be used for - /// overlays, which is the most common use case. - /// - /// Support for vectorial text is planned, and should address all these - /// limitations. - /// - /// [`Canvas`]: crate::widget::Canvas - pub fn fill_text(&mut self, text: impl Into) { - delegate!(self, frame => frame.fill_text(text)); - } - - /// Stores the current transform of the [`Frame`] and executes the given - /// drawing operations, restoring the transform afterwards. - /// - /// This method is useful to compose transforms and perform drawing - /// operations in different coordinate systems. - #[inline] - pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { - delegate!(self, frame => frame.push_transform()); - - f(self); - - delegate!(self, frame => frame.pop_transform()); - } - - /// Executes the given drawing operations within a [`Rectangle`] region, - /// clipping any geometry that overflows its bounds. Any transformations - /// performed are local to the provided closure. - /// - /// This method is useful to perform drawing operations that need to be - /// clipped. - #[inline] - pub fn with_clip(&mut self, region: Rectangle, f: impl FnOnce(&mut Frame)) { - let mut frame = match self { - Self::Wgpu(_) => { - Self::Wgpu(iced_wgpu::canvas::Frame::new(region.size())) - } - Self::TinySkia(_) => Self::TinySkia( - iced_tiny_skia::canvas::Frame::new(region.size()), - ), - }; - - f(&mut frame); - - let translation = Vector::new(region.x, region.y); - - match (self, frame) { - (Self::Wgpu(target), Self::Wgpu(frame)) => { - target.clip(frame, translation); - } - (Self::TinySkia(target), Self::TinySkia(frame)) => { - target.clip(frame, translation); - } - _ => unreachable!(), - }; - } - - /// Applies a translation to the current transform of the [`Frame`]. - #[inline] - pub fn translate(&mut self, translation: Vector) { - delegate!(self, frame => frame.translate(translation)); - } - - /// Applies a rotation in radians to the current transform of the [`Frame`]. - #[inline] - pub fn rotate(&mut self, angle: f32) { - delegate!(self, frame => frame.rotate(angle)); - } - - /// Applies a scaling to the current transform of the [`Frame`]. - #[inline] - pub fn scale(&mut self, scale: f32) { - delegate!(self, frame => frame.scale(scale)); - } - - pub fn into_geometry(self) -> Geometry { - Geometry(delegate!(self, frame => frame.into_primitive())) - } -} diff --git a/renderer/src/widget/canvas/cache.rs b/renderer/src/widget/canvas/cache.rs deleted file mode 100644 index 7d6b4811..00000000 --- a/renderer/src/widget/canvas/cache.rs +++ /dev/null @@ -1,85 +0,0 @@ -use crate::widget::canvas::{Frame, Geometry}; -use crate::{Primitive, Renderer, Size}; - -use std::cell::RefCell; -use std::sync::Arc; - -/// A simple cache that stores generated [`Geometry`] to avoid recomputation. -/// -/// A [`Cache`] will not redraw its geometry unless the dimensions of its layer -/// change or it is explicitly cleared. -#[derive(Debug, Default)] -pub struct Cache { - state: RefCell, -} - -#[derive(Debug, Default)] -enum State { - #[default] - Empty, - Filled { - bounds: Size, - primitive: Arc, - }, -} - -impl Cache { - /// Creates a new empty [`Cache`]. - pub fn new() -> Self { - Cache { - state: Default::default(), - } - } - - /// Clears the [`Cache`], forcing a redraw the next time it is used. - pub fn clear(&self) { - *self.state.borrow_mut() = State::Empty; - } - - /// Draws [`Geometry`] using the provided closure and stores it in the - /// [`Cache`]. - /// - /// The closure will only be called when - /// - the bounds have changed since the previous draw call. - /// - the [`Cache`] is empty or has been explicitly cleared. - /// - /// Otherwise, the previously stored [`Geometry`] will be returned. The - /// [`Cache`] is not cleared in this case. In other words, it will keep - /// returning the stored [`Geometry`] if needed. - pub fn draw( - &self, - renderer: &Renderer, - bounds: Size, - draw_fn: impl FnOnce(&mut Frame), - ) -> Geometry { - use std::ops::Deref; - - if let State::Filled { - bounds: cached_bounds, - primitive, - } = self.state.borrow().deref() - { - if *cached_bounds == bounds { - return Geometry(Primitive::Cache { - content: primitive.clone(), - }); - } - } - - let mut frame = Frame::new(renderer, bounds); - draw_fn(&mut frame); - - let primitive = { - let geometry = frame.into_geometry(); - - Arc::new(geometry.0) - }; - - *self.state.borrow_mut() = State::Filled { - bounds, - primitive: primitive.clone(), - }; - - Geometry(Primitive::Cache { content: primitive }) - } -} diff --git a/renderer/src/widget/qr_code.rs b/renderer/src/widget/qr_code.rs deleted file mode 100644 index aae4ec88..00000000 --- a/renderer/src/widget/qr_code.rs +++ /dev/null @@ -1,301 +0,0 @@ -//! Encode and display information in a QR code. -use crate::widget::canvas; -use crate::Renderer; - -use iced_graphics::renderer; - -use iced_native::layout; -use iced_native::widget::Tree; -use iced_native::{ - Color, Element, Layout, Length, Point, Rectangle, Size, Vector, Widget, -}; -use thiserror::Error; - -const DEFAULT_CELL_SIZE: u16 = 4; -const QUIET_ZONE: usize = 2; - -/// A type of matrix barcode consisting of squares arranged in a grid which -/// can be read by an imaging device, such as a camera. -#[derive(Debug)] -pub struct QRCode<'a> { - state: &'a State, - dark: Color, - light: Color, - cell_size: u16, -} - -impl<'a> QRCode<'a> { - /// Creates a new [`QRCode`] with the provided [`State`]. - pub fn new(state: &'a State) -> Self { - Self { - cell_size: DEFAULT_CELL_SIZE, - dark: Color::BLACK, - light: Color::WHITE, - state, - } - } - - /// Sets both the dark and light [`Color`]s of the [`QRCode`]. - pub fn color(mut self, dark: Color, light: Color) -> Self { - self.dark = dark; - self.light = light; - self - } - - /// Sets the size of the squares of the grid cell of the [`QRCode`]. - pub fn cell_size(mut self, cell_size: u16) -> Self { - self.cell_size = cell_size; - self - } -} - -impl<'a, Message, Theme> Widget> for QRCode<'a> { - fn width(&self) -> Length { - Length::Shrink - } - - fn height(&self) -> Length { - Length::Shrink - } - - fn layout( - &self, - _renderer: &Renderer, - _limits: &layout::Limits, - ) -> layout::Node { - let side_length = (self.state.width + 2 * QUIET_ZONE) as f32 - * f32::from(self.cell_size); - - layout::Node::new(Size::new(side_length, side_length)) - } - - fn draw( - &self, - _state: &Tree, - renderer: &mut Renderer, - _theme: &Theme, - _style: &renderer::Style, - layout: Layout<'_>, - _cursor_position: Point, - _viewport: &Rectangle, - ) { - use iced_native::Renderer as _; - - let bounds = layout.bounds(); - let side_length = self.state.width + 2 * QUIET_ZONE; - - // Reuse cache if possible - let geometry = - self.state.cache.draw(renderer, bounds.size(), |frame| { - // Scale units to cell size - frame.scale(f32::from(self.cell_size)); - - // Draw background - frame.fill_rectangle( - Point::ORIGIN, - Size::new(side_length as f32, side_length as f32), - self.light, - ); - - // Avoid drawing on the quiet zone - frame.translate(Vector::new( - QUIET_ZONE as f32, - QUIET_ZONE as f32, - )); - - // Draw contents - self.state - .contents - .iter() - .enumerate() - .filter(|(_, value)| **value == qrcode::Color::Dark) - .for_each(|(index, _)| { - let row = index / self.state.width; - let column = index % self.state.width; - - frame.fill_rectangle( - Point::new(column as f32, row as f32), - Size::UNIT, - self.dark, - ); - }); - }); - - let translation = Vector::new(bounds.x, bounds.y); - - renderer.with_translation(translation, |renderer| { - renderer.draw_primitive(geometry.0); - }); - } -} - -impl<'a, Message, Theme> From> - for Element<'a, Message, Renderer> -{ - fn from(qr_code: QRCode<'a>) -> Self { - Self::new(qr_code) - } -} - -/// The state of a [`QRCode`]. -/// -/// It stores the data that will be displayed. -#[derive(Debug)] -pub struct State { - contents: Vec, - width: usize, - cache: canvas::Cache, -} - -impl State { - /// Creates a new [`State`] with the provided data. - /// - /// This method uses an [`ErrorCorrection::Medium`] and chooses the smallest - /// size to display the data. - pub fn new(data: impl AsRef<[u8]>) -> Result { - let encoded = qrcode::QrCode::new(data)?; - - Ok(Self::build(encoded)) - } - - /// Creates a new [`State`] with the provided [`ErrorCorrection`]. - pub fn with_error_correction( - data: impl AsRef<[u8]>, - error_correction: ErrorCorrection, - ) -> Result { - let encoded = qrcode::QrCode::with_error_correction_level( - data, - error_correction.into(), - )?; - - Ok(Self::build(encoded)) - } - - /// Creates a new [`State`] with the provided [`Version`] and - /// [`ErrorCorrection`]. - pub fn with_version( - data: impl AsRef<[u8]>, - version: Version, - error_correction: ErrorCorrection, - ) -> Result { - let encoded = qrcode::QrCode::with_version( - data, - version.into(), - error_correction.into(), - )?; - - Ok(Self::build(encoded)) - } - - fn build(encoded: qrcode::QrCode) -> Self { - let width = encoded.width(); - let contents = encoded.into_colors(); - - Self { - contents, - width, - cache: canvas::Cache::new(), - } - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -/// The size of a [`QRCode`]. -/// -/// The higher the version the larger the grid of cells, and therefore the more -/// information the [`QRCode`] can carry. -pub enum Version { - /// A normal QR code version. It should be between 1 and 40. - Normal(u8), - - /// A micro QR code version. It should be between 1 and 4. - Micro(u8), -} - -impl From for qrcode::Version { - fn from(version: Version) -> Self { - match version { - Version::Normal(v) => qrcode::Version::Normal(i16::from(v)), - Version::Micro(v) => qrcode::Version::Micro(i16::from(v)), - } - } -} - -/// The error correction level. -/// -/// It controls the amount of data that can be damaged while still being able -/// to recover the original information. -/// -/// A higher error correction level allows for more corrupted data. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum ErrorCorrection { - /// Low error correction. 7% of the data can be restored. - Low, - /// Medium error correction. 15% of the data can be restored. - Medium, - /// Quartile error correction. 25% of the data can be restored. - Quartile, - /// High error correction. 30% of the data can be restored. - High, -} - -impl From for qrcode::EcLevel { - fn from(ec_level: ErrorCorrection) -> Self { - match ec_level { - ErrorCorrection::Low => qrcode::EcLevel::L, - ErrorCorrection::Medium => qrcode::EcLevel::M, - ErrorCorrection::Quartile => qrcode::EcLevel::Q, - ErrorCorrection::High => qrcode::EcLevel::H, - } - } -} - -/// An error that occurred when building a [`State`] for a [`QRCode`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)] -pub enum Error { - /// The data is too long to encode in a QR code for the chosen [`Version`]. - #[error( - "The data is too long to encode in a QR code for the chosen version" - )] - DataTooLong, - - /// The chosen [`Version`] and [`ErrorCorrection`] combination is invalid. - #[error( - "The chosen version and error correction level combination is invalid." - )] - InvalidVersion, - - /// One or more characters in the provided data are not supported by the - /// chosen [`Version`]. - #[error( - "One or more characters in the provided data are not supported by the \ - chosen version" - )] - UnsupportedCharacterSet, - - /// The chosen ECI designator is invalid. A valid designator should be - /// between 0 and 999999. - #[error( - "The chosen ECI designator is invalid. A valid designator should be \ - between 0 and 999999." - )] - InvalidEciDesignator, - - /// A character that does not belong to the character set was found. - #[error("A character that does not belong to the character set was found")] - InvalidCharacter, -} - -impl From for Error { - fn from(error: qrcode::types::QrError) -> Self { - use qrcode::types::QrError; - - match error { - QrError::DataTooLong => Error::DataTooLong, - QrError::InvalidVersion => Error::InvalidVersion, - QrError::UnsupportedCharacterSet => Error::UnsupportedCharacterSet, - QrError::InvalidEciDesignator => Error::InvalidEciDesignator, - QrError::InvalidCharacter => Error::InvalidCharacter, - } - } -} -- cgit