2019-10-23 01:33:38 +11:00
//! # Style
//!
//! The `style` module provides a functionality to apply attributes and colors on your text.
//!
//! This documentation does not contain a lot of examples. The reason is that it's fairly
//! obvious how to use this crate. Although, we do provide
2019-12-13 17:12:35 +11:00
//! [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) repository
2019-10-23 01:33:38 +11:00
//! to demonstrate the capabilities.
//!
//! ## Platform-specific Notes
//!
//! Not all features are supported on all terminals/platforms. You should always consult
//! platform-specific notes of the following types:
//!
//! * [Color](enum.Color.html#platform-specific-notes)
//! * [Attribute](enum.Attribute.html#platform-specific-notes)
//!
//! ## Examples
2019-11-19 07:50:57 +11:00
//!
2019-11-02 04:09:05 +11:00
//! A few examples of how to use the style module.
2019-10-23 01:33:38 +11:00
//!
//! ### Colors
2019-11-19 07:50:57 +11:00
//!
2019-11-02 04:09:05 +11:00
//! How to change the terminal text color.
2019-10-23 01:33:38 +11:00
//!
2019-11-19 07:50:57 +11:00
//! Command API:
2019-11-02 04:09:05 +11:00
//!
//! Using the Command API to color text.
2019-10-23 01:33:38 +11:00
//!
//! ```no_run
2023-04-08 02:17:10 +10:00
//! use std::io::{self, Write};
//! use crossterm::execute;
2019-12-05 03:26:57 +11:00
//! use crossterm::style::{Print, SetForegroundColor, SetBackgroundColor, ResetColor, Color, Attribute};
2019-10-23 01:33:38 +11:00
//!
2023-04-08 02:17:10 +10:00
//! fn main() -> io::Result<()> {
2019-10-23 01:33:38 +11:00
//! execute!(
2023-04-08 02:17:10 +10:00
//! io::stdout(),
2019-10-23 01:33:38 +11:00
//! // Blue foreground
2019-11-01 07:02:04 +11:00
//! SetForegroundColor(Color::Blue),
2019-10-23 01:33:38 +11:00
//! // Red background
2019-11-01 07:02:04 +11:00
//! SetBackgroundColor(Color::Red),
2019-12-05 03:26:57 +11:00
//! // Print text
//! Print("Blue text on Red.".to_string()),
2019-10-23 01:33:38 +11:00
//! // Reset to default colors
//! ResetColor
//! )
//! }
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Functions:
2019-11-02 04:09:05 +11:00
//!
2021-06-10 23:29:22 +10:00
//! Using functions from [`Stylize`](crate::style::Stylize) on a `String` or `&'static str` to color
//! it.
2019-10-23 01:33:38 +11:00
//!
//! ```no_run
2021-06-10 23:29:22 +10:00
//! use crossterm::style::Stylize;
2019-10-23 01:33:38 +11:00
//!
//! println!("{}", "Red foreground color & blue background.".red().on_blue());
//! ```
//!
//! ### Attributes
2019-11-19 07:50:57 +11:00
//!
2022-02-17 23:49:41 +11:00
//! How to apply terminal attributes to text.
2019-11-02 04:09:05 +11:00
//!
2019-11-19 07:50:57 +11:00
//! Command API:
2019-10-23 01:33:38 +11:00
//!
2019-11-02 04:09:05 +11:00
//! Using the Command API to set attributes.
2019-10-23 01:33:38 +11:00
//!
//! ```no_run
2023-04-08 02:17:10 +10:00
//! use std::io::{self, Write};
2019-10-23 01:33:38 +11:00
//!
2023-08-05 23:24:54 +10:00
//! use crossterm::execute;
//! use crossterm::style::{Attribute, Print, SetAttribute};
2019-10-23 01:33:38 +11:00
//!
2023-04-08 02:17:10 +10:00
//! fn main() -> io::Result<()> {
2019-10-23 01:33:38 +11:00
//! execute!(
2023-04-08 02:17:10 +10:00
//! io::stdout(),
2019-10-23 01:33:38 +11:00
//! // Set to bold
2019-11-01 07:02:04 +11:00
//! SetAttribute(Attribute::Bold),
2019-12-05 03:26:57 +11:00
//! Print("Bold text here.".to_string()),
2019-10-23 01:33:38 +11:00
//! // Reset all attributes
2019-11-01 07:02:04 +11:00
//! SetAttribute(Attribute::Reset)
2019-10-23 01:33:38 +11:00
//! )
//! }
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Functions:
2019-11-02 04:09:05 +11:00
//!
2021-06-10 23:29:22 +10:00
//! Using [`Stylize`](crate::style::Stylize) functions on a `String` or `&'static str` to set
//! attributes to it.
2019-10-23 01:33:38 +11:00
//!
//! ```no_run
2021-06-10 23:29:22 +10:00
//! use crossterm::style::Stylize;
2019-10-23 01:33:38 +11:00
//!
//! println!("{}", "Bold".bold());
//! println!("{}", "Underlined".underlined());
//! println!("{}", "Negative".negative());
//! ```
//!
2019-11-19 07:50:57 +11:00
//! Displayable:
2019-11-02 04:09:05 +11:00
//!
//! [`Attribute`](enum.Attribute.html) implements [Display](https://doc.rust-lang.org/beta/std/fmt/trait.Display.html) and therefore it can be formatted like:
2019-10-23 01:33:38 +11:00
//!
//! ```no_run
2019-11-01 07:02:04 +11:00
//! use crossterm::style::Attribute;
2019-10-23 01:33:38 +11:00
//!
//! println!(
//! "{} Underlined {} No Underline",
//! Attribute::Underlined,
//! Attribute::NoUnderline
//! );
//! ```
2020-12-28 17:56:32 +11:00
use std ::{
env ,
fmt ::{ self , Display } ,
} ;
2019-10-23 01:33:38 +11:00
2021-06-10 23:29:22 +10:00
use crate ::command ::execute_fmt ;
2021-01-04 00:29:29 +11:00
use crate ::{ csi , impl_display , Command } ;
2019-10-23 01:33:38 +11:00
2019-11-19 07:50:57 +11:00
pub use self ::{
2020-02-08 00:06:41 +11:00
attributes ::Attributes ,
2019-11-19 07:50:57 +11:00
content_style ::ContentStyle ,
styled_content ::StyledContent ,
2021-06-10 23:29:22 +10:00
stylize ::Stylize ,
2020-07-07 03:14:53 +10:00
types ::{ Attribute , Color , Colored , Colors } ,
2019-11-19 07:50:57 +11:00
} ;
2019-10-23 01:33:38 +11:00
2020-02-08 00:06:41 +11:00
mod attributes ;
2019-11-01 07:02:04 +11:00
mod content_style ;
mod styled_content ;
2021-06-10 23:29:22 +10:00
mod stylize ;
2019-11-01 07:02:04 +11:00
mod sys ;
2020-07-07 03:14:53 +10:00
mod types ;
2019-10-23 01:33:38 +11:00
2019-10-28 07:07:09 +11:00
/// Creates a `StyledContent`.
2019-10-23 01:33:38 +11:00
///
/// This could be used to style any type that implements `Display` with colors and text attributes.
///
2019-10-28 07:07:09 +11:00
/// See [`StyledContent`](struct.StyledContent.html) for more info.
2019-10-23 01:33:38 +11:00
///
/// # Examples
///
/// ```no_run
2021-06-10 23:29:22 +10:00
/// use crossterm::style::{style, Stylize, Color};
2019-10-23 01:33:38 +11:00
///
2019-10-28 07:07:09 +11:00
/// let styled_content = style("Blue colored text on yellow background")
2019-10-23 01:33:38 +11:00
/// .with(Color::Blue)
/// .on(Color::Yellow);
///
2019-10-28 07:07:09 +11:00
/// println!("{}", styled_content);
2019-10-23 01:33:38 +11:00
/// ```
2021-01-04 19:16:08 +11:00
pub fn style < D : Display > ( val : D ) -> StyledContent < D > {
2019-10-28 07:07:09 +11:00
ContentStyle ::new ( ) . apply ( val )
2019-10-23 01:33:38 +11:00
}
2019-11-01 07:02:04 +11:00
/// Returns available color count.
2019-10-23 01:33:38 +11:00
///
2019-11-01 07:02:04 +11:00
/// # Notes
2019-10-23 01:33:38 +11:00
///
2019-11-01 07:02:04 +11:00
/// This does not always provide a good result.
pub fn available_color_count ( ) -> u16 {
env ::var ( " TERM " )
. map ( | x | if x . contains ( " 256color " ) { 256 } else { 8 } )
. unwrap_or ( 8 )
2019-10-23 01:33:38 +11:00
}
2019-11-01 07:02:04 +11:00
/// A command that sets the the foreground color.
2019-10-23 01:33:38 +11:00
///
/// See [`Color`](enum.Color.html) for more info.
///
2020-07-07 03:14:53 +10:00
/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
/// color in one command.
///
2019-10-23 01:33:38 +11:00
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-01-29 06:20:26 +11:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
2019-11-01 07:02:04 +11:00
pub struct SetForegroundColor ( pub Color ) ;
2019-10-23 01:33:38 +11:00
2019-11-01 07:02:04 +11:00
impl Command for SetForegroundColor {
2020-12-28 17:56:32 +11:00
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-01-04 00:29:29 +11:00
write! ( f , csi! ( " {}m " ) , Colored ::ForegroundColor ( self . 0 ) )
2019-10-23 01:33:38 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2019-11-01 07:02:04 +11:00
sys ::windows ::set_foreground_color ( self . 0 )
2019-10-23 01:33:38 +11:00
}
}
2019-11-01 07:02:04 +11:00
/// A command that sets the the background color.
2019-10-23 01:33:38 +11:00
///
/// See [`Color`](enum.Color.html) for more info.
///
2020-07-07 03:14:53 +10:00
/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
/// color with one command.
///
2019-10-23 01:33:38 +11:00
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-01-29 06:20:26 +11:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
2019-11-01 07:02:04 +11:00
pub struct SetBackgroundColor ( pub Color ) ;
2019-10-23 01:33:38 +11:00
2019-11-01 07:02:04 +11:00
impl Command for SetBackgroundColor {
2020-12-28 17:56:32 +11:00
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-01-04 00:29:29 +11:00
write! ( f , csi! ( " {}m " ) , Colored ::BackgroundColor ( self . 0 ) )
2019-10-23 01:33:38 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2019-11-01 07:02:04 +11:00
sys ::windows ::set_background_color ( self . 0 )
2019-10-23 01:33:38 +11:00
}
}
2022-07-01 05:33:49 +10:00
/// A command that sets the the underline color.
///
/// See [`Color`](enum.Color.html) for more info.
///
/// [`SetColors`](struct.SetColors.html) can also be used to set both the foreground and background
/// color with one command.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub struct SetUnderlineColor ( pub Color ) ;
impl Command for SetUnderlineColor {
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
write! ( f , csi! ( " {}m " ) , Colored ::UnderlineColor ( self . 0 ) )
}
2022-07-03 05:39:25 +10:00
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2022-07-03 05:39:25 +10:00
Err ( std ::io ::Error ::new (
std ::io ::ErrorKind ::Other ,
" SetUnderlineColor not supported by winapi. " ,
) )
}
2022-07-01 05:33:49 +10:00
}
2020-07-07 03:14:53 +10:00
/// A command that optionally sets the foreground and/or background color.
///
/// For example:
/// ```no_run
/// use std::io::{stdout, Write};
2020-12-28 19:47:20 +11:00
///
2020-07-07 03:14:53 +10:00
/// use crossterm::execute;
/// use crossterm::style::{Color::{Green, Black}, Colors, Print, SetColors};
///
/// execute!(
/// stdout(),
/// SetColors(Colors::new(Green, Black)),
/// Print("Hello, world!".to_string()),
/// ).unwrap();
/// ```
///
/// See [`Colors`](struct.Colors.html) for more info.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub struct SetColors ( pub Colors ) ;
2020-12-28 17:56:32 +11:00
impl Command for SetColors {
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
if let Some ( color ) = self . 0. foreground {
2021-01-04 00:29:29 +11:00
SetForegroundColor ( color ) . write_ansi ( f ) ? ;
2020-07-07 03:14:53 +10:00
}
2020-12-28 17:56:32 +11:00
if let Some ( color ) = self . 0. background {
2021-01-04 00:29:29 +11:00
SetBackgroundColor ( color ) . write_ansi ( f ) ? ;
2020-07-07 03:14:53 +10:00
}
Ok ( ( ) )
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2020-07-07 03:14:53 +10:00
if let Some ( color ) = self . 0. foreground {
sys ::windows ::set_foreground_color ( color ) ? ;
}
if let Some ( color ) = self . 0. background {
sys ::windows ::set_background_color ( color ) ? ;
}
Ok ( ( ) )
}
}
2019-11-01 07:02:04 +11:00
/// A command that sets an attribute.
2019-10-23 01:33:38 +11:00
///
/// See [`Attribute`](enum.Attribute.html) for more info.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-01-29 06:20:26 +11:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
2019-11-01 07:02:04 +11:00
pub struct SetAttribute ( pub Attribute ) ;
2019-10-23 01:33:38 +11:00
2019-11-01 07:02:04 +11:00
impl Command for SetAttribute {
2020-12-28 17:56:32 +11:00
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-01-04 00:29:29 +11:00
write! ( f , csi! ( " {}m " ) , self . 0. sgr ( ) )
2019-10-23 01:33:38 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2019-10-23 01:33:38 +11:00
// attributes are not supported by WinAPI.
2020-02-08 00:06:41 +11:00
Ok ( ( ) )
}
}
/// A command that sets several attributes.
///
/// See [`Attributes`](struct.Attributes.html) for more info.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub struct SetAttributes ( pub Attributes ) ;
impl Command for SetAttributes {
2020-12-28 17:56:32 +11:00
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-01-04 00:29:29 +11:00
for attr in Attribute ::iterator ( ) {
if self . 0. has ( attr ) {
SetAttribute ( attr ) . write_ansi ( f ) ? ;
}
}
Ok ( ( ) )
2020-02-08 00:06:41 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2020-02-08 00:06:41 +11:00
// attributes are not supported by WinAPI.
2019-10-23 01:33:38 +11:00
Ok ( ( ) )
}
}
2022-07-22 05:05:02 +10:00
/// A command that sets a style (colors and attributes).
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub struct SetStyle ( pub ContentStyle ) ;
impl Command for SetStyle {
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
if let Some ( bg ) = self . 0. background_color {
execute_fmt ( f , SetBackgroundColor ( bg ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
if let Some ( fg ) = self . 0. foreground_color {
execute_fmt ( f , SetForegroundColor ( fg ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
if let Some ( ul ) = self . 0. underline_color {
execute_fmt ( f , SetUnderlineColor ( ul ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
if ! self . 0. attributes . is_empty ( ) {
execute_fmt ( f , SetAttributes ( self . 0. attributes ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
Ok ( ( ) )
}
2022-07-27 00:01:16 +10:00
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2022-07-27 00:01:16 +10:00
panic! ( " tried to execute SetStyle command using WinAPI, use ANSI instead " ) ;
}
#[ cfg(windows) ]
fn is_ansi_code_supported ( & self ) -> bool {
true
}
2022-07-22 05:05:02 +10:00
}
2019-11-01 07:02:04 +11:00
/// A command that prints styled content.
2019-10-23 01:33:38 +11:00
///
2019-10-28 07:07:09 +11:00
/// See [`StyledContent`](struct.StyledContent.html) for more info.
2019-10-23 01:33:38 +11:00
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-08-03 16:06:09 +10:00
#[ derive(Debug, Copy, Clone) ]
2020-12-28 17:56:32 +11:00
pub struct PrintStyledContent < D : Display > ( pub StyledContent < D > ) ;
2019-10-23 01:33:38 +11:00
2020-12-28 17:56:32 +11:00
impl < D : Display > Command for PrintStyledContent < D > {
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-06-10 23:29:22 +10:00
let style = self . 0. style ( ) ;
let mut reset_background = false ;
let mut reset_foreground = false ;
let mut reset = false ;
if let Some ( bg ) = style . background_color {
execute_fmt ( f , SetBackgroundColor ( bg ) ) . map_err ( | _ | fmt ::Error ) ? ;
reset_background = true ;
}
if let Some ( fg ) = style . foreground_color {
execute_fmt ( f , SetForegroundColor ( fg ) ) . map_err ( | _ | fmt ::Error ) ? ;
reset_foreground = true ;
}
2022-07-01 05:33:49 +10:00
if let Some ( ul ) = style . underline_color {
execute_fmt ( f , SetUnderlineColor ( ul ) ) . map_err ( | _ | fmt ::Error ) ? ;
reset_foreground = true ;
}
2021-06-10 23:29:22 +10:00
if ! style . attributes . is_empty ( ) {
execute_fmt ( f , SetAttributes ( style . attributes ) ) . map_err ( | _ | fmt ::Error ) ? ;
reset = true ;
}
write! ( f , " {} " , self . 0. content ( ) ) ? ;
if reset {
// NOTE: This will reset colors even though self has no colors, hence produce unexpected
// resets.
// TODO: reset the set attributes only.
execute_fmt ( f , ResetColor ) . map_err ( | _ | fmt ::Error ) ? ;
} else {
// NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
if reset_background {
execute_fmt ( f , SetBackgroundColor ( Color ::Reset ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
if reset_foreground {
execute_fmt ( f , SetForegroundColor ( Color ::Reset ) ) . map_err ( | _ | fmt ::Error ) ? ;
}
}
Ok ( ( ) )
2019-10-23 01:33:38 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2019-10-23 01:33:38 +11:00
Ok ( ( ) )
}
}
2019-11-01 07:02:04 +11:00
/// A command that resets the colors back to default.
2019-10-23 01:33:38 +11:00
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-01-29 06:20:26 +11:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
2019-10-23 01:33:38 +11:00
pub struct ResetColor ;
impl Command for ResetColor {
2020-12-28 17:56:32 +11:00
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
2021-01-04 00:29:29 +11:00
f . write_str ( csi! ( " 0m " ) )
2019-10-23 01:33:38 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2019-11-01 07:02:04 +11:00
sys ::windows ::reset ( )
2019-10-23 01:33:38 +11:00
}
}
2019-12-05 03:26:57 +11:00
/// A command that prints the given displayable type.
///
/// Commands must be executed/queued for execution otherwise they do nothing.
2020-01-29 06:20:26 +11:00
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
2020-12-28 17:56:32 +11:00
pub struct Print < T : Display > ( pub T ) ;
2019-12-05 03:26:57 +11:00
2020-12-28 17:56:32 +11:00
impl < T : Display > Command for Print < T > {
fn write_ansi ( & self , f : & mut impl fmt ::Write ) -> fmt ::Result {
write! ( f , " {} " , self . 0 )
2019-12-05 03:26:57 +11:00
}
#[ cfg(windows) ]
2023-04-08 02:17:10 +10:00
fn execute_winapi ( & self ) -> std ::io ::Result < ( ) > {
2021-06-10 23:20:00 +10:00
panic! ( " tried to execute Print command using WinAPI, use ANSI instead " ) ;
}
#[ cfg(windows) ]
fn is_ansi_code_supported ( & self ) -> bool {
true
2019-12-05 03:26:57 +11:00
}
}
2020-12-28 17:56:32 +11:00
impl < T : Display > Display for Print < T > {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
self . 0. fmt ( f )
2019-12-05 03:26:57 +11:00
}
}
2019-11-01 07:02:04 +11:00
impl_display! ( for SetForegroundColor ) ;
impl_display! ( for SetBackgroundColor ) ;
2020-07-07 03:14:53 +10:00
impl_display! ( for SetColors ) ;
2019-11-01 07:02:04 +11:00
impl_display! ( for SetAttribute ) ;
2019-10-30 17:37:57 +11:00
impl_display! ( for PrintStyledContent < String > ) ;
impl_display! ( for PrintStyledContent < & 'static str > ) ;
2019-10-23 01:33:38 +11:00
impl_display! ( for ResetColor ) ;
2021-01-04 00:29:29 +11:00
/// Utility function for ANSI parsing in Color and Colored.
2022-02-17 23:49:41 +11:00
/// Gets the next element of `iter` and tries to parse it as a `u8`.
2021-01-04 00:29:29 +11:00
fn parse_next_u8 < ' a > ( iter : & mut impl Iterator < Item = & ' a str > ) -> Option < u8 > {
2021-06-10 23:20:00 +10:00
iter . next ( ) . and_then ( | s | s . parse ( ) . ok ( ) )
2021-01-04 00:29:29 +11:00
}