1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-12-18 01:33:59 +01:00

rename AtError => Error (#275)

* refactor(settings)!: rename AtError => Error

and remove AtResult from public API

* update changelog

* recover from file metadata errors
This commit is contained in:
Rob Ede 2022-08-10 10:13:34 +02:00 committed by GitHub
parent a325f5dd02
commit e61dbae860
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 72 additions and 67 deletions

View File

@ -2,11 +2,15 @@
## Unreleased - 2022-xx-xx ## Unreleased - 2022-xx-xx
- Rename `AtError => Error`.
- Remove `AtResult` type alias.
## 0.6.0 - 2022-07-31 ## 0.6.0 - 2022-07-31
- Update Actix Web dependencies to v4 ecosystem. - Update Actix Web dependencies to v4 ecosystem.
- Rename `actix.ssl` settings object to `actix.tls`. - Rename `actix.ssl` settings object to `actix.tls`.
- `NoSettings` is now marked `#[non_exhaustive]`. - `NoSettings` is now marked `#[non_exhaustive]`.
## 0.5.2 - 2022-07-31 ## 0.5.2 - 2022-07-31
- Adopted into @actix org from <https://github.com/jjpe/actix-settings>. - Adopted into @actix org from <https://github.com/jjpe/actix-settings>.

View File

@ -2,12 +2,9 @@ use std::{env::VarError, io, num::ParseIntError, path::PathBuf, str::ParseBoolEr
use toml::de::Error as TomlError; use toml::de::Error as TomlError;
/// Convenience type alias for `Result<T, AtError>`.
pub type AtResult<T> = std::result::Result<T, AtError>;
/// Errors that can be returned from methods in this crate. /// Errors that can be returned from methods in this crate.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum AtError { pub enum Error {
/// Environment variable does not exists or is invalid. /// Environment variable does not exists or is invalid.
EnvVarError(VarError), EnvVarError(VarError),
@ -42,7 +39,7 @@ pub enum AtError {
macro_rules! InvalidValue { macro_rules! InvalidValue {
(expected: $expected:expr, got: $got:expr,) => { (expected: $expected:expr, got: $got:expr,) => {
crate::AtError::InvalidValue { crate::Error::InvalidValue {
expected: $expected, expected: $expected,
got: $got.to_string(), got: $got.to_string(),
file: file!(), file: file!(),
@ -52,56 +49,56 @@ macro_rules! InvalidValue {
}; };
} }
impl From<io::Error> for AtError { impl From<io::Error> for Error {
fn from(err: io::Error) -> Self { fn from(err: io::Error) -> Self {
Self::IoError(ioe::IoError::from(err)) Self::IoError(ioe::IoError::from(err))
} }
} }
impl From<ioe::IoError> for AtError { impl From<ioe::IoError> for Error {
fn from(err: ioe::IoError) -> Self { fn from(err: ioe::IoError) -> Self {
Self::IoError(err) Self::IoError(err)
} }
} }
impl From<ParseBoolError> for AtError { impl From<ParseBoolError> for Error {
fn from(err: ParseBoolError) -> Self { fn from(err: ParseBoolError) -> Self {
Self::ParseBoolError(err) Self::ParseBoolError(err)
} }
} }
impl From<ParseIntError> for AtError { impl From<ParseIntError> for Error {
fn from(err: ParseIntError) -> Self { fn from(err: ParseIntError) -> Self {
Self::ParseIntError(err) Self::ParseIntError(err)
} }
} }
impl From<TomlError> for AtError { impl From<TomlError> for Error {
fn from(err: TomlError) -> Self { fn from(err: TomlError) -> Self {
Self::TomlError(err) Self::TomlError(err)
} }
} }
impl From<VarError> for AtError { impl From<VarError> for Error {
fn from(err: VarError) -> Self { fn from(err: VarError) -> Self {
Self::EnvVarError(err) Self::EnvVarError(err)
} }
} }
impl From<AtError> for io::Error { impl From<Error> for io::Error {
fn from(err: AtError) -> Self { fn from(err: Error) -> Self {
match err { match err {
AtError::EnvVarError(var_error) => { Error::EnvVarError(var_error) => {
let msg = format!("Env var error: {}", var_error); let msg = format!("Env var error: {}", var_error);
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }
AtError::FileExists(path_buf) => { Error::FileExists(path_buf) => {
let msg = format!("File exists: {}", path_buf.display()); let msg = format!("File exists: {}", path_buf.display());
io::Error::new(io::ErrorKind::AlreadyExists, msg) io::Error::new(io::ErrorKind::AlreadyExists, msg)
} }
AtError::InvalidValue { Error::InvalidValue {
expected, expected,
ref got, ref got,
file, file,
@ -115,24 +112,24 @@ impl From<AtError> for io::Error {
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }
AtError::IoError(io_error) => io_error.into(), Error::IoError(io_error) => io_error.into(),
AtError::ParseBoolError(parse_bool_error) => { Error::ParseBoolError(parse_bool_error) => {
let msg = format!("Failed to parse boolean: {}", parse_bool_error); let msg = format!("Failed to parse boolean: {}", parse_bool_error);
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }
AtError::ParseIntError(parse_int_error) => { Error::ParseIntError(parse_int_error) => {
let msg = format!("Failed to parse integer: {}", parse_int_error); let msg = format!("Failed to parse integer: {}", parse_int_error);
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }
AtError::ParseAddressError(string) => { Error::ParseAddressError(string) => {
let msg = format!("Failed to parse address: {}", string); let msg = format!("Failed to parse address: {}", string);
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }
AtError::TomlError(toml_error) => { Error::TomlError(toml_error) => {
let msg = format!("TOML error: {}", toml_error); let msg = format!("TOML error: {}", toml_error);
io::Error::new(io::ErrorKind::InvalidInput, msg) io::Error::new(io::ErrorKind::InvalidInput, msg)
} }

View File

@ -89,13 +89,16 @@ mod error;
mod parse; mod parse;
mod settings; mod settings;
pub use self::error::{AtError, AtResult}; pub use self::error::Error;
pub use self::parse::Parse; pub use self::parse::Parse;
pub use self::settings::{ pub use self::settings::{
ActixSettings, Address, Backlog, KeepAlive, MaxConnectionRate, MaxConnections, Mode, ActixSettings, Address, Backlog, KeepAlive, MaxConnectionRate, MaxConnections, Mode,
NumWorkers, Timeout, Tls, NumWorkers, Timeout, Tls,
}; };
/// Convenience type alias for `Result<T, AtError>`.
type AsResult<T> = std::result::Result<T, Error>;
/// Wrapper for server and application-specific settings. /// Wrapper for server and application-specific settings.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
#[serde(bound = "A: Deserialize<'de>")] #[serde(bound = "A: Deserialize<'de>")]
@ -129,7 +132,7 @@ where
/// ///
/// If the file doesn't exist, it is generated from the default TOML template, after which the /// If the file doesn't exist, it is generated from the default TOML template, after which the
/// newly generated file is read in and parsed. /// newly generated file is read in and parsed.
pub fn parse_toml<P>(filepath: P) -> AtResult<Self> pub fn parse_toml<P>(filepath: P) -> AsResult<Self>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
@ -140,8 +143,9 @@ where
} }
let mut f = File::open(filepath)?; let mut f = File::open(filepath)?;
// TODO: don't bail on metadata fail let len_guess = f.metadata().map(|md| md.len()).unwrap_or(128);
let mut contents = String::with_capacity(f.metadata()?.len() as usize);
let mut contents = String::with_capacity(len_guess as usize);
f.read_to_string(&mut contents)?; f.read_to_string(&mut contents)?;
Ok(toml::from_str::<Self>(&contents)?) Ok(toml::from_str::<Self>(&contents)?)
@ -150,13 +154,13 @@ where
/// Parse an instance of `Self` straight from the default TOML template. /// Parse an instance of `Self` straight from the default TOML template.
// TODO: make infallible // TODO: make infallible
// TODO: consider "template" rename // TODO: consider "template" rename
pub fn from_default_template() -> AtResult<Self> { pub fn from_default_template() -> AsResult<Self> {
Self::from_template(Self::DEFAULT_TOML_TEMPLATE) Self::from_template(Self::DEFAULT_TOML_TEMPLATE)
} }
/// Parse an instance of `Self` straight from the default TOML template. /// Parse an instance of `Self` straight from the default TOML template.
// TODO: consider "template" rename // TODO: consider "template" rename
pub fn from_template(template: &str) -> AtResult<Self> { pub fn from_template(template: &str) -> AsResult<Self> {
Ok(toml::from_str(template)?) Ok(toml::from_str(template)?)
} }
@ -165,14 +169,14 @@ where
/// # Errors /// # Errors
/// Returns a [`FileExists`](crate::AtError::FileExists) error if a file already exists at that /// Returns a [`FileExists`](crate::AtError::FileExists) error if a file already exists at that
/// location. /// location.
pub fn write_toml_file<P>(filepath: P) -> AtResult<()> pub fn write_toml_file<P>(filepath: P) -> AsResult<()>
where where
P: AsRef<Path>, P: AsRef<Path>,
{ {
let filepath = filepath.as_ref(); let filepath = filepath.as_ref();
if filepath.exists() { if filepath.exists() {
return Err(AtError::FileExists(filepath.to_path_buf())); return Err(Error::FileExists(filepath.to_path_buf()));
} }
let mut file = File::create(filepath)?; let mut file = File::create(filepath)?;
@ -188,7 +192,7 @@ where
/// ``` /// ```
/// use actix_settings::{Settings, Mode}; /// use actix_settings::{Settings, Mode};
/// ///
/// # fn inner() -> actix_settings::AtResult<()> { /// # fn inner() -> Result<(), actix_settings::Error> {
/// let mut settings = Settings::from_default_template()?; /// let mut settings = Settings::from_default_template()?;
/// assert_eq!(settings.actix.mode, Mode::Development); /// assert_eq!(settings.actix.mode, Mode::Development);
/// ///
@ -196,7 +200,7 @@ where
/// assert_eq!(settings.actix.mode, Mode::Production); /// assert_eq!(settings.actix.mode, Mode::Production);
/// # Ok(()) } /// # Ok(()) }
/// ``` /// ```
pub fn override_field<F, V>(field: &mut F, value: V) -> AtResult<()> pub fn override_field<F, V>(field: &mut F, value: V) -> AsResult<()>
where where
F: Parse, F: Parse,
V: AsRef<str>, V: AsRef<str>,
@ -213,7 +217,7 @@ where
/// ///
/// std::env::set_var("OVERRIDE__MODE", "production"); /// std::env::set_var("OVERRIDE__MODE", "production");
/// ///
/// # fn inner() -> actix_settings::AtResult<()> { /// # fn inner() -> Result<(), actix_settings::Error> {
/// let mut settings = Settings::from_default_template()?; /// let mut settings = Settings::from_default_template()?;
/// assert_eq!(settings.actix.mode, Mode::Development); /// assert_eq!(settings.actix.mode, Mode::Development);
/// ///
@ -221,14 +225,14 @@ where
/// assert_eq!(settings.actix.mode, Mode::Production); /// assert_eq!(settings.actix.mode, Mode::Production);
/// # Ok(()) } /// # Ok(()) }
/// ``` /// ```
pub fn override_field_with_env_var<F, N>(field: &mut F, var_name: N) -> AtResult<()> pub fn override_field_with_env_var<F, N>(field: &mut F, var_name: N) -> AsResult<()>
where where
F: Parse, F: Parse,
N: AsRef<str>, N: AsRef<str>,
{ {
match env::var(var_name.as_ref()) { match env::var(var_name.as_ref()) {
Err(env::VarError::NotPresent) => Ok((/*NOP*/)), Err(env::VarError::NotPresent) => Ok((/*NOP*/)),
Err(var_error) => Err(AtError::from(var_error)), Err(var_error) => Err(Error::from(var_error)),
Ok(value) => Self::override_field(field, value), Ok(value) => Self::override_field(field, value),
} }
} }

View File

@ -1,16 +1,16 @@
use std::{path::PathBuf, str::FromStr}; use std::{path::PathBuf, str::FromStr};
use crate::AtError; use crate::Error;
/// A specialized `FromStr` trait that returns [`AtError`] errors /// A specialized `FromStr` trait that returns [`AtError`] errors
pub trait Parse: Sized { pub trait Parse: Sized {
/// Parse `Self` from `string`. /// Parse `Self` from `string`.
fn parse(string: &str) -> Result<Self, AtError>; fn parse(string: &str) -> Result<Self, Error>;
} }
impl Parse for bool { impl Parse for bool {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
Self::from_str(string).map_err(AtError::from) Self::from_str(string).map_err(Error::from)
} }
} }
@ -18,8 +18,8 @@ macro_rules! impl_parse_for_int_type {
($($int_type:ty),+ $(,)?) => { ($($int_type:ty),+ $(,)?) => {
$( $(
impl Parse for $int_type { impl Parse for $int_type {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
Self::from_str(string).map_err(AtError::from) Self::from_str(string).map_err(Error::from)
} }
} }
)+ )+
@ -28,13 +28,13 @@ macro_rules! impl_parse_for_int_type {
impl_parse_for_int_type![i8, i16, i32, i64, i128, u8, u16, u32, u64, u128]; impl_parse_for_int_type![i8, i16, i32, i64, i128, u8, u16, u32, u64, u128];
impl Parse for String { impl Parse for String {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
Ok(string.to_string()) Ok(string.to_string())
} }
} }
impl Parse for PathBuf { impl Parse for PathBuf {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
Ok(PathBuf::from(string)) Ok(PathBuf::from(string))
} }
} }

View File

@ -2,7 +2,7 @@ use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use crate::{AtError, Parse}; use crate::{Error, Parse};
static ADDR_REGEX: Lazy<Regex> = Lazy::new(|| { static ADDR_REGEX: Lazy<Regex> = Lazy::new(|| {
Regex::new( Regex::new(
@ -48,14 +48,14 @@ pub struct Address {
} }
impl Parse for Address { impl Parse for Address {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
let mut items = string let mut items = string
.trim() .trim()
.trim_start_matches('[') .trim_start_matches('[')
.trim_end_matches(']') .trim_end_matches(']')
.split(','); .split(',');
let parse_error = || AtError::ParseAddressError(string.to_string()); let parse_error = || Error::ParseAddressError(string.to_string());
if !ADDR_REGEX.is_match(string) { if !ADDR_REGEX.is_match(string) {
return Err(parse_error()); return Err(parse_error());
@ -69,8 +69,8 @@ impl Parse for Address {
} }
impl Parse for Vec<Address> { impl Parse for Vec<Address> {
fn parse(string: &str) -> Result<Self, AtError> { fn parse(string: &str) -> Result<Self, Error> {
let parse_error = || AtError::ParseAddressError(string.to_string()); let parse_error = || Error::ParseAddressError(string.to_string());
if !ADDR_LIST_REGEX.is_match(string) { if !ADDR_LIST_REGEX.is_match(string) {
return Err(parse_error()); return Err(parse_error());

View File

@ -2,7 +2,7 @@ use std::fmt;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// The maximum number of pending connections. /// The maximum number of pending connections.
/// ///
@ -22,7 +22,7 @@ pub enum Backlog {
} }
impl Parse for Backlog { impl Parse for Backlog {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
match string { match string {
"default" => Ok(Backlog::Default), "default" => Ok(Backlog::Default),
string => match string.parse::<usize>() { string => match string.parse::<usize>() {
@ -57,7 +57,7 @@ impl<'de> de::Deserialize<'de> for Backlog {
{ {
match Backlog::parse(value) { match Backlog::parse(value) {
Ok(backlog) => Ok(backlog), Ok(backlog) => Ok(backlog),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),

View File

@ -4,7 +4,7 @@ use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// The server keep-alive preference. /// The server keep-alive preference.
/// ///
@ -28,7 +28,7 @@ pub enum KeepAlive {
} }
impl Parse for KeepAlive { impl Parse for KeepAlive {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
pub(crate) static FMT: Lazy<Regex> = pub(crate) static FMT: Lazy<Regex> =
Lazy::new(|| Regex::new(r"^\d+ seconds$").expect("Failed to compile regex: FMT")); Lazy::new(|| Regex::new(r"^\d+ seconds$").expect("Failed to compile regex: FMT"));
@ -82,7 +82,7 @@ impl<'de> de::Deserialize<'de> for KeepAlive {
{ {
match KeepAlive::parse(value) { match KeepAlive::parse(value) {
Ok(keep_alive) => Ok(keep_alive), Ok(keep_alive) => Ok(keep_alive),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),

View File

@ -2,7 +2,7 @@ use std::fmt;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// The maximum per-worker concurrent TLS connection limit. /// The maximum per-worker concurrent TLS connection limit.
/// ///
@ -19,7 +19,7 @@ pub enum MaxConnectionRate {
} }
impl Parse for MaxConnectionRate { impl Parse for MaxConnectionRate {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
match string { match string {
"default" => Ok(MaxConnectionRate::Default), "default" => Ok(MaxConnectionRate::Default),
string => match string.parse::<usize>() { string => match string.parse::<usize>() {
@ -54,7 +54,7 @@ impl<'de> de::Deserialize<'de> for MaxConnectionRate {
{ {
match MaxConnectionRate::parse(value) { match MaxConnectionRate::parse(value) {
Ok(max_connection_rate) => Ok(max_connection_rate), Ok(max_connection_rate) => Ok(max_connection_rate),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),

View File

@ -2,7 +2,7 @@ use std::fmt;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// The maximum per-worker number of concurrent connections. /// The maximum per-worker number of concurrent connections.
/// ///
@ -19,7 +19,7 @@ pub enum MaxConnections {
} }
impl Parse for MaxConnections { impl Parse for MaxConnections {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
match string { match string {
"default" => Ok(MaxConnections::Default), "default" => Ok(MaxConnections::Default),
string => match string.parse::<usize>() { string => match string.parse::<usize>() {
@ -54,7 +54,7 @@ impl<'de> de::Deserialize<'de> for MaxConnections {
{ {
match MaxConnections::parse(value) { match MaxConnections::parse(value) {
Ok(max_connections) => Ok(max_connections), Ok(max_connections) => Ok(max_connections),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),

View File

@ -1,6 +1,6 @@
use serde::Deserialize; use serde::Deserialize;
use crate::{AtResult, Parse}; use crate::{AsResult, Parse};
/// Marker of intended deployment environment. /// Marker of intended deployment environment.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)] #[derive(Debug, Clone, PartialEq, Eq, Hash, Deserialize)]
@ -14,7 +14,7 @@ pub enum Mode {
} }
impl Parse for Mode { impl Parse for Mode {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
match string { match string {
"development" => Ok(Self::Development), "development" => Ok(Self::Development),
"production" => Ok(Self::Production), "production" => Ok(Self::Production),

View File

@ -2,7 +2,7 @@ use std::fmt;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// The number of workers that the server should start. /// The number of workers that the server should start.
/// ///
@ -18,7 +18,7 @@ pub enum NumWorkers {
} }
impl Parse for NumWorkers { impl Parse for NumWorkers {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
match string { match string {
"default" => Ok(NumWorkers::Default), "default" => Ok(NumWorkers::Default),
string => match string.parse::<usize>() { string => match string.parse::<usize>() {
@ -53,7 +53,7 @@ impl<'de> de::Deserialize<'de> for NumWorkers {
{ {
match NumWorkers::parse(value) { match NumWorkers::parse(value) {
Ok(num_workers) => Ok(num_workers), Ok(num_workers) => Ok(num_workers),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),

View File

@ -4,7 +4,7 @@ use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::de; use serde::de;
use crate::{AtError, AtResult, Parse}; use crate::{AsResult, Error, Parse};
/// A timeout duration in milliseconds or seconds. /// A timeout duration in milliseconds or seconds.
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -20,7 +20,7 @@ pub enum Timeout {
} }
impl Parse for Timeout { impl Parse for Timeout {
fn parse(string: &str) -> AtResult<Self> { fn parse(string: &str) -> AsResult<Self> {
pub static FMT: Lazy<Regex> = Lazy::new(|| { pub static FMT: Lazy<Regex> = Lazy::new(|| {
Regex::new(r"^\d+ (milliseconds|seconds)$").expect("Failed to compile regex: FMT") Regex::new(r"^\d+ (milliseconds|seconds)$").expect("Failed to compile regex: FMT")
}); });
@ -85,7 +85,7 @@ impl<'de> de::Deserialize<'de> for Timeout {
{ {
match Timeout::parse(value) { match Timeout::parse(value) {
Ok(num_workers) => Ok(num_workers), Ok(num_workers) => Ok(num_workers),
Err(AtError::InvalidValue { expected, got, .. }) => Err( Err(Error::InvalidValue { expected, got, .. }) => Err(
de::Error::invalid_value(de::Unexpected::Str(&got), &expected), de::Error::invalid_value(de::Unexpected::Str(&got), &expected),
), ),
Err(_) => unreachable!(), Err(_) => unreachable!(),