abi_stable 0.9.0

For doing Rust-to-Rust ffi,writing libraries loaded at program startup.
Documentation
use super::*;


/// An individual error from checking the layout of some type.
#[derive(Debug, PartialEq,Clone)]
pub enum AbiInstability {
    ReentrantLayoutCheckingCall,
    CyclicTypeChecking{
        interface:&'static TypeLayout,
        implementation:&'static TypeLayout,
    },
    NonZeroness(ExpectedFound<bool>),
    Name(ExpectedFound<FmtFullType>),
    Package(ExpectedFound<RStr<'static>>),
    PackageVersionParseError(ParseVersionError),
    PackageVersion(ExpectedFound<VersionStrings>),
    MismatchedPrefixSize(ExpectedFound<u8>),
    Size(ExpectedFound<usize>),
    Alignment(ExpectedFound<usize>),
    GenericParamCount(ExpectedFound<FmtFullType>),
    TLDataDiscriminant(ExpectedFound<TLDataDiscriminant>),
    MismatchedPrimitive(ExpectedFound<TLPrimitive>),
    FieldCountMismatch(ExpectedFound<usize>),
    FieldLifetimeMismatch(ExpectedFound<TLField>),
    FnLifetimeMismatch(ExpectedFound<TLFunction>),
    UnexpectedField(ExpectedFound<TLField>),
    TooManyVariants(ExpectedFound<usize>),
    MismatchedPrefixConditionality(ExpectedFound<FieldConditionality>),
    MismatchedExhaustiveness(ExpectedFound<IsExhaustive>),
    MismatchedConstParam(ExpectedFound<ConstGeneric>),
    UnexpectedVariant(ExpectedFound<RStr<'static>>),
    ReprAttr(ExpectedFound<ReprAttr>),
    EnumDiscriminant(ExpectedFound<TLDiscriminant>),
    IncompatibleWithNonExhaustive(IncompatibleWithNonExhaustive),
    NoneExtraChecks,
    ExtraCheckError(CmpIgnored<ExtraCheckError>),
    TagError{
        err:TagErrors,
    },
}

#[derive(Debug,Clone)]
pub struct ExtraCheckError{
    pub err:RArc<RBoxError>,
    pub expected_err:ExpectedFound<RArc<RBoxError>>,
}


use self::AbiInstability as AI;

#[allow(dead_code)]
impl AbiInstabilityErrors {
    #[cfg(feature = "testing")]
    pub fn flatten_errors(&self) -> RVec<AbiInstability> {
        self.flattened_errors()
            .collect::<RVec<AbiInstability>>()
    }

    #[cfg(feature = "testing")]
    pub fn flattened_errors<'a>(&'a self) -> impl Iterator<Item=AbiInstability>+'a {
        self.errors
            .iter()
            .flat_map(|x| &x.errs )
            .cloned()
    }
}

impl std::error::Error for AbiInstabilityErrors{}

impl fmt::Debug for AbiInstabilityErrors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self,f)
    }
}
impl fmt::Display for AbiInstabilityErrors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        writeln!(
            f,
            "Compared <this>:\n{}\nTo <other>:\n{}\n",
            self.interface.to_string().left_padder(4),
            self.implementation.to_string().left_padder(4),
        )?;
        for err in &self.errors {
            fmt::Display::fmt(err, f)?;
        }
        Ok(())
    }
}

