Import upstream v0.16.22, stripped

Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
2026-09-18 10:21:56 -07:00
commit 7dae9b29fd
1650 changed files with 485521 additions and 0 deletions
+598
View File
@@ -0,0 +1,598 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use std::{borrow::Cow, fmt::Debug, str::FromStr, time::Duration};
use compact_str::{CompactString, ToCompactString, format_compact};
use mail_auth::common::verify::VerifySignature;
use crate::*;
impl AsRef<EventType> for Error {
fn as_ref(&self) -> &EventType {
&self.0.inner
}
}
impl From<&'static str> for Value {
fn from(value: &'static str) -> Self {
Self::String(CompactString::const_new(value))
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Self::String(CompactString::from_string_buffer(value))
}
}
impl From<CompactString> for Value {
fn from(value: CompactString) -> Self {
Self::String(value)
}
}
impl From<Box<str>> for Value {
fn from(value: Box<str>) -> Self {
Self::String(CompactString::from(value))
}
}
impl From<u64> for Value {
fn from(value: u64) -> Self {
Self::UInt(value)
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Self::Int(value)
}
}
impl From<f64> for Value {
fn from(value: f64) -> Self {
Self::Float(value)
}
}
impl From<f32> for Value {
fn from(value: f32) -> Self {
Self::Float(value.into())
}
}
impl From<u16> for Value {
fn from(value: u16) -> Self {
Self::UInt(value.into())
}
}
impl From<i32> for Value {
fn from(value: i32) -> Self {
Self::Int(value.into())
}
}
impl From<u32> for Value {
fn from(value: u32) -> Self {
Self::UInt(value.into())
}
}
impl From<usize> for Value {
fn from(value: usize) -> Self {
Self::UInt(value as u64)
}
}
impl From<bool> for Value {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
impl From<IpAddr> for Value {
fn from(value: IpAddr) -> Self {
match value {
IpAddr::V4(ip) => Value::Ipv4(ip),
IpAddr::V6(ip) => Value::Ipv6(ip),
}
}
}
impl<T: Into<Value>> From<Option<T>> for Value {
fn from(value: Option<T>) -> Self {
match value {
Some(value) => value.into(),
None => Self::None,
}
}
}
impl From<Duration> for Value {
fn from(value: Duration) -> Self {
Self::Duration(value.as_millis() as u64)
}
}
impl From<Error> for Value {
fn from(value: Error) -> Self {
Self::Event(value)
}
}
impl From<EventType> for Error {
fn from(value: EventType) -> Self {
Error::new(value)
}
}
impl From<StoreEvent> for Error {
fn from(value: StoreEvent) -> Self {
Error::new(EventType::Store(value))
}
}
impl From<AuthEvent> for Error {
fn from(value: AuthEvent) -> Self {
Error::new(EventType::Auth(value))
}
}
impl From<Vec<u8>> for Value {
fn from(value: Vec<u8>) -> Self {
Self::Bytes(value)
}
}
impl From<&[u8]> for Value {
fn from(value: &[u8]) -> Self {
Self::Bytes(value.to_vec())
}
}
impl From<Cow<'static, str>> for Value {
fn from(value: Cow<'static, str>) -> Self {
match value {
Cow::Borrowed(value) => Self::String(CompactString::const_new(value)),
Cow::Owned(value) => Self::String(value.into()),
}
}
}
impl<T> From<&crate::Result<T>> for Value
where
T: Debug,
{
fn from(value: &crate::Result<T>) -> Self {
match value {
Ok(value) => format_compact!("{:?}", value).into(),
Err(err) => Value::Event(err.clone()),
}
}
}
impl<T> From<Vec<T>> for Value
where
T: Into<Value>,
{
fn from(value: Vec<T>) -> Self {
Self::Array(value.into_iter().map(Into::into).collect())
}
}
impl<T> From<&[T]> for Value
where
T: Into<Value> + Clone,
{
fn from(value: &[T]) -> Self {
Self::Array(value.iter().map(|v| v.clone().into()).collect())
}
}
impl EventType {
pub fn from_io_error(self, err: std::io::Error) -> Error {
self.reason(err).details("I/O error")
}
pub fn from_json_error(self, err: serde_json::Error) -> Error {
self.reason(err).details("JSON deserialization failed")
}
pub fn from_base64_error(self, err: base64::DecodeError) -> Error {
self.reason(err).details("Base64 decoding failed")
}
pub fn from_http_error(self, err: reqwest::Error) -> Error {
self.into_err()
.ctx_opt(
Key::Url,
err.url().map(|url| url.as_ref().to_compact_string()),
)
.ctx_opt(Key::Code, err.status().map(|status| status.as_u16()))
.reason(err)
}
pub fn from_http_str_error(self, err: reqwest::header::ToStrError) -> Error {
self.reason(err)
.details("Failed to convert header to string")
}
}
impl From<mail_auth::Error> for Error {
fn from(err: mail_auth::Error) -> Self {
match err {
mail_auth::Error::ParseError => {
EventType::MailAuth(MailAuthEvent::ParseError).into_err()
}
mail_auth::Error::MissingParameters => {
EventType::MailAuth(MailAuthEvent::MissingParameters).into_err()
}
mail_auth::Error::NoHeadersFound => {
EventType::MailAuth(MailAuthEvent::NoHeadersFound).into_err()
}
mail_auth::Error::Io(details) => EventType::MailAuth(MailAuthEvent::Io)
.into_err()
.details(CompactString::from(details)),
mail_auth::Error::Base64 => EventType::MailAuth(MailAuthEvent::Base64).into_err(),
mail_auth::Error::NotAligned => {
EventType::MailAuth(MailAuthEvent::PolicyNotAligned).into_err()
}
mail_auth::Error::Crypto(err) => match err {
mail_auth::common::crypto::CryptoError::Library(details) => {
EventType::MailAuth(MailAuthEvent::Crypto)
.into_err()
.details(CompactString::from(details))
}
mail_auth::common::crypto::CryptoError::FailedVerification => {
EventType::Dkim(DkimEvent::FailedVerification).into_err()
}
mail_auth::common::crypto::CryptoError::IncompatibleAlgorithms => {
EventType::Dkim(DkimEvent::IncompatibleAlgorithms).into_err()
}
},
mail_auth::Error::Dns(err) => match err {
mail_auth::DnsError::Resolver(details) => {
EventType::MailAuth(MailAuthEvent::DnsError)
.into_err()
.details(CompactString::from(details))
}
mail_auth::DnsError::RecordNotFound(code) => {
EventType::MailAuth(MailAuthEvent::DnsRecordNotFound)
.into_err()
.code(code.to_str())
}
mail_auth::DnsError::InvalidRecordType => {
EventType::MailAuth(MailAuthEvent::DnsInvalidRecordType).into_err()
}
},
mail_auth::Error::Dkim(err) => match err {
mail_auth::dkim::DkimError::UnsupportedVersion => {
EventType::Dkim(DkimEvent::UnsupportedVersion).into_err()
}
mail_auth::dkim::DkimError::UnsupportedAlgorithm => {
EventType::Dkim(DkimEvent::UnsupportedAlgorithm).into_err()
}
mail_auth::dkim::DkimError::UnsupportedCanonicalization => {
EventType::Dkim(DkimEvent::UnsupportedCanonicalization).into_err()
}
mail_auth::dkim::DkimError::UnsupportedKeyType => {
EventType::Dkim(DkimEvent::UnsupportedKeyType).into_err()
}
mail_auth::dkim::DkimError::FailedBodyHashMatch => {
EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err()
}
mail_auth::dkim::DkimError::FailedAuidMatch => {
EventType::Dkim(DkimEvent::FailedAuidMatch).into_err()
}
mail_auth::dkim::DkimError::RevokedPublicKey => {
EventType::Dkim(DkimEvent::RevokedPublicKey).into_err()
}
mail_auth::dkim::DkimError::SignatureExpired => {
EventType::Dkim(DkimEvent::SignatureExpired).into_err()
}
mail_auth::dkim::DkimError::SignatureLength => {
EventType::Dkim(DkimEvent::SignatureLength).into_err()
}
},
mail_auth::Error::Arc(err) => match err {
mail_auth::arc::ArcError::ChainTooLong => {
EventType::Arc(ArcEvent::ChainTooLong).into_err()
}
mail_auth::arc::ArcError::InvalidInstance(instance) => {
EventType::Arc(ArcEvent::InvalidInstance).ctx(Key::Id, instance)
}
mail_auth::arc::ArcError::InvalidCV => {
EventType::Arc(ArcEvent::InvalidCv).into_err()
}
mail_auth::arc::ArcError::HasHeaderTag => {
EventType::Arc(ArcEvent::HasHeaderTag).into_err()
}
mail_auth::arc::ArcError::BrokenChain => {
EventType::Arc(ArcEvent::BrokenChain).into_err()
}
mail_auth::arc::ArcError::FailedBodyHashMatch => {
EventType::Dkim(DkimEvent::FailedBodyHashMatch).into_err()
}
mail_auth::arc::ArcError::SignatureExpired => {
EventType::Dkim(DkimEvent::SignatureExpired).into_err()
}
mail_auth::arc::ArcError::SignatureLength => {
EventType::Dkim(DkimEvent::SignatureLength).into_err()
}
},
mail_auth::Error::Dkim2(err) => match err {
mail_auth::dkim2::Dkim2Error::InstanceMissing(m) => {
EventType::Dkim(DkimEvent::InstanceMissing).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::InstanceSyntax(m) => {
EventType::Dkim(DkimEvent::InstanceSyntax).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::InstanceTagMissing { m, tag } => {
EventType::Dkim(DkimEvent::InstanceTagMissing)
.ctx(Key::Id, m)
.details(tag)
}
mail_auth::dkim2::Dkim2Error::InstanceNotSigned(m) => {
EventType::Dkim(DkimEvent::InstanceNotSigned).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::InstanceAboveSignature(m) => {
EventType::Dkim(DkimEvent::InstanceAboveSignature).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::SignatureMissing(i) => {
EventType::Dkim(DkimEvent::SignatureMissing).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::SignatureSyntax(i) => {
EventType::Dkim(DkimEvent::SignatureSyntax).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::SignatureTagMissing { i, tag } => {
EventType::Dkim(DkimEvent::SignatureTagMissing)
.ctx(Key::Id, i)
.details(tag)
}
mail_auth::dkim2::Dkim2Error::SignatureTagUnexpected { i, tag } => {
EventType::Dkim(DkimEvent::SignatureTagUnexpected)
.ctx(Key::Id, i)
.details(tag)
}
mail_auth::dkim2::Dkim2Error::SequenceGap => {
EventType::Dkim(DkimEvent::SequenceGap).into_err()
}
mail_auth::dkim2::Dkim2Error::SequenceOverflow => {
EventType::Dkim(DkimEvent::SequenceOverflow).into_err()
}
mail_auth::dkim2::Dkim2Error::ChainTooLong => {
EventType::Dkim(DkimEvent::ChainTooLong).into_err()
}
mail_auth::dkim2::Dkim2Error::SignatureExpired(i) => {
EventType::Dkim(DkimEvent::SignatureExpired).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::MailFromMismatch(i) => {
EventType::Dkim(DkimEvent::MailFromMismatch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::RcptToMismatch(i) => {
EventType::Dkim(DkimEvent::RcptToMismatch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::MailFromDomainMismatch(i) => {
EventType::Dkim(DkimEvent::MailFromDomainMismatch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::NextDomainMismatch(i) => {
EventType::Dkim(DkimEvent::NextDomainMismatch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::CustodyBreak(i) => {
EventType::Dkim(DkimEvent::CustodyBreak).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeyFetch(i) => {
EventType::Dkim(DkimEvent::PublicKeyFetch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeyMissing(i) => {
EventType::Dkim(DkimEvent::PublicKeyMissing).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeyMultiple(i) => {
EventType::Dkim(DkimEvent::PublicKeyMultiple).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeySyntax(i) => {
EventType::Dkim(DkimEvent::PublicKeySyntax).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeyAlgorithmMismatch(i) => {
EventType::Dkim(DkimEvent::PublicKeyAlgorithmMismatch).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::PublicKeyRevoked(i) => {
EventType::Dkim(DkimEvent::RevokedPublicKey).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::IncorrectSignature(i) => {
EventType::Dkim(DkimEvent::FailedVerification).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::NoValidAlgorithm(i) => {
EventType::Dkim(DkimEvent::NoValidAlgorithm).ctx(Key::Id, i)
}
mail_auth::dkim2::Dkim2Error::HeaderHashMismatch(m) => {
EventType::Dkim(DkimEvent::HeaderHashMismatch).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::BodyHashMismatch(m) => {
EventType::Dkim(DkimEvent::FailedBodyHashMatch).ctx(Key::Id, m)
}
mail_auth::dkim2::Dkim2Error::Modified => {
EventType::Dkim(DkimEvent::Modified).into_err()
}
mail_auth::dkim2::Dkim2Error::Exploded => {
EventType::Dkim(DkimEvent::Exploded).into_err()
}
},
}
}
}
impl From<&mail_auth::DkimResult> for Error {
fn from(value: &mail_auth::DkimResult) -> Self {
match value.clone() {
mail_auth::DkimResult::Pass => Error::new(EventType::Dkim(DkimEvent::Pass)),
mail_auth::DkimResult::Neutral(err) => {
Error::new(EventType::Dkim(DkimEvent::Neutral)).caused_by(Error::from(err))
}
mail_auth::DkimResult::Fail(err) => {
Error::new(EventType::Dkim(DkimEvent::Fail)).caused_by(Error::from(err))
}
mail_auth::DkimResult::PermError(err) => {
Error::new(EventType::Dkim(DkimEvent::PermError)).caused_by(Error::from(err))
}
mail_auth::DkimResult::TempError(err) => {
Error::new(EventType::Dkim(DkimEvent::TempError)).caused_by(Error::from(err))
}
mail_auth::DkimResult::None => Error::new(EventType::Dkim(DkimEvent::None)),
}
}
}
impl From<&mail_auth::Dkim2Result> for Error {
fn from(value: &mail_auth::Dkim2Result) -> Self {
match value.clone() {
mail_auth::Dkim2Result::Pass => Error::new(EventType::Dkim(DkimEvent::Pass)),
mail_auth::Dkim2Result::Fail(err) => {
Error::new(EventType::Dkim(DkimEvent::Fail)).caused_by(Error::from(err))
}
mail_auth::Dkim2Result::PermError(err) => {
Error::new(EventType::Dkim(DkimEvent::PermError)).caused_by(Error::from(err))
}
mail_auth::Dkim2Result::TempError(err) => {
Error::new(EventType::Dkim(DkimEvent::TempError)).caused_by(Error::from(err))
}
mail_auth::Dkim2Result::None => Error::new(EventType::Dkim(DkimEvent::None)),
}
}
}
impl From<&mail_auth::dkim2::Dkim2Output<'_>> for Error {
fn from(value: &mail_auth::dkim2::Dkim2Output<'_>) -> Self {
Error::from(value.result()).ctx_opt(
Key::Domain,
value
.chain()
.first()
.map(|link| link.signature.d.to_compact_string()),
)
}
}
impl From<&mail_auth::DmarcResult> for Error {
fn from(value: &mail_auth::DmarcResult) -> Self {
match value.clone() {
mail_auth::DmarcResult::Pass => Error::new(EventType::Dmarc(DmarcEvent::Pass)),
mail_auth::DmarcResult::Fail(err) => {
Error::new(EventType::Dmarc(DmarcEvent::Fail)).caused_by(Error::from(err))
}
mail_auth::DmarcResult::PermError(err) => {
Error::new(EventType::Dmarc(DmarcEvent::PermError)).caused_by(Error::from(err))
}
mail_auth::DmarcResult::TempError(err) => {
Error::new(EventType::Dmarc(DmarcEvent::TempError)).caused_by(Error::from(err))
}
mail_auth::DmarcResult::None => Error::new(EventType::Dmarc(DmarcEvent::None)),
}
}
}
impl From<&mail_auth::DkimOutput<'_>> for Error {
fn from(value: &mail_auth::DkimOutput<'_>) -> Self {
Error::from(value.result()).ctx_opt(
Key::Domain,
value.signature().map(|s| s.domain().to_compact_string()),
)
}
}
impl From<&mail_auth::IprevOutput> for Error {
fn from(value: &mail_auth::IprevOutput) -> Self {
match value.result().clone() {
mail_auth::IprevResult::Pass => Error::new(EventType::Iprev(IprevEvent::Pass)),
mail_auth::IprevResult::Fail(err) => {
Error::new(EventType::Iprev(IprevEvent::Fail)).caused_by(Error::from(err))
}
mail_auth::IprevResult::PermError(err) => {
Error::new(EventType::Iprev(IprevEvent::PermError)).caused_by(Error::from(err))
}
mail_auth::IprevResult::TempError(err) => {
Error::new(EventType::Iprev(IprevEvent::TempError)).caused_by(Error::from(err))
}
mail_auth::IprevResult::None => Error::new(EventType::Iprev(IprevEvent::None)),
}
.ctx_opt(
Key::Details,
value.ptr.as_ref().map(|s| {
s.iter()
.map(|v| Value::String(v.as_ref().into()))
.collect::<Vec<_>>()
}),
)
}
}
impl From<&mail_auth::SpfOutput> for Error {
fn from(value: &mail_auth::SpfOutput) -> Self {
Error::new(EventType::Spf(match value.result() {
mail_auth::SpfResult::Pass => SpfEvent::Pass,
mail_auth::SpfResult::Fail => SpfEvent::Fail,
mail_auth::SpfResult::SoftFail => SpfEvent::SoftFail,
mail_auth::SpfResult::Neutral => SpfEvent::Neutral,
mail_auth::SpfResult::PermError => SpfEvent::PermError,
mail_auth::SpfResult::TempError => SpfEvent::TempError,
mail_auth::SpfResult::None => SpfEvent::None,
}))
.ctx_opt(
Key::Details,
value.explanation().map(|s| s.to_compact_string()),
)
}
}
impl From<rkyv::rancor::Error> for Error {
fn from(value: rkyv::rancor::Error) -> Self {
Error::new(EventType::Store(StoreEvent::DeserializeError))
.reason(value)
.details("Rkyv de/serialization failed")
}
}
pub trait AssertSuccess
where
Self: Sized,
{
fn assert_success(
self,
cause: EventType,
) -> impl std::future::Future<Output = crate::Result<Self>> + Send;
}
impl AssertSuccess for reqwest::Response {
async fn assert_success(self, cause: EventType) -> crate::Result<Self> {
let status = self.status();
if status.is_success() {
Ok(self)
} else {
Err(cause
.ctx(Key::Code, status.as_u16())
.details("HTTP request failed")
.ctx_opt(Key::Reason, self.text().await.map(CompactString::from).ok()))
}
}
}
impl FromStr for EventType {
type Err = ();
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
EventType::parse(s).ok_or(())
}
}
impl FromStr for Key {
type Err = ();
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
Key::parse(s).ok_or(())
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+81
View File
@@ -0,0 +1,81 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use crate::Level;
use std::{cmp::Ordering, fmt::Display, str::FromStr};
impl PartialOrd for Level {
#[inline(always)]
fn partial_cmp(&self, other: &Level) -> Option<Ordering> {
Some(self.cmp(other))
}
#[inline(always)]
fn lt(&self, other: &Level) -> bool {
(*other as usize) < (*self as usize)
}
#[inline(always)]
fn le(&self, other: &Level) -> bool {
(*other as usize) <= (*self as usize)
}
#[inline(always)]
fn gt(&self, other: &Level) -> bool {
(*other as usize) > (*self as usize)
}
#[inline(always)]
fn ge(&self, other: &Level) -> bool {
(*other as usize) >= (*self as usize)
}
}
impl Ord for Level {
#[inline(always)]
fn cmp(&self, other: &Self) -> Ordering {
(*other as usize).cmp(&(*self as usize))
}
}
impl FromStr for Level {
type Err = String;
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"disable" => Ok(Self::Disable),
"trace" => Ok(Self::Trace),
"debug" => Ok(Self::Debug),
"info" => Ok(Self::Info),
"warn" => Ok(Self::Warn),
"error" => Ok(Self::Error),
_ => Err(s.to_string()),
}
}
}
impl Level {
pub fn as_str(&self) -> &'static str {
match self {
Self::Disable => "DISABLE",
Self::Trace => "TRACE",
Self::Debug => "DEBUG",
Self::Info => "INFO",
Self::Warn => "WARN",
Self::Error => "ERROR",
}
}
pub fn is_contained(&self, other: Self) -> bool {
*self >= other && other != Level::Disable && *self != Level::Disable
}
}
impl Display for Level {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.as_str().fmt(f)
}
}
+683
View File
@@ -0,0 +1,683 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
pub mod conv;
pub mod level;
pub mod enums;
#[allow(clippy::match_like_matches_macro)]
pub mod enums_impl;
use compact_str::ToCompactString;
use std::fmt::Display;
use crate::*;
impl<T> Event<T> {
pub fn with_capacity(inner: T, capacity: usize) -> Self {
Self {
inner,
keys: Vec::with_capacity(capacity),
}
}
pub fn with_keys(inner: T, keys: Vec<(Key, Value)>) -> Self {
Self { inner, keys }
}
pub fn new(inner: T) -> Self {
Self {
inner,
keys: Vec::with_capacity(5),
}
}
pub fn value(&self, key: Key) -> Option<&Value> {
self.keys
.iter()
.find_map(|(k, v)| if *k == key { Some(v) } else { None })
}
pub fn value_as_str(&self, key: Key) -> Option<&str> {
self.value(key).and_then(|v| v.as_str())
}
pub fn value_as_uint(&self, key: Key) -> Option<u64> {
self.value(key).and_then(|v| v.to_uint())
}
pub fn take_value(&mut self, key: Key) -> Option<Value> {
self.keys.iter_mut().find_map(|(k, v)| {
if *k == key {
Some(std::mem::take(v))
} else {
None
}
})
}
pub fn into_boxed(self) -> Box<Self> {
Box::new(self)
}
}
impl Error {
#[inline(always)]
pub fn new(inner: EventType) -> Self {
Error(Box::new(Event::new(inner)))
}
#[inline(always)]
pub fn set_ctx(&mut self, key: Key, value: impl Into<Value>) {
self.0.keys.push((key, value.into()));
}
#[inline(always)]
pub fn ctx(mut self, key: Key, value: impl Into<Value>) -> Self {
self.0.keys.push((key, value.into()));
self
}
#[inline(always)]
pub fn ctx_unique(mut self, key: Key, value: impl Into<Value>) -> Self {
if self.0.keys.iter().all(|(k, _)| *k != key) {
self.0.keys.push((key, value.into()));
}
self
}
#[inline(always)]
pub fn ctx_opt(self, key: Key, value: Option<impl Into<Value>>) -> Self {
match value {
Some(value) => self.ctx(key, value),
None => self,
}
}
#[inline(always)]
pub fn matches(&self, inner: EventType) -> bool {
self.0.inner == inner
}
#[inline(always)]
pub fn event_type(&self) -> EventType {
self.0.inner
}
#[inline(always)]
pub fn span_id(self, session_id: u64) -> Self {
self.ctx(Key::SpanId, session_id)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Self {
self.ctx(Key::CausedBy, error)
}
#[inline(always)]
pub fn details(self, error: impl Into<Value>) -> Self {
self.ctx(Key::Details, error)
}
#[inline(always)]
pub fn code(self, error: impl Into<Value>) -> Self {
self.ctx(Key::Code, error)
}
#[inline(always)]
pub fn id(self, error: impl Into<Value>) -> Self {
self.ctx(Key::Id, error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Self {
self.ctx(Key::Reason, error.to_compact_string())
}
#[inline(always)]
pub fn document_id(self, id: u32) -> Self {
self.ctx(Key::DocumentId, id)
}
#[inline(always)]
pub fn account_id(self, id: u32) -> Self {
self.ctx(Key::AccountId, id)
}
#[inline(always)]
pub fn collection(self, id: impl Into<u8>) -> Self {
self.ctx(Key::Collection, id.into() as u64)
}
#[inline(always)]
pub fn wrap(self, cause: EventType) -> Self {
Error::new(cause).caused_by(self)
}
#[inline(always)]
pub fn keys(&self) -> &[(Key, Value)] {
&self.0.keys
}
#[inline(always)]
pub fn value(&self, key: Key) -> Option<&Value> {
self.0.value(key)
}
#[inline(always)]
pub fn value_as_str(&self, key: Key) -> Option<&str> {
self.0.value_as_str(key)
}
#[inline(always)]
pub fn value_as_uint(&self, key: Key) -> Option<u64> {
self.0.value_as_uint(key)
}
#[inline(always)]
pub fn take_value(&mut self, key: Key) -> Option<Value> {
self.0.take_value(key)
}
#[inline(always)]
pub fn is_assertion_failure(&self) -> bool {
self.0.inner == EventType::Store(StoreEvent::AssertValueFailed)
}
pub fn key(&self, key: Key) -> Option<&Value> {
self.0
.keys
.iter()
.find_map(|(k, v)| if *k == key { Some(v) } else { None })
}
#[inline(always)]
pub fn is_jmap_method_error(&self) -> bool {
!matches!(
self.0.inner,
EventType::Jmap(
JmapEvent::UnknownCapability | JmapEvent::NotJson | JmapEvent::NotRequest
)
)
}
#[inline(always)]
pub fn must_disconnect(&self) -> bool {
matches!(
self.0.inner,
EventType::Network(_)
| EventType::Auth(AuthEvent::TooManyAttempts)
| EventType::Limit(LimitEvent::ConcurrentRequest | LimitEvent::TooManyRequests)
| EventType::Security(_)
)
}
#[inline(always)]
pub fn should_write_err(&self) -> bool {
!matches!(self.0.inner, EventType::Network(_) | EventType::Security(_))
}
pub fn corrupted_key(key: &[u8], value: Option<&[u8]>, caused_by: &'static str) -> Error {
EventType::Store(StoreEvent::DataCorruption)
.ctx(Key::Key, key)
.ctx_opt(Key::Value, value)
.ctx(Key::CausedBy, caused_by)
}
}
impl Event<EventDetails> {
pub fn span_id(&self) -> Option<u64> {
for (key, value) in &self.keys {
match (key, value) {
(Key::SpanId, Value::UInt(value)) => return Some(*value),
(Key::SpanId, Value::Int(value)) => return Some(*value as u64),
_ => {}
}
}
None
}
}
impl EventType {
#[inline(always)]
pub fn is_span_start(&self) -> bool {
matches!(
self,
EventType::Smtp(SmtpEvent::ConnectionStart)
| EventType::Imap(ImapEvent::ConnectionStart)
| EventType::ManageSieve(ManageSieveEvent::ConnectionStart)
| EventType::Pop3(Pop3Event::ConnectionStart)
| EventType::Http(HttpEvent::ConnectionStart)
| EventType::Delivery(DeliveryEvent::AttemptStart)
)
}
#[inline(always)]
pub fn is_span_end(&self) -> bool {
matches!(
self,
EventType::Smtp(SmtpEvent::ConnectionEnd)
| EventType::Imap(ImapEvent::ConnectionEnd)
| EventType::ManageSieve(ManageSieveEvent::ConnectionEnd)
| EventType::Pop3(Pop3Event::ConnectionEnd)
| EventType::Http(HttpEvent::ConnectionEnd)
| EventType::Delivery(DeliveryEvent::AttemptEnd)
)
}
pub fn is_raw_io(&self) -> bool {
matches!(
self,
EventType::Imap(ImapEvent::RawInput | ImapEvent::RawOutput)
| EventType::Smtp(SmtpEvent::RawInput | SmtpEvent::RawOutput)
| EventType::Pop3(Pop3Event::RawInput | Pop3Event::RawOutput)
| EventType::ManageSieve(ManageSieveEvent::RawInput | ManageSieveEvent::RawOutput)
| EventType::Delivery(DeliveryEvent::RawInput | DeliveryEvent::RawOutput)
| EventType::Milter(MilterEvent::Read | MilterEvent::Write)
)
}
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(self)
}
}
impl StoreEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Store(self))
}
}
impl DnsEvent {
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Dns(self))
}
}
impl AcmeEvent {
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Acme(self))
}
}
impl DkimEvent {
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Dkim(self))
}
}
impl SecurityEvent {
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Security(self))
}
}
impl AuthEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Auth(self))
}
}
impl JmapEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Jmap(self))
}
}
impl LimitEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Limit(self))
}
}
impl ResourceEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Resource(self))
}
}
impl SmtpEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Smtp(self))
}
}
impl SieveEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Sieve(self))
}
}
impl SpamEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Spam(self))
}
}
impl ImapEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Imap(self))
}
#[inline(always)]
pub fn caused_by(self, error: impl Into<Value>) -> Error {
self.into_err().caused_by(error)
}
#[inline(always)]
pub fn reason(self, error: impl Display) -> Error {
self.into_err().reason(error)
}
}
impl Pop3Event {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Pop3(self))
}
}
impl ManageSieveEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::ManageSieve(self))
}
}
impl NetworkEvent {
#[inline(always)]
pub fn ctx(self, key: Key, value: impl Into<Value>) -> Error {
self.into_err().ctx(key, value)
}
#[inline(always)]
pub fn into_err(self) -> Error {
Error::new(EventType::Network(self))
}
}
impl Value {
pub fn from_maybe_string(value: &[u8]) -> Self {
if let Ok(value) = std::str::from_utf8(value) {
Self::String(value.into())
} else {
Self::Bytes(value.to_vec())
}
}
pub fn to_uint(&self) -> Option<u64> {
match self {
Self::UInt(value) => Some(*value),
Self::Int(value) => Some(*value as u64),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
Self::String(value) => Some(value.as_str()),
_ => None,
}
}
pub fn into_string(self) -> Option<CompactString> {
match self {
Self::String(value) => Some(value),
_ => None,
}
}
}
impl<T> AddContext<T> for Result<T> {
#[inline(always)]
fn caused_by(self, location: &'static str) -> Result<T> {
match self {
Ok(value) => Ok(value),
Err(mut err) => {
err.set_ctx(Key::CausedBy, location);
Err(err)
}
}
}
#[inline(always)]
fn add_context<F>(self, f: F) -> Result<T>
where
F: FnOnce(Error) -> Error,
{
match self {
Ok(value) => Ok(value),
Err(err) => Err(f(err)),
}
}
}
impl std::error::Error for Error {}
impl Eq for Error {}
impl PartialEq for Error {
fn eq(&self, other: &Self) -> bool {
if self.0.inner == other.0.inner && self.0.keys.len() == other.0.keys.len() {
for kv in self.0.keys.iter() {
if !other.0.keys.iter().any(|okv| kv == okv) {
return false;
}
}
true
} else {
false
}
}
}
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::String(l0), Self::String(r0)) => l0 == r0,
(Self::UInt(l0), Self::UInt(r0)) => l0 == r0,
(Self::Int(l0), Self::Int(r0)) => l0 == r0,
(Self::Float(l0), Self::Float(r0)) => l0 == r0,
(Self::Bytes(l0), Self::Bytes(r0)) => l0 == r0,
(Self::Bool(l0), Self::Bool(r0)) => l0 == r0,
(Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
(Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
(Self::Event(l0), Self::Event(r0)) => l0 == r0,
(Self::Array(l0), Self::Array(r0)) => l0 == r0,
_ => false,
}
}
}
impl Eq for Value {}
impl From<EventType> for usize {
fn from(value: EventType) -> Self {
value.to_id() as usize
}
}
impl AsRef<Event<EventDetails>> for Event<EventDetails> {
fn as_ref(&self) -> &Event<EventDetails> {
self
}
}