nutype icon indicating copy to clipboard operation
nutype copied to clipboard

allow implementing `core::error::Error` when available

Open vic1707 opened this issue 1 year ago β€’ 6 comments

rust 1.81.0 made std::error::Error available in core. Users with that version or higher should be getting the Error impl no matter if std feature is enabled. fixes #179 without introducing a breaking change

vic1707 avatar Sep 13 '24 09:09 vic1707

I think its good

lib.rs

use nutype::nutype;

#[nutype(validate(finite))]
struct A(f32);

Cargo.toml

[dependencies]
nutype = { path = "../nutype/nutype" }

Outputs of cargo expand

1.81.0

`nutype = { path = "../nutype/nutype" }`

=> impl ::core::error::Error for AError { /* ... */ }

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl ::core::error::Error for AError {
        fn source(&self) -> Option<&(dyn ::core::error::Error + 'static)> {
            None
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;
`nutype = { path = "../nutype/nutype", default-features = false }`

=> impl ::core::error::Error for AError { /* ... */ }

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl ::core::error::Error for AError {
        fn source(&self) -> Option<&(dyn ::core::error::Error + 'static)> {
            None
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;

1.80.0

`nutype = { path = "../nutype/nutype" }`

=> impl ::std::error::Error for AError { /* ... */ }

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl ::std::error::Error for AError {
        fn source(&self) -> Option<&(dyn ::std::error::Error + 'static)> {
            None
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;
`nutype = { path = "../nutype/nutype", default-features = false }`

=> No implementation of Error

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;

1.83.0-nightly

`nutype = { path = "../nutype/nutype" }`

=> impl ::std::error::Error for AError { /* ... */ }

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl ::core::error::Error for AError {
        fn source(&self) -> Option<&(dyn ::core::error::Error + 'static)> {
            None
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;
`nutype = { path = "../nutype/nutype", default-features = false }`

=> impl ::core::error::Error for AError { /* ... */ }

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2021::*;
#[macro_use]
extern crate std;
use nutype::nutype;
#[doc(hidden)]
mod __nutype_A__ {
    use super::*;
    pub struct A(f32);
    #[allow(clippy::enum_variant_names)]
    pub enum AError {
        FiniteViolated,
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::fmt::Debug for AError {
        #[inline]
        fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
            ::core::fmt::Formatter::write_str(f, "FiniteViolated")
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::clone::Clone for AError {
        #[inline]
        fn clone(&self) -> AError {
            AError::FiniteViolated
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::marker::StructuralPartialEq for AError {}
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::PartialEq for AError {
        #[inline]
        fn eq(&self, other: &AError) -> bool {
            true
        }
    }
    #[automatically_derived]
    #[allow(clippy::enum_variant_names)]
    impl ::core::cmp::Eq for AError {
        #[inline]
        #[doc(hidden)]
        #[coverage(off)]
        fn assert_receiver_is_total_eq(&self) -> () {}
    }
    impl ::core::fmt::Display for AError {
        fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
            match self {
                AError::FiniteViolated => {
                    f.write_fmt(format_args!("{0} is not finite.", "A"))
                }
            }
        }
    }
    impl ::core::error::Error for AError {
        fn source(&self) -> Option<&(dyn ::core::error::Error + 'static)> {
            None
        }
    }
    impl A {
        pub fn try_new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            let sanitized_value: f32 = Self::__sanitize__(raw_value);
            Self::__validate__(&sanitized_value)?;
            Ok(A(sanitized_value))
        }
        fn __sanitize__(mut value: f32) -> f32 {
            value
        }
        fn __validate__(val: &f32) -> core::result::Result<(), AError> {
            let val = *val;
            if !val.is_finite() {
                return Err(AError::FiniteViolated);
            }
            Ok(())
        }
        #[deprecated(since = "0.4.3", note = "\nUse `try_new` instead.")]
        pub fn new(raw_value: f32) -> ::core::result::Result<Self, AError> {
            Self::try_new(raw_value)
        }
    }
    impl A {
        #[inline]
        pub fn into_inner(self) -> f32 {
            self.0
        }
    }
}
use __nutype_A__::A;
use __nutype_A__::AError;

vic1707 avatar Sep 13 '24 11:09 vic1707

@vic1707 Hi thanks for your PRs. Just to keep you update: sorry for the delay. I had seen them and wanted to review over the weekend by did not manage to. I'll try to process them on the next weekend.

greyblake avatar Sep 17 '24 21:09 greyblake

No problem take your time πŸ‘ Thanks for telling me

vic1707 avatar Sep 17 '24 21:09 vic1707

Added the cargo expand on nightly just to be sure I didn't ruin everything.

vic1707 avatar Sep 18 '24 14:09 vic1707

Hi @greyblake may I ask for an update ?

vic1707 avatar Sep 29 '24 15:09 vic1707

Hi, sorry I am on vacation, will be back in 10 days.

On Sun, Sep 29, 2024, 18:21 Victor LEFEBVRE @.***> wrote:

Hi @greyblake https://github.com/greyblake may I ask for an update ?

β€” Reply to this email directly, view it on GitHub https://github.com/greyblake/nutype/pull/184#issuecomment-2381396546, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAA3W2E7SJ4AGSQFV5CHHQTZZALGPAVCNFSM6AAAAABOE6I4NSVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGOBRGM4TMNJUGY . You are receiving this because you were mentioned.Message ID: @.***>

greyblake avatar Sep 29 '24 19:09 greyblake

Hi @greyblake may I ask for an update ?

vic1707 avatar Oct 29 '24 11:10 vic1707

@vic1707 Sorry, I'll try to merge this on the weekend.

greyblake avatar Oct 31 '24 08:10 greyblake

@vic1707 Thank you for your contribution and again sorry for the delay. I've dropped 2 tiny comments. Let me know if you'd like to address them, if no, I guess I can do it.

greyblake avatar Nov 08 '24 22:11 greyblake

@greyblake, just pushed a dryer version, what do you think ?

I thought of doing

let error = cfg_if! {
    if #[cfg(ERROR_IN_CORE)] {
        quote! { ::core::error::Error }
    } else {
        quote! { ::std::error::Error }
    }
};

instead of the proposed version but it's not yet supported by rust itself, see: https://github.com/rust-lang/rust/issues/15701.

Also, do you think you could publish a new version after this merge ?

vic1707 avatar Nov 08 '24 23:11 vic1707

@vic1707 Sorry by bad, in my thinking I assumed that we could just use the core:: variant. With a fresh head, I see that it's obviously would be contra-productive and could not work with the older rust versions. Thank you very much for the very hard try to DRY it.

greyblake avatar Nov 09 '24 10:11 greyblake

No problem, it helped me get a dryer version out, win-win πŸ‘. How about releasing 0.5.1 @greyblake ? Since 0.5.0 we got a few fixes and QOL improvements πŸ™ƒ

vic1707 avatar Nov 09 '24 11:11 vic1707