impl fmt::Display for AbiInstabilityError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut extra_err=None::<String>;

        write!(f, "{} error(s)", self.errs.len())?;
        if self.stack_trace.is_empty() {
            writeln!(f,".")?;
        }else{
            writeln!(f,"inside:\n    <other>\n")?;
        }
        for field in &self.stack_trace {
            writeln!(f, "{}\n", field.found.to_string().left_padder(4))?;
        }
        if let Some(ExpectedFound{expected,found}) = self.stack_trace.last() {
            writeln!(
                f, 
                "Layout of expected type:\n{}\n\n\
                 Layout of found type:\n{}\n", 
                expected.formatted_layout().left_padder(4),
                found.formatted_layout().left_padder(4),
            )?;
        }
        writeln!(f)?;

        for err in &self.errs {
            let pair = match err {
                AI::ReentrantLayoutCheckingCall => ("reentrant layout checking call", None),
                AI::CyclicTypeChecking{interface,..} => {
                    extra_err=Some(format!("The type:\n{}",interface));

                    (
                        "Attempted to check the layout of a type while checking the layout \
                         of one of it's const parameters/extra_checks\
                         (not necessarily a direct one).",
                        None,
                    )
                }
                AI::NonZeroness(v) => ("mismatched non-zeroness", v.display_str()),
                AI::Name(v) => ("mismatched type", v.display_str()),
                AI::Package(v) => ("mismatched package", v.display_str()),
                AI::PackageVersionParseError(v) => {
                    let expected = "a valid version string".to_string();
                    let found = format!("{:#?}", v);

                    (
                        "could not parse version string",
                        Some(ExpectedFound { expected, found }),
                    )
                }
                AI::PackageVersion(v) => ("incompatible package versions", v.display_str()),
                AI::MismatchedPrefixSize(v) => 
                    (
                        "prefix-types have a different prefix", 
                        v.display_str()
                    ),
                AI::Size(v) => ("incompatible type size", v.display_str()),
                AI::Alignment(v) => ("incompatible type alignment", v.display_str()),
                AI::GenericParamCount(v) => (
                    "incompatible amount of generic parameters",
                    v.display_str(),
                ),

                AI::TLDataDiscriminant(v) => ("incompatible data ", v.debug_str()),
                AI::MismatchedPrimitive(v) => ("incompatible primitive", v.debug_str()),
                AI::FieldCountMismatch(v) => ("too many fields", v.display_str()),
                AI::FnLifetimeMismatch(v) => {
                    ("function pointers reference different lifetimes", v.display_str())
                }
                AI::FieldLifetimeMismatch(v) => {
                    ("field references different lifetimes", v.display_str())
                }
                AI::UnexpectedField(v) => ("unexpected field", v.display_str()),
                AI::TooManyVariants(v) => ("too many variants", v.display_str()),
                AI::MismatchedPrefixConditionality(v)=>(
                    "prefix fields differ in whether they are conditional",
                    v.debug_str()
                ),
                AI::MismatchedExhaustiveness(v)=>(
                    "enums differ in whether they are exhaustive",
                    v.debug_str()
                ),
                AI::MismatchedConstParam(v)=>(
                    "The cconst parameters are different",
                    v.debug_str()
                ),
                AI::UnexpectedVariant(v) => ("unexpected variant", v.debug_str()),
                AI::ReprAttr(v)=>("incompatible repr attributes",v.debug_str()),
                AI::EnumDiscriminant(v)=>("different discriminants",v.debug_str()),
                AI::IncompatibleWithNonExhaustive(e)=>{
                    extra_err=Some(e.to_string());

                    ("",None)
                }
                AI::NoneExtraChecks=>{
                    let msg="\
                        Interface contains a value in `extra_checks` \
                        while the implementation does not.\
                    ";
                    (msg, None)
                }
                AI::ExtraCheckError(ec_error) => {
                    let ExtraCheckError{err,expected_err}=&**ec_error;
                    extra_err=Some((**err).to_string());

                    ("", expected_err.display_str())
                },
                AI::TagError{err} => {
                    extra_err=Some(err.to_string());

                    ("", None)
                },
            };

            let (error_msg, expected_err):(&'static str, Option<ExpectedFound<String>>)=pair;

            if let Some(expected_err)=expected_err{
                writeln!(
                    f,
                    "\nError:{}\nExpected:\n{}\nFound:\n{}",
                    error_msg,
                    expected_err.expected.left_padder(4),
                    expected_err.found   .left_padder(4),
                )?;
            }
            if let Some(extra_err)=&extra_err {
                writeln!(f,"\nExtra:\n{}\n",extra_err.left_padder(4))?;
            }
        }
        Ok(())
    }
}


/// All the errors from checking the layout of every nested type in TypeLayout.
#[derive(Clone, PartialEq)]
#[repr(C)]
pub struct AbiInstabilityErrors {
    pub interface: &'static TypeLayout,
    pub implementation: &'static TypeLayout,
    pub errors: RVec<AbiInstabilityError>,
    pub(super) _priv:(),
}

/// All the shallow errors from checking an individual type.
///
/// Error that happen lower or higher on the stack are stored in separate
///  `AbiInstabilityError`s.
#[derive(Debug,Clone, PartialEq)]
#[repr(C)]
pub struct AbiInstabilityError {
    pub stack_trace: RVec<ExpectedFound<TLFieldOrFunction>>,
    pub errs: RVec<AbiInstability>,
    pub index: usize,
    pub(super) _priv:(),
}