/*
 * SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
 *
 * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
 */

// This file is auto-generated. Do not edit directly.

use crate::schema::prelude::*;

impl ObjectImpl for Account {
    const FLAGS: u64 = OBJ_FILTER_TENANT | OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Account;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Account::User(inner) => inner.validate(errors),
            Account::Group(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            Account::User(object) => {
                i.typ(0);
                object.index(i);
            }
            Account::Group(object) => {
                i.typ(1);
                object.index(i);
            }
        }
    }
}

impl Default for Account {
    fn default() -> Self {
        Account::User(Default::default())
    }
}

impl Pickle for Account {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Account::User(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Account::Group(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Account::User),
            1 => Pickle::unpickle(stream).map(Account::Group),
            _ => None,
        }
    }
}

impl IntoValue for Account {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Account::User(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("User".into()));
                obj
            }
            Account::Group(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Group".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Account {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                AccountType::User => *self = Account::User(Default::default()),
                AccountType::Group => *self = Account::Group(Default::default()),
            }
        }
        match self {
            Account::User(inner) => inner.patch(pointer, value),
            Account::Group(inner) => inner.patch(pointer, value),
        }
    }
}

impl Account {
    pub fn object_type(&self) -> AccountType {
        match self {
            Account::User(_) => AccountType::User,
            Account::Group(_) => AccountType::Group,
        }
    }
}

impl ObjectImpl for AccountPassword {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AccountPassword;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.secret {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Secret));
            }
        }
        if let Some(value) = &self.current_secret {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::CurrentSecret));
            }
        }
        let value = &self.otp_auth;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for AccountPassword {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret.pickle(out);
        self.current_secret.pickle(out);
        self.otp_auth.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.secret = Pickle::unpickle(stream)?;
        this.current_secret = Pickle::unpickle(stream)?;
        this.otp_auth = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AccountPassword {
    fn default() -> Self {
        Self {
            secret: Default::default(),
            current_secret: Default::default(),
            otp_auth: Default::default(),
        }
    }
}

impl IntoValue for AccountPassword {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        if self.secret.is_some() {
            map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        }
        if self.current_secret.is_some() {
            map.insert_unchecked(
                Property::CurrentSecret,
                JmapValue::Str(MASKED_PASSWORD.into()),
            );
        }
        map.insert_unchecked(Property::OtpAuth, self.otp_auth.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AccountPassword {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::CurrentSecret) => self.current_secret.patch(pointer, value),
            Some(Property::OtpAuth) => self.otp_auth.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for AccountSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AccountSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.encryption_at_rest;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        self.encryption_at_rest.index(i);
    }
}

impl Pickle for AccountSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.locale.pickle(out);
        self.time_zone.pickle(out);
        self.encryption_at_rest.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.locale = Pickle::unpickle(stream)?;
        this.time_zone = Pickle::unpickle(stream)?;
        this.encryption_at_rest = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AccountSettings {
    fn default() -> Self {
        Self {
            description: Default::default(),
            locale: Locale::EnUS,
            time_zone: Default::default(),
            encryption_at_rest: Default::default(),
        }
    }
}

impl IntoValue for AccountSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Locale, self.locale.into_value());
        map.insert_unchecked(Property::TimeZone, self.time_zone.into_value());
        map.insert_unchecked(
            Property::EncryptionAtRest,
            self.encryption_at_rest.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AccountSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Locale) => self.locale.patch(pointer, value),
            Some(Property::TimeZone) => self.time_zone.patch(pointer, value),
            Some(Property::EncryptionAtRest) => self.encryption_at_rest.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for AcmeProvider {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AcmeProvider;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.contact;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Contact));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Contact, 1));
        }
        let value = &self.directory;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Directory));
        }
        let value = &self.account_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccountKey));
        }
        let value = &self.account_uri;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccountUri));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        for value in self.contact.iter() {
            i.text(Property::Text, value);
        }
        i.text(Property::Text, &self.directory);
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for AcmeProvider {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.challenge_type.pickle(out);
        self.contact.pickle(out);
        self.directory.pickle(out);
        self.account_key.pickle(out);
        self.account_uri.pickle(out);
        self.renew_before.pickle(out);
        self.max_retries.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.challenge_type = Pickle::unpickle(stream)?;
        this.contact = Pickle::unpickle(stream)?;
        this.directory = Pickle::unpickle(stream)?;
        this.account_key = Pickle::unpickle(stream)?;
        this.account_uri = Pickle::unpickle(stream)?;
        this.renew_before = Pickle::unpickle(stream)?;
        this.max_retries = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AcmeProvider {
    fn default() -> Self {
        Self {
            challenge_type: AcmeChallengeType::TlsAlpn01,
            contact: Default::default(),
            directory: "https://acme-v02.api.letsencrypt.org/directory".to_string(),
            account_key: Default::default(),
            account_uri: Default::default(),
            renew_before: AcmeRenewBefore::R23,
            max_retries: 10i64,
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for AcmeProvider {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::ChallengeType, self.challenge_type.into_value());
        map.insert_unchecked(Property::Contact, self.contact.into_value());
        map.insert_unchecked(Property::Directory, self.directory.into_value());
        map.insert_unchecked(Property::AccountKey, JmapValue::Str(MASKED_PASSWORD.into()));
        map.insert_unchecked(Property::AccountUri, self.account_uri.into_value());
        map.insert_unchecked(Property::RenewBefore, self.renew_before.into_value());
        map.insert_unchecked(Property::MaxRetries, self.max_retries.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AcmeProvider {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ChallengeType) => self.challenge_type.patch(pointer, value),
            Some(Property::Contact) => self
                .contact
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Directory) => self.directory.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Trim]),
                value,
            ),
            Some(property @ Property::EabHmacKey) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(property @ Property::EabKeyId) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(Property::AccountKey) => pointer.assert_server_set(),
            Some(Property::AccountUri) => pointer.assert_server_set(),
            Some(Property::RenewBefore) => self.renew_before.patch(pointer, value),
            Some(Property::MaxRetries) => self.max_retries.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Action {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Action;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Action::ReloadSettings => true,
            Action::ReloadTlsCertificates => true,
            Action::ReloadLookupStores => true,
            Action::ReloadBlockedIps => true,
            Action::UpdateApps => true,
            Action::TroubleshootDmarc(inner) => inner.validate(errors),
            Action::ClassifySpam(inner) => inner.validate(errors),
            Action::InvalidateCaches => true,
            Action::InvalidateNegativeCaches => true,
            Action::PauseMtaQueue => true,
            Action::ResumeMtaQueue => true,
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for Action {
    fn default() -> Self {
        Action::ReloadSettings
    }
}

impl Pickle for Action {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Action::ReloadSettings => {
                0u16.pickle(out);
            }
            Action::ReloadTlsCertificates => {
                1u16.pickle(out);
            }
            Action::ReloadLookupStores => {
                2u16.pickle(out);
            }
            Action::ReloadBlockedIps => {
                3u16.pickle(out);
            }
            Action::UpdateApps => {
                4u16.pickle(out);
            }
            Action::TroubleshootDmarc(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            Action::ClassifySpam(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            Action::InvalidateCaches => {
                7u16.pickle(out);
            }
            Action::InvalidateNegativeCaches => {
                8u16.pickle(out);
            }
            Action::PauseMtaQueue => {
                9u16.pickle(out);
            }
            Action::ResumeMtaQueue => {
                10u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(Action::ReloadSettings),
            1 => Some(Action::ReloadTlsCertificates),
            2 => Some(Action::ReloadLookupStores),
            3 => Some(Action::ReloadBlockedIps),
            4 => Some(Action::UpdateApps),
            5 => Pickle::unpickle(stream).map(Action::TroubleshootDmarc),
            6 => Pickle::unpickle(stream).map(Action::ClassifySpam),
            7 => Some(Action::InvalidateCaches),
            8 => Some(Action::InvalidateNegativeCaches),
            9 => Some(Action::PauseMtaQueue),
            10 => Some(Action::ResumeMtaQueue),
            _ => None,
        }
    }
}

impl IntoValue for Action {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Action::ReloadSettings => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ReloadSettings".into()));
                JmapValue::Object(obj)
            }
            Action::ReloadTlsCertificates => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(
                    Property::Type,
                    JmapValue::Str("ReloadTlsCertificates".into()),
                );
                JmapValue::Object(obj)
            }
            Action::ReloadLookupStores => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ReloadLookupStores".into()));
                JmapValue::Object(obj)
            }
            Action::ReloadBlockedIps => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ReloadBlockedIps".into()));
                JmapValue::Object(obj)
            }
            Action::UpdateApps => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("UpdateApps".into()));
                JmapValue::Object(obj)
            }
            Action::TroubleshootDmarc(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TroubleshootDmarc".into()));
                obj
            }
            Action::ClassifySpam(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ClassifySpam".into()));
                obj
            }
            Action::InvalidateCaches => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("InvalidateCaches".into()));
                JmapValue::Object(obj)
            }
            Action::InvalidateNegativeCaches => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(
                    Property::Type,
                    JmapValue::Str("InvalidateNegativeCaches".into()),
                );
                JmapValue::Object(obj)
            }
            Action::PauseMtaQueue => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("PauseMtaQueue".into()));
                JmapValue::Object(obj)
            }
            Action::ResumeMtaQueue => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ResumeMtaQueue".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for Action {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                ActionType::ReloadSettings => *self = Action::ReloadSettings,
                ActionType::ReloadTlsCertificates => *self = Action::ReloadTlsCertificates,
                ActionType::ReloadLookupStores => *self = Action::ReloadLookupStores,
                ActionType::ReloadBlockedIps => *self = Action::ReloadBlockedIps,
                ActionType::UpdateApps => *self = Action::UpdateApps,
                ActionType::TroubleshootDmarc => {
                    *self = Action::TroubleshootDmarc(Default::default())
                }
                ActionType::ClassifySpam => *self = Action::ClassifySpam(Default::default()),
                ActionType::InvalidateCaches => *self = Action::InvalidateCaches,
                ActionType::InvalidateNegativeCaches => *self = Action::InvalidateNegativeCaches,
                ActionType::PauseMtaQueue => *self = Action::PauseMtaQueue,
                ActionType::ResumeMtaQueue => *self = Action::ResumeMtaQueue,
            }
        }
        match self {
            Action::ReloadSettings => pointer.assert_eof(),
            Action::ReloadTlsCertificates => pointer.assert_eof(),
            Action::ReloadLookupStores => pointer.assert_eof(),
            Action::ReloadBlockedIps => pointer.assert_eof(),
            Action::UpdateApps => pointer.assert_eof(),
            Action::TroubleshootDmarc(inner) => inner.patch(pointer, value),
            Action::ClassifySpam(inner) => inner.patch(pointer, value),
            Action::InvalidateCaches => pointer.assert_eof(),
            Action::InvalidateNegativeCaches => pointer.assert_eof(),
            Action::PauseMtaQueue => pointer.assert_eof(),
            Action::ResumeMtaQueue => pointer.assert_eof(),
        }
    }
}

impl Action {
    pub fn object_type(&self) -> ActionType {
        match self {
            Action::ReloadSettings => ActionType::ReloadSettings,
            Action::ReloadTlsCertificates => ActionType::ReloadTlsCertificates,
            Action::ReloadLookupStores => ActionType::ReloadLookupStores,
            Action::ReloadBlockedIps => ActionType::ReloadBlockedIps,
            Action::UpdateApps => ActionType::UpdateApps,
            Action::TroubleshootDmarc(_) => ActionType::TroubleshootDmarc,
            Action::ClassifySpam(_) => ActionType::ClassifySpam,
            Action::InvalidateCaches => ActionType::InvalidateCaches,
            Action::InvalidateNegativeCaches => ActionType::InvalidateNegativeCaches,
            Action::PauseMtaQueue => ActionType::PauseMtaQueue,
            Action::ResumeMtaQueue => ActionType::ResumeMtaQueue,
        }
    }
}

impl ObjectImpl for AddressBook {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AddressBook;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.default_display_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DefaultDisplayName));
            }
        }
        if let Some(value) = &self.default_href_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DefaultHrefName));
            }
        }
        if let Some(value) = &self.max_address_books {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxAddressBooks, 1));
            }
        }
        if let Some(value) = &self.max_contacts {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxContacts, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for AddressBook {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.default_display_name.pickle(out);
        self.default_href_name.pickle(out);
        self.max_v_card_size.pickle(out);
        self.max_address_books.pickle(out);
        self.max_contacts.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.default_display_name = Pickle::unpickle(stream)?;
        this.default_href_name = Pickle::unpickle(stream)?;
        this.max_v_card_size = Pickle::unpickle(stream)?;
        this.max_address_books = Pickle::unpickle(stream)?;
        this.max_contacts = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AddressBook {
    fn default() -> Self {
        Self {
            default_display_name: Some("Stalwart Address Book".to_string()),
            default_href_name: Some("default".to_string()),
            max_v_card_size: 524288u64,
            max_address_books: Some(250u64),
            max_contacts: Default::default(),
        }
    }
}

impl IntoValue for AddressBook {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(
            Property::DefaultDisplayName,
            self.default_display_name.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultHrefName,
            self.default_href_name.into_value(),
        );
        map.insert_unchecked(Property::MaxVCardSize, self.max_v_card_size.into_value());
        map.insert_unchecked(
            Property::MaxAddressBooks,
            self.max_address_books.into_value(),
        );
        map.insert_unchecked(Property::MaxContacts, self.max_contacts.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AddressBook {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DefaultDisplayName) => self
                .default_display_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DefaultHrefName) => self
                .default_href_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MaxVCardSize) => self.max_v_card_size.patch(pointer, value),
            Some(Property::MaxAddressBooks) => self.max_address_books.patch(pointer, value),
            Some(Property::MaxContacts) => self.max_contacts.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for AiModel {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AiModel;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.temperature;
        if *value > Float::new(1.0) {
            errors.push(ValidationError::max_value(Property::Temperature, 1));
        }
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::Temperature, 0));
        }
        let value = &self.model;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Model));
        }
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for AiModel {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.temperature.pickle(out);
        self.model.pickle(out);
        self.timeout.pickle(out);
        self.model_type.pickle(out);
        self.url.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.temperature = Pickle::unpickle(stream)?;
        this.model = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.model_type = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AiModel {
    fn default() -> Self {
        Self {
            name: Default::default(),
            allow_invalid_certs: false,
            temperature: Float::new(0.7f64),
            model: Default::default(),
            timeout: Duration::from_millis(120000),
            model_type: AiModelType::Chat,
            url: Default::default(),
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for AiModel {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::Temperature, self.temperature.into_value());
        map.insert_unchecked(Property::Model, self.model.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::ModelType, self.model_type.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AiModel {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self
                .name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::Temperature) => self.temperature.patch(pointer, value),
            Some(Property::Model) => self
                .model
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::ModelType) => self.model_type.patch(pointer, value),
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Alert {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Alert;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.email_alert;
        value.validate(errors);
        let value = &self.event_alert;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Alert {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: &[],
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for Alert {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.email_alert.pickle(out);
        self.event_alert.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.email_alert = Pickle::unpickle(stream)?;
        this.event_alert = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Alert {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            email_alert: Default::default(),
            event_alert: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for Alert {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::EmailAlert, self.email_alert.into_value());
        map.insert_unchecked(Property::EventAlert, self.event_alert.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Alert {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::EmailAlert) => self.email_alert.patch(pointer, value),
            Some(Property::EventAlert) => self.event_alert.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl AlertEmail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            AlertEmail::Disabled => true,
            AlertEmail::Enabled(inner) => inner.validate(errors),
        }
    }
}

impl Default for AlertEmail {
    fn default() -> Self {
        AlertEmail::Disabled
    }
}

impl Pickle for AlertEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            AlertEmail::Disabled => {
                0u16.pickle(out);
            }
            AlertEmail::Enabled(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(AlertEmail::Disabled),
            1 => Pickle::unpickle(stream).map(AlertEmail::Enabled),
            _ => None,
        }
    }
}

impl IntoValue for AlertEmail {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            AlertEmail::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            AlertEmail::Enabled(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Enabled".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for AlertEmail {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                AlertEmailType::Disabled => *self = AlertEmail::Disabled,
                AlertEmailType::Enabled => *self = AlertEmail::Enabled(Default::default()),
            }
        }
        match self {
            AlertEmail::Disabled => pointer.assert_eof(),
            AlertEmail::Enabled(inner) => inner.patch(pointer, value),
        }
    }
}

impl AlertEmail {
    pub fn object_type(&self) -> AlertEmailType {
        match self {
            AlertEmail::Disabled => AlertEmailType::Disabled,
            AlertEmail::Enabled(_) => AlertEmailType::Enabled,
        }
    }
}

impl AlertEmailProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.body;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Body));
        }
        let value = &self.from_address;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FromAddress));
        }
        if let Some(value) = &self.from_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FromName));
            }
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::To));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::To, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for AlertEmailProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.body.pickle(out);
        self.from_address.pickle(out);
        self.from_name.pickle(out);
        self.subject.pickle(out);
        self.to.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.body = Pickle::unpickle(stream)?;
        this.from_address = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.to = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AlertEmailProperties {
    fn default() -> Self {
        Self {
            body: Default::default(),
            from_address: Default::default(),
            from_name: Default::default(),
            subject: Default::default(),
            to: Default::default(),
        }
    }
}

impl IntoValue for AlertEmailProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Body, self.body.into_value());
        map.insert_unchecked(Property::FromAddress, self.from_address.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::To, self.to.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AlertEmailProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Body) => self.body.patch(pointer, value),
            Some(Property::FromAddress) => self
                .from_address
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::FromName) => self.from_name.patch(pointer, value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::To) => self
                .to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl AlertEvent {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            AlertEvent::Disabled => true,
            AlertEvent::Enabled(inner) => inner.validate(errors),
        }
    }
}

impl Default for AlertEvent {
    fn default() -> Self {
        AlertEvent::Disabled
    }
}

impl Pickle for AlertEvent {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            AlertEvent::Disabled => {
                0u16.pickle(out);
            }
            AlertEvent::Enabled(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(AlertEvent::Disabled),
            1 => Pickle::unpickle(stream).map(AlertEvent::Enabled),
            _ => None,
        }
    }
}

impl IntoValue for AlertEvent {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            AlertEvent::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            AlertEvent::Enabled(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Enabled".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for AlertEvent {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                AlertEventType::Disabled => *self = AlertEvent::Disabled,
                AlertEventType::Enabled => *self = AlertEvent::Enabled(Default::default()),
            }
        }
        match self {
            AlertEvent::Disabled => pointer.assert_eof(),
            AlertEvent::Enabled(inner) => inner.patch(pointer, value),
        }
    }
}

impl AlertEvent {
    pub fn object_type(&self) -> AlertEventType {
        match self {
            AlertEvent::Disabled => AlertEventType::Disabled,
            AlertEvent::Enabled(_) => AlertEventType::Enabled,
        }
    }
}

impl AlertEventProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.event_message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EventMessage));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for AlertEventProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.event_message.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.event_message = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AlertEventProperties {
    fn default() -> Self {
        Self {
            event_message: Default::default(),
        }
    }
}

impl IntoValue for AlertEventProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::EventMessage, self.event_message.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AlertEventProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::EventMessage) => self.event_message.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for AllowedIp {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AllowedIp;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.address;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Address, value));
        }
        if let Some(value) = &self.reason {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Reason));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Address, &self.address);
    }
}

impl Pickle for AllowedIp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.address.pickle(out);
        self.reason.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.address = Pickle::unpickle(stream)?;
        this.reason = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AllowedIp {
    fn default() -> Self {
        Self {
            address: Default::default(),
            reason: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
        }
    }
}

impl IntoValue for AllowedIp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Address, self.address.into_value());
        map.insert_unchecked(Property::Reason, self.reason.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AllowedIp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Address) => self.address.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Trim]),
                value,
            ),
            Some(Property::Reason) => self
                .reason
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::CreatedAt) => self.created_at.patch(pointer.assert_read_only()?, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ApiKey {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ApiKey;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        let value = &self.permissions;
        value.validate(errors);
        let value = &self.allowed_ips;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::AllowedIps, value));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for ApiKey {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.secret.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
        self.permissions.pickle(out);
        self.allowed_ips.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.allowed_ips = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ApiKey {
    fn default() -> Self {
        Self {
            description: Default::default(),
            secret: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
            permissions: Default::default(),
            allowed_ips: Default::default(),
        }
    }
}

impl IntoValue for ApiKey {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::AllowedIps, self.allowed_ips.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ApiKey {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Secret) => pointer.assert_server_set(),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::AllowedIps) => self.allowed_ips.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for AppPassword {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::AppPassword;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        let value = &self.permissions;
        value.validate(errors);
        let value = &self.allowed_ips;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::AllowedIps, value));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for AppPassword {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.secret.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
        self.permissions.pickle(out);
        self.allowed_ips.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.allowed_ips = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AppPassword {
    fn default() -> Self {
        Self {
            description: Default::default(),
            secret: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
            permissions: Default::default(),
            allowed_ips: Default::default(),
        }
    }
}

impl IntoValue for AppPassword {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::AllowedIps, self.allowed_ips.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AppPassword {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Secret) => pointer.assert_server_set(),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::AllowedIps) => self.allowed_ips.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Application {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Application;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.resource_url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ResourceUrl));
        }
        let value = &self.url_prefix;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::UrlPrefix));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::UrlPrefix, 1));
        }
        if let Some(value) = &self.unpack_directory {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::UnpackDirectory));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Application {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enabled.pickle(out);
        self.description.pickle(out);
        self.resource_url.pickle(out);
        self.url_prefix.pickle(out);
        self.auto_update_frequency.pickle(out);
        self.unpack_directory.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enabled = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.resource_url = Pickle::unpickle(stream)?;
        this.url_prefix = Pickle::unpickle(stream)?;
        this.auto_update_frequency = Pickle::unpickle(stream)?;
        this.unpack_directory = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Application {
    fn default() -> Self {
        Self {
            enabled: true,
            description: Default::default(),
            resource_url: Default::default(),
            url_prefix: Default::default(),
            auto_update_frequency: Duration::from_millis(7776000000),
            unpack_directory: Default::default(),
        }
    }
}

impl IntoValue for Application {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Enabled, self.enabled.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::ResourceUrl, self.resource_url.into_value());
        map.insert_unchecked(Property::UrlPrefix, self.url_prefix.into_value());
        map.insert_unchecked(
            Property::AutoUpdateFrequency,
            self.auto_update_frequency.into_value(),
        );
        map.insert_unchecked(
            Property::UnpackDirectory,
            self.unpack_directory.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Application {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enabled) => self.enabled.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ResourceUrl) => self
                .resource_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::UrlPrefix) => self
                .url_prefix
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AutoUpdateFrequency) => self.auto_update_frequency.patch(pointer, value),
            Some(Property::UnpackDirectory) => self
                .unpack_directory
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ArchivedCalendarEvent {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.title;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Title));
        }
        if let Some(value) = &self.start_time {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::StartTime, value));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.archived_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for ArchivedCalendarEvent {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.title.pickle(out);
        self.start_time.pickle(out);
        self.created_at.pickle(out);
        self.account_id.pickle(out);
        self.archived_at.pickle(out);
        self.archived_until.pickle(out);
        self.blob_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.title = Pickle::unpickle(stream)?;
        this.start_time = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.archived_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArchivedCalendarEvent {
    fn default() -> Self {
        Self {
            title: Default::default(),
            start_time: Default::default(),
            created_at: Default::default(),
            account_id: Default::default(),
            archived_at: Default::default(),
            archived_until: Default::default(),
            blob_id: Default::default(),
        }
    }
}

impl IntoValue for ArchivedCalendarEvent {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Title, self.title.into_value());
        map.insert_unchecked(Property::StartTime, self.start_time.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ArchivedAt, self.archived_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArchivedCalendarEvent {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Title) => self.title.patch(pointer, value),
            Some(Property::StartTime) => self.start_time.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_can_set_account()?, value),
            Some(Property::ArchivedAt) => self.archived_at.patch(pointer, value),
            Some(Property::ArchivedUntil) => self.archived_until.patch(pointer, value),
            Some(Property::BlobId) => self.blob_id.patch(pointer, value),
            Some(property @ Property::Status) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ArchivedContactCard {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Name));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.archived_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for ArchivedContactCard {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.created_at.pickle(out);
        self.account_id.pickle(out);
        self.archived_at.pickle(out);
        self.archived_until.pickle(out);
        self.blob_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.archived_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArchivedContactCard {
    fn default() -> Self {
        Self {
            name: Default::default(),
            created_at: Default::default(),
            account_id: Default::default(),
            archived_at: Default::default(),
            archived_until: Default::default(),
            blob_id: Default::default(),
        }
    }
}

impl IntoValue for ArchivedContactCard {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ArchivedAt, self.archived_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArchivedContactCard {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_can_set_account()?, value),
            Some(Property::ArchivedAt) => self.archived_at.patch(pointer, value),
            Some(Property::ArchivedUntil) => self.archived_until.patch(pointer, value),
            Some(Property::BlobId) => self.blob_id.patch(pointer, value),
            Some(property @ Property::Status) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ArchivedEmail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.received_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ReceivedAt, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.archived_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for ArchivedEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from.pickle(out);
        self.subject.pickle(out);
        self.received_at.pickle(out);
        self.size.pickle(out);
        self.account_id.pickle(out);
        self.archived_at.pickle(out);
        self.archived_until.pickle(out);
        self.blob_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.received_at = Pickle::unpickle(stream)?;
        this.size = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.archived_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArchivedEmail {
    fn default() -> Self {
        Self {
            from: Default::default(),
            subject: Default::default(),
            received_at: Default::default(),
            size: 0u64,
            account_id: Default::default(),
            archived_at: Default::default(),
            archived_until: Default::default(),
            blob_id: Default::default(),
        }
    }
}

impl IntoValue for ArchivedEmail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::ReceivedAt, self.received_at.into_value());
        map.insert_unchecked(Property::Size, self.size.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ArchivedAt, self.archived_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArchivedEmail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::From) => self.from.patch(pointer, value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::ReceivedAt) => self.received_at.patch(pointer, value),
            Some(Property::Size) => self.size.patch(pointer.assert_read_only()?, value),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_can_set_account()?, value),
            Some(Property::ArchivedAt) => self.archived_at.patch(pointer, value),
            Some(Property::ArchivedUntil) => self.archived_until.patch(pointer, value),
            Some(Property::BlobId) => self.blob_id.patch(pointer, value),
            Some(property @ Property::Status) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ArchivedFileNode {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.archived_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for ArchivedFileNode {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.created_at.pickle(out);
        self.account_id.pickle(out);
        self.archived_at.pickle(out);
        self.archived_until.pickle(out);
        self.blob_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.archived_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArchivedFileNode {
    fn default() -> Self {
        Self {
            name: Default::default(),
            created_at: Default::default(),
            account_id: Default::default(),
            archived_at: Default::default(),
            archived_until: Default::default(),
            blob_id: Default::default(),
        }
    }
}

impl IntoValue for ArchivedFileNode {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ArchivedAt, self.archived_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArchivedFileNode {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_can_set_account()?, value),
            Some(Property::ArchivedAt) => self.archived_at.patch(pointer, value),
            Some(Property::ArchivedUntil) => self.archived_until.patch(pointer, value),
            Some(Property::BlobId) => self.blob_id.patch(pointer, value),
            Some(property @ Property::Status) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ArchivedItem {
    const FLAGS: u64 = OBJ_FILTER_ACCOUNT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ArchivedItem;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            ArchivedItem::Email(inner) => inner.validate(errors),
            ArchivedItem::FileNode(inner) => inner.validate(errors),
            ArchivedItem::CalendarEvent(inner) => inner.validate(errors),
            ArchivedItem::ContactCard(inner) => inner.validate(errors),
            ArchivedItem::SieveScript(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            ArchivedItem::Email(object) => {
                object.index(i);
            }
            ArchivedItem::FileNode(object) => {
                object.index(i);
            }
            ArchivedItem::CalendarEvent(object) => {
                object.index(i);
            }
            ArchivedItem::ContactCard(object) => {
                object.index(i);
            }
            ArchivedItem::SieveScript(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for ArchivedItem {
    fn default() -> Self {
        ArchivedItem::Email(Default::default())
    }
}

impl Pickle for ArchivedItem {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            ArchivedItem::Email(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            ArchivedItem::FileNode(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            ArchivedItem::CalendarEvent(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            ArchivedItem::ContactCard(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            ArchivedItem::SieveScript(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(ArchivedItem::Email),
            1 => Pickle::unpickle(stream).map(ArchivedItem::FileNode),
            2 => Pickle::unpickle(stream).map(ArchivedItem::CalendarEvent),
            3 => Pickle::unpickle(stream).map(ArchivedItem::ContactCard),
            4 => Pickle::unpickle(stream).map(ArchivedItem::SieveScript),
            _ => None,
        }
    }
}

impl IntoValue for ArchivedItem {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            ArchivedItem::Email(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Email".into()));
                obj
            }
            ArchivedItem::FileNode(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FileNode".into()));
                obj
            }
            ArchivedItem::CalendarEvent(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("CalendarEvent".into()));
                obj
            }
            ArchivedItem::ContactCard(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ContactCard".into()));
                obj
            }
            ArchivedItem::SieveScript(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("SieveScript".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for ArchivedItem {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                ArchivedItemType::Email => *self = ArchivedItem::Email(Default::default()),
                ArchivedItemType::FileNode => *self = ArchivedItem::FileNode(Default::default()),
                ArchivedItemType::CalendarEvent => {
                    *self = ArchivedItem::CalendarEvent(Default::default())
                }
                ArchivedItemType::ContactCard => {
                    *self = ArchivedItem::ContactCard(Default::default())
                }
                ArchivedItemType::SieveScript => {
                    *self = ArchivedItem::SieveScript(Default::default())
                }
            }
        }
        match self {
            ArchivedItem::Email(inner) => inner.patch(pointer, value),
            ArchivedItem::FileNode(inner) => inner.patch(pointer, value),
            ArchivedItem::CalendarEvent(inner) => inner.patch(pointer, value),
            ArchivedItem::ContactCard(inner) => inner.patch(pointer, value),
            ArchivedItem::SieveScript(inner) => inner.patch(pointer, value),
        }
    }
}

impl ArchivedItem {
    pub fn object_type(&self) -> ArchivedItemType {
        match self {
            ArchivedItem::Email(_) => ArchivedItemType::Email,
            ArchivedItem::FileNode(_) => ArchivedItemType::FileNode,
            ArchivedItem::CalendarEvent(_) => ArchivedItemType::CalendarEvent,
            ArchivedItem::ContactCard(_) => ArchivedItemType::ContactCard,
            ArchivedItem::SieveScript(_) => ArchivedItemType::SieveScript,
        }
    }
}

impl ArchivedSieveScript {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.content;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Content));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.archived_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for ArchivedSieveScript {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.created_at.pickle(out);
        self.content.pickle(out);
        self.account_id.pickle(out);
        self.archived_at.pickle(out);
        self.archived_until.pickle(out);
        self.blob_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.content = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.archived_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArchivedSieveScript {
    fn default() -> Self {
        Self {
            name: Default::default(),
            created_at: Default::default(),
            content: Default::default(),
            account_id: Default::default(),
            archived_at: Default::default(),
            archived_until: Default::default(),
            blob_id: Default::default(),
        }
    }
}

impl IntoValue for ArchivedSieveScript {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::Content, self.content.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ArchivedAt, self.archived_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArchivedSieveScript {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::Content) => self.content.patch(pointer, value),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_can_set_account()?, value),
            Some(Property::ArchivedAt) => self.archived_at.patch(pointer, value),
            Some(Property::ArchivedUntil) => self.archived_until.patch(pointer, value),
            Some(Property::BlobId) => self.blob_id.patch(pointer, value),
            Some(property @ Property::Status) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ArfExternalReport {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ArfExternalReport;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.report;
        value.validate(errors);
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::To));
            }
        }
        let value = &self.received_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ReceivedAt, value));
        }
        let value = &self.expires_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ExpiresAt, value));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
    }
}

impl Pickle for ArfExternalReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.report.pickle(out);
        self.from.pickle(out);
        self.subject.pickle(out);
        self.to.pickle(out);
        self.received_at.pickle(out);
        self.expires_at.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.report = Pickle::unpickle(stream)?;
        this.from = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.to = Pickle::unpickle(stream)?;
        this.received_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArfExternalReport {
    fn default() -> Self {
        Self {
            report: Default::default(),
            from: Default::default(),
            subject: Default::default(),
            to: Default::default(),
            received_at: Default::default(),
            expires_at: Default::default(),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for ArfExternalReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::To, self.to.into_value());
        map.insert_unchecked(Property::ReceivedAt, self.received_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArfExternalReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::From) => self
                .from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::To) => self
                .to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::ReceivedAt) => self.received_at.patch(pointer, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ArfFeedbackReport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.arrival_date {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ArrivalDate, value));
            }
        }
        let value = &self.authentication_results;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthenticationResults));
            }
        }
        if let Some(value) = &self.original_envelope_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OriginalEnvelopeId));
            }
        }
        if let Some(value) = &self.original_mail_from {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OriginalMailFrom));
            }
        }
        if let Some(value) = &self.original_rcpt_to {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OriginalRcptTo));
            }
        }
        let value = &self.reported_domains;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReportedDomains));
            }
        }
        let value = &self.reported_uris;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReportedUris));
            }
        }
        if let Some(value) = &self.reporting_mta {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReportingMta));
            }
        }
        if let Some(value) = &self.source_ip {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::SourceIp, value));
            }
        }
        if let Some(value) = &self.source_port {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::SourcePort, 1));
            }
            if *value > 65535 {
                errors.push(ValidationError::max_value(Property::SourcePort, 65535));
            }
        }
        if let Some(value) = &self.user_agent {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::UserAgent));
            }
        }
        if let Some(value) = &self.dkim_adsp_dns {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimAdspDns));
            }
        }
        if let Some(value) = &self.dkim_canonicalized_body {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimCanonicalizedBody));
            }
        }
        if let Some(value) = &self.dkim_canonicalized_header {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimCanonicalizedHeader));
            }
        }
        if let Some(value) = &self.dkim_domain {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimDomain));
            }
        }
        if let Some(value) = &self.dkim_identity {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimIdentity));
            }
        }
        if let Some(value) = &self.dkim_selector {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimSelector));
            }
        }
        if let Some(value) = &self.dkim_selector_dns {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DkimSelectorDns));
            }
        }
        if let Some(value) = &self.spf_dns {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::SpfDns));
            }
        }
        if let Some(value) = &self.message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Message));
            }
        }
        if let Some(value) = &self.headers {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Headers));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for ArfFeedbackReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.feedback_type.pickle(out);
        self.arrival_date.pickle(out);
        self.authentication_results.pickle(out);
        self.incidents.pickle(out);
        self.original_envelope_id.pickle(out);
        self.original_mail_from.pickle(out);
        self.original_rcpt_to.pickle(out);
        self.reported_domains.pickle(out);
        self.reported_uris.pickle(out);
        self.reporting_mta.pickle(out);
        self.source_ip.pickle(out);
        self.source_port.pickle(out);
        self.user_agent.pickle(out);
        self.version.pickle(out);
        self.auth_failure.pickle(out);
        self.delivery_result.pickle(out);
        self.dkim_adsp_dns.pickle(out);
        self.dkim_canonicalized_body.pickle(out);
        self.dkim_canonicalized_header.pickle(out);
        self.dkim_domain.pickle(out);
        self.dkim_identity.pickle(out);
        self.dkim_selector.pickle(out);
        self.dkim_selector_dns.pickle(out);
        self.spf_dns.pickle(out);
        self.identity_alignment.pickle(out);
        self.message.pickle(out);
        self.headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.feedback_type = Pickle::unpickle(stream)?;
        this.arrival_date = Pickle::unpickle(stream)?;
        this.authentication_results = Pickle::unpickle(stream)?;
        this.incidents = Pickle::unpickle(stream)?;
        this.original_envelope_id = Pickle::unpickle(stream)?;
        this.original_mail_from = Pickle::unpickle(stream)?;
        this.original_rcpt_to = Pickle::unpickle(stream)?;
        this.reported_domains = Pickle::unpickle(stream)?;
        this.reported_uris = Pickle::unpickle(stream)?;
        this.reporting_mta = Pickle::unpickle(stream)?;
        this.source_ip = Pickle::unpickle(stream)?;
        this.source_port = Pickle::unpickle(stream)?;
        this.user_agent = Pickle::unpickle(stream)?;
        this.version = Pickle::unpickle(stream)?;
        this.auth_failure = Pickle::unpickle(stream)?;
        this.delivery_result = Pickle::unpickle(stream)?;
        this.dkim_adsp_dns = Pickle::unpickle(stream)?;
        this.dkim_canonicalized_body = Pickle::unpickle(stream)?;
        this.dkim_canonicalized_header = Pickle::unpickle(stream)?;
        this.dkim_domain = Pickle::unpickle(stream)?;
        this.dkim_identity = Pickle::unpickle(stream)?;
        this.dkim_selector = Pickle::unpickle(stream)?;
        this.dkim_selector_dns = Pickle::unpickle(stream)?;
        this.spf_dns = Pickle::unpickle(stream)?;
        this.identity_alignment = Pickle::unpickle(stream)?;
        this.message = Pickle::unpickle(stream)?;
        this.headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ArfFeedbackReport {
    fn default() -> Self {
        Self {
            feedback_type: Default::default(),
            arrival_date: Default::default(),
            authentication_results: Default::default(),
            incidents: 0u64,
            original_envelope_id: Default::default(),
            original_mail_from: Default::default(),
            original_rcpt_to: Default::default(),
            reported_domains: Default::default(),
            reported_uris: Default::default(),
            reporting_mta: Default::default(),
            source_ip: Default::default(),
            source_port: Default::default(),
            user_agent: Default::default(),
            version: 1u64,
            auth_failure: Default::default(),
            delivery_result: Default::default(),
            dkim_adsp_dns: Default::default(),
            dkim_canonicalized_body: Default::default(),
            dkim_canonicalized_header: Default::default(),
            dkim_domain: Default::default(),
            dkim_identity: Default::default(),
            dkim_selector: Default::default(),
            dkim_selector_dns: Default::default(),
            spf_dns: Default::default(),
            identity_alignment: Default::default(),
            message: Default::default(),
            headers: Default::default(),
        }
    }
}

impl IntoValue for ArfFeedbackReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(29);
        map.insert_unchecked(Property::FeedbackType, self.feedback_type.into_value());
        map.insert_unchecked(Property::ArrivalDate, self.arrival_date.into_value());
        map.insert_unchecked(
            Property::AuthenticationResults,
            self.authentication_results.into_value(),
        );
        map.insert_unchecked(Property::Incidents, self.incidents.into_value());
        map.insert_unchecked(
            Property::OriginalEnvelopeId,
            self.original_envelope_id.into_value(),
        );
        map.insert_unchecked(
            Property::OriginalMailFrom,
            self.original_mail_from.into_value(),
        );
        map.insert_unchecked(Property::OriginalRcptTo, self.original_rcpt_to.into_value());
        map.insert_unchecked(
            Property::ReportedDomains,
            self.reported_domains.into_value(),
        );
        map.insert_unchecked(Property::ReportedUris, self.reported_uris.into_value());
        map.insert_unchecked(Property::ReportingMta, self.reporting_mta.into_value());
        map.insert_unchecked(Property::SourceIp, self.source_ip.into_value());
        map.insert_unchecked(Property::SourcePort, self.source_port.into_value());
        map.insert_unchecked(Property::UserAgent, self.user_agent.into_value());
        map.insert_unchecked(Property::Version, self.version.into_value());
        map.insert_unchecked(Property::AuthFailure, self.auth_failure.into_value());
        map.insert_unchecked(Property::DeliveryResult, self.delivery_result.into_value());
        map.insert_unchecked(Property::DkimAdspDns, self.dkim_adsp_dns.into_value());
        map.insert_unchecked(
            Property::DkimCanonicalizedBody,
            self.dkim_canonicalized_body.into_value(),
        );
        map.insert_unchecked(
            Property::DkimCanonicalizedHeader,
            self.dkim_canonicalized_header.into_value(),
        );
        map.insert_unchecked(Property::DkimDomain, self.dkim_domain.into_value());
        map.insert_unchecked(Property::DkimIdentity, self.dkim_identity.into_value());
        map.insert_unchecked(Property::DkimSelector, self.dkim_selector.into_value());
        map.insert_unchecked(
            Property::DkimSelectorDns,
            self.dkim_selector_dns.into_value(),
        );
        map.insert_unchecked(Property::SpfDns, self.spf_dns.into_value());
        map.insert_unchecked(
            Property::IdentityAlignment,
            self.identity_alignment.into_value(),
        );
        map.insert_unchecked(Property::Message, self.message.into_value());
        map.insert_unchecked(Property::Headers, self.headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ArfFeedbackReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::FeedbackType) => self.feedback_type.patch(pointer, value),
            Some(Property::ArrivalDate) => self.arrival_date.patch(pointer, value),
            Some(Property::AuthenticationResults) => {
                self.authentication_results.patch(pointer, value)
            }
            Some(Property::Incidents) => self.incidents.patch(pointer, value),
            Some(Property::OriginalEnvelopeId) => self.original_envelope_id.patch(pointer, value),
            Some(Property::OriginalMailFrom) => self
                .original_mail_from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::OriginalRcptTo) => self
                .original_rcpt_to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::ReportedDomains) => self
                .reported_domains
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::ReportedUris) => self.reported_uris.patch(pointer, value),
            Some(Property::ReportingMta) => self.reporting_mta.patch(pointer, value),
            Some(Property::SourceIp) => self.source_ip.patch(pointer, value),
            Some(Property::SourcePort) => self.source_port.patch(pointer, value),
            Some(Property::UserAgent) => self.user_agent.patch(pointer, value),
            Some(Property::Version) => self.version.patch(pointer, value),
            Some(Property::AuthFailure) => self.auth_failure.patch(pointer, value),
            Some(Property::DeliveryResult) => self.delivery_result.patch(pointer, value),
            Some(Property::DkimAdspDns) => self.dkim_adsp_dns.patch(pointer, value),
            Some(Property::DkimCanonicalizedBody) => {
                self.dkim_canonicalized_body.patch(pointer, value)
            }
            Some(Property::DkimCanonicalizedHeader) => {
                self.dkim_canonicalized_header.patch(pointer, value)
            }
            Some(Property::DkimDomain) => self.dkim_domain.patch(pointer, value),
            Some(Property::DkimIdentity) => self.dkim_identity.patch(pointer, value),
            Some(Property::DkimSelector) => self.dkim_selector.patch(pointer, value),
            Some(Property::DkimSelectorDns) => self.dkim_selector_dns.patch(pointer, value),
            Some(Property::SpfDns) => self.spf_dns.patch(pointer, value),
            Some(Property::IdentityAlignment) => self.identity_alignment.patch(pointer, value),
            Some(Property::Message) => self.message.patch(pointer, value),
            Some(Property::Headers) => self.headers.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Asn {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Asn;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Asn::Disabled => true,
            Asn::Resource(inner) => inner.validate(errors),
            Asn::Dns(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for Asn {
    fn default() -> Self {
        Asn::Disabled
    }
}

impl Pickle for Asn {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Asn::Disabled => {
                0u16.pickle(out);
            }
            Asn::Resource(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Asn::Dns(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(Asn::Disabled),
            1 => Pickle::unpickle(stream).map(Asn::Resource),
            2 => Pickle::unpickle(stream).map(Asn::Dns),
            _ => None,
        }
    }
}

impl IntoValue for Asn {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Asn::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            Asn::Resource(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Resource".into()));
                obj
            }
            Asn::Dns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dns".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Asn {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                AsnType::Disabled => *self = Asn::Disabled,
                AsnType::Resource => *self = Asn::Resource(Default::default()),
                AsnType::Dns => *self = Asn::Dns(Default::default()),
            }
        }
        match self {
            Asn::Disabled => pointer.assert_eof(),
            Asn::Resource(inner) => inner.patch(pointer, value),
            Asn::Dns(inner) => inner.patch(pointer, value),
        }
    }
}

impl Asn {
    pub fn object_type(&self) -> AsnType {
        match self {
            Asn::Disabled => AsnType::Disabled,
            Asn::Resource(_) => AsnType::Resource,
            Asn::Dns(_) => AsnType::Dns,
        }
    }
}

impl AsnDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.separator;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Separator));
        }
        let value = &self.zone_ip_v4;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ZoneIpV4));
        }
        let value = &self.zone_ip_v6;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ZoneIpV6));
        }
        errors.len() == neb
    }
}

impl Pickle for AsnDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.index_asn.pickle(out);
        self.index_asn_name.pickle(out);
        self.index_country.pickle(out);
        self.separator.pickle(out);
        self.zone_ip_v4.pickle(out);
        self.zone_ip_v6.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.index_asn = Pickle::unpickle(stream)?;
        this.index_asn_name = Pickle::unpickle(stream)?;
        this.index_country = Pickle::unpickle(stream)?;
        this.separator = Pickle::unpickle(stream)?;
        this.zone_ip_v4 = Pickle::unpickle(stream)?;
        this.zone_ip_v6 = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AsnDns {
    fn default() -> Self {
        Self {
            index_asn: 0u64,
            index_asn_name: Default::default(),
            index_country: Default::default(),
            separator: "|".to_string(),
            zone_ip_v4: Default::default(),
            zone_ip_v6: Default::default(),
        }
    }
}

impl IntoValue for AsnDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::IndexAsn, self.index_asn.into_value());
        map.insert_unchecked(Property::IndexAsnName, self.index_asn_name.into_value());
        map.insert_unchecked(Property::IndexCountry, self.index_country.into_value());
        map.insert_unchecked(Property::Separator, self.separator.into_value());
        map.insert_unchecked(Property::ZoneIpV4, self.zone_ip_v4.into_value());
        map.insert_unchecked(Property::ZoneIpV6, self.zone_ip_v6.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AsnDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IndexAsn) => self.index_asn.patch(pointer, value),
            Some(Property::IndexAsnName) => self.index_asn_name.patch(pointer, value),
            Some(Property::IndexCountry) => self.index_country.patch(pointer, value),
            Some(Property::Separator) => self
                .separator
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ZoneIpV4) => self
                .zone_ip_v4
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ZoneIpV6) => self
                .zone_ip_v6
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl AsnResource {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.asn_urls;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AsnUrls));
            }
        }
        let value = &self.geo_urls;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::GeoUrls));
            }
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for AsnResource {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.expires.pickle(out);
        self.max_size.pickle(out);
        self.timeout.pickle(out);
        self.asn_urls.pickle(out);
        self.geo_urls.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.expires = Pickle::unpickle(stream)?;
        this.max_size = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.asn_urls = Pickle::unpickle(stream)?;
        this.geo_urls = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AsnResource {
    fn default() -> Self {
        Self {
            expires: Duration::from_millis(86400000),
            max_size: 104857600,
            timeout: Duration::from_millis(300000),
            asn_urls: Default::default(),
            geo_urls: Default::default(),
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for AsnResource {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Expires, self.expires.into_value());
        map.insert_unchecked(Property::MaxSize, self.max_size.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::AsnUrls, self.asn_urls.into_value());
        map.insert_unchecked(Property::GeoUrls, self.geo_urls.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AsnResource {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Expires) => self.expires.patch(pointer, value),
            Some(Property::MaxSize) => self.max_size.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AsnUrls) => self
                .asn_urls
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::GeoUrls) => self
                .geo_urls
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Authentication {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Authentication;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.directory_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DirectoryId));
            }
        }
        let value = &self.default_user_role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DefaultUserRoleIds));
            }
        }
        let value = &self.default_group_role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DefaultGroupRoleIds));
            }
        }
        let value = &self.default_tenant_role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DefaultTenantRoleIds));
            }
        }
        let value = &self.default_admin_role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DefaultAdminRoleIds));
            }
        }
        let value = &self.password_min_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PasswordMinLength, 1));
        }
        if *value > 100 {
            errors.push(ValidationError::max_value(Property::PasswordMinLength, 100));
        }
        let value = &self.password_max_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PasswordMaxLength, 1));
        }
        if *value > 1000 {
            errors.push(ValidationError::max_value(
                Property::PasswordMaxLength,
                1000,
            ));
        }
        if let Some(value) = &self.max_app_passwords {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxAppPasswords, 1));
            }
        }
        if let Some(value) = &self.max_api_keys {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxApiKeys, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Directory, self.directory_id, None);
        for id in self.default_user_role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
        for id in self.default_group_role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
        for id in self.default_tenant_role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
        for id in self.default_admin_role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
    }
}

impl Pickle for Authentication {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.directory_id.pickle(out);
        self.default_user_role_ids.pickle(out);
        self.default_group_role_ids.pickle(out);
        self.default_tenant_role_ids.pickle(out);
        self.default_admin_role_ids.pickle(out);
        self.password_hash_algorithm.pickle(out);
        self.password_min_length.pickle(out);
        self.password_max_length.pickle(out);
        self.password_min_strength.pickle(out);
        self.password_default_expiry.pickle(out);
        self.max_app_passwords.pickle(out);
        self.max_api_keys.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.directory_id = Pickle::unpickle(stream)?;
        this.default_user_role_ids = Pickle::unpickle(stream)?;
        this.default_group_role_ids = Pickle::unpickle(stream)?;
        this.default_tenant_role_ids = Pickle::unpickle(stream)?;
        this.default_admin_role_ids = Pickle::unpickle(stream)?;
        this.password_hash_algorithm = Pickle::unpickle(stream)?;
        this.password_min_length = Pickle::unpickle(stream)?;
        this.password_max_length = Pickle::unpickle(stream)?;
        this.password_min_strength = Pickle::unpickle(stream)?;
        this.password_default_expiry = Pickle::unpickle(stream)?;
        this.max_app_passwords = Pickle::unpickle(stream)?;
        this.max_api_keys = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Authentication {
    fn default() -> Self {
        Self {
            directory_id: Default::default(),
            default_user_role_ids: Default::default(),
            default_group_role_ids: Default::default(),
            default_tenant_role_ids: Default::default(),
            default_admin_role_ids: Default::default(),
            password_hash_algorithm: PasswordHashAlgorithm::Argon2id,
            password_min_length: 8u64,
            password_max_length: 128u64,
            password_min_strength: PasswordStrength::Three,
            password_default_expiry: Default::default(),
            max_app_passwords: Some(5u64),
            max_api_keys: Some(5u64),
        }
    }
}

impl IntoValue for Authentication {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::DirectoryId, self.directory_id.into_value());
        map.insert_unchecked(
            Property::DefaultUserRoleIds,
            self.default_user_role_ids.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultGroupRoleIds,
            self.default_group_role_ids.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultTenantRoleIds,
            self.default_tenant_role_ids.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultAdminRoleIds,
            self.default_admin_role_ids.into_value(),
        );
        map.insert_unchecked(
            Property::PasswordHashAlgorithm,
            self.password_hash_algorithm.into_value(),
        );
        map.insert_unchecked(
            Property::PasswordMinLength,
            self.password_min_length.into_value(),
        );
        map.insert_unchecked(
            Property::PasswordMaxLength,
            self.password_max_length.into_value(),
        );
        map.insert_unchecked(
            Property::PasswordMinStrength,
            self.password_min_strength.into_value(),
        );
        map.insert_unchecked(
            Property::PasswordDefaultExpiry,
            self.password_default_expiry.into_value(),
        );
        map.insert_unchecked(
            Property::MaxAppPasswords,
            self.max_app_passwords.into_value(),
        );
        map.insert_unchecked(Property::MaxApiKeys, self.max_api_keys.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Authentication {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DirectoryId) => self.directory_id.patch(pointer, value),
            Some(Property::DefaultUserRoleIds) => self.default_user_role_ids.patch(pointer, value),
            Some(Property::DefaultGroupRoleIds) => {
                self.default_group_role_ids.patch(pointer, value)
            }
            Some(Property::DefaultTenantRoleIds) => {
                self.default_tenant_role_ids.patch(pointer, value)
            }
            Some(Property::DefaultAdminRoleIds) => {
                self.default_admin_role_ids.patch(pointer, value)
            }
            Some(Property::PasswordHashAlgorithm) => {
                self.password_hash_algorithm.patch(pointer, value)
            }
            Some(Property::PasswordMinLength) => self.password_min_length.patch(pointer, value),
            Some(Property::PasswordMaxLength) => self.password_max_length.patch(pointer, value),
            Some(Property::PasswordMinStrength) => self.password_min_strength.patch(pointer, value),
            Some(Property::PasswordDefaultExpiry) => {
                self.password_default_expiry.patch(pointer, value)
            }
            Some(Property::MaxAppPasswords) => self.max_app_passwords.patch(pointer, value),
            Some(Property::MaxApiKeys) => self.max_api_keys.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl AzureStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.storage_account;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::StorageAccount));
        }
        let value = &self.container;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Container));
        }
        let value = &self.access_key;
        value.validate(errors);
        let value = &self.sas_token;
        value.validate(errors);
        let value = &self.max_retries;
        if *value > 10 {
            errors.push(ValidationError::max_value(Property::MaxRetries, 10));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxRetries, 1));
        }
        if let Some(value) = &self.key_prefix {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::KeyPrefix));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for AzureStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.storage_account.pickle(out);
        self.container.pickle(out);
        self.access_key.pickle(out);
        self.sas_token.pickle(out);
        self.timeout.pickle(out);
        self.max_retries.pickle(out);
        self.key_prefix.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.storage_account = Pickle::unpickle(stream)?;
        this.container = Pickle::unpickle(stream)?;
        this.access_key = Pickle::unpickle(stream)?;
        this.sas_token = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.max_retries = Pickle::unpickle(stream)?;
        this.key_prefix = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for AzureStore {
    fn default() -> Self {
        Self {
            storage_account: Default::default(),
            container: Default::default(),
            access_key: Default::default(),
            sas_token: Default::default(),
            timeout: Duration::from_millis(30000),
            max_retries: 3u64,
            key_prefix: Default::default(),
        }
    }
}

impl IntoValue for AzureStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::StorageAccount, self.storage_account.into_value());
        map.insert_unchecked(Property::Container, self.container.into_value());
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SasToken, self.sas_token.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::MaxRetries, self.max_retries.into_value());
        map.insert_unchecked(Property::KeyPrefix, self.key_prefix.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for AzureStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::StorageAccount) => self
                .storage_account
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Container) => self
                .container
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AccessKey) => self.access_key.patch(pointer, value),
            Some(Property::SasToken) => self.sas_token.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::MaxRetries) => self.max_retries.patch(pointer, value),
            Some(Property::KeyPrefix) => self
                .key_prefix
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for BlobStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 1;
    const OBJECT: ObjectType = ObjectType::BlobStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            BlobStore::Default => true,
            BlobStore::Sharded(inner) => inner.validate(errors),
            BlobStore::S3(inner) => inner.validate(errors),
            BlobStore::Azure(inner) => inner.validate(errors),
            BlobStore::FileSystem(inner) => inner.validate(errors),
            BlobStore::FoundationDb(inner) => inner.validate(errors),
            BlobStore::PostgreSql(inner) => inner.validate(errors),
            BlobStore::MySql(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for BlobStore {
    fn default() -> Self {
        BlobStore::Default
    }
}

impl Pickle for BlobStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            BlobStore::Default => {
                0u16.pickle(out);
            }
            BlobStore::Sharded(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::S3(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::Azure(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::FileSystem(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::FoundationDb(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::PostgreSql(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            BlobStore::MySql(inner) => {
                7u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(BlobStore::Default),
            1 => Pickle::unpickle(stream).map(BlobStore::Sharded),
            2 => Pickle::unpickle(stream).map(BlobStore::S3),
            3 => Pickle::unpickle(stream).map(BlobStore::Azure),
            4 => Pickle::unpickle(stream).map(BlobStore::FileSystem),
            5 => Pickle::unpickle(stream).map(BlobStore::FoundationDb),
            6 => Pickle::unpickle(stream).map(BlobStore::PostgreSql),
            7 => Pickle::unpickle(stream).map(BlobStore::MySql),
            _ => None,
        }
    }
}

impl IntoValue for BlobStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            BlobStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            BlobStore::Sharded(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sharded".into()));
                obj
            }
            BlobStore::S3(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("S3".into()));
                obj
            }
            BlobStore::Azure(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Azure".into()));
                obj
            }
            BlobStore::FileSystem(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FileSystem".into()));
                obj
            }
            BlobStore::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            BlobStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            BlobStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for BlobStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                BlobStoreType::Default => *self = BlobStore::Default,
                BlobStoreType::Sharded => *self = BlobStore::Sharded(Default::default()),
                BlobStoreType::S3 => *self = BlobStore::S3(Default::default()),
                BlobStoreType::Azure => *self = BlobStore::Azure(Default::default()),
                BlobStoreType::FileSystem => *self = BlobStore::FileSystem(Default::default()),
                BlobStoreType::FoundationDb => *self = BlobStore::FoundationDb(Default::default()),
                BlobStoreType::PostgreSql => *self = BlobStore::PostgreSql(Default::default()),
                BlobStoreType::MySql => *self = BlobStore::MySql(Default::default()),
            }
        }
        match self {
            BlobStore::Default => pointer.assert_eof(),
            BlobStore::Sharded(inner) => inner.patch(pointer, value),
            BlobStore::S3(inner) => inner.patch(pointer, value),
            BlobStore::Azure(inner) => inner.patch(pointer, value),
            BlobStore::FileSystem(inner) => inner.patch(pointer, value),
            BlobStore::FoundationDb(inner) => inner.patch(pointer, value),
            BlobStore::PostgreSql(inner) => inner.patch(pointer, value),
            BlobStore::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl BlobStore {
    pub fn object_type(&self) -> BlobStoreType {
        match self {
            BlobStore::Default => BlobStoreType::Default,
            BlobStore::Sharded(_) => BlobStoreType::Sharded,
            BlobStore::S3(_) => BlobStoreType::S3,
            BlobStore::Azure(_) => BlobStoreType::Azure,
            BlobStore::FileSystem(_) => BlobStoreType::FileSystem,
            BlobStore::FoundationDb(_) => BlobStoreType::FoundationDb,
            BlobStore::PostgreSql(_) => BlobStoreType::PostgreSql,
            BlobStore::MySql(_) => BlobStoreType::MySql,
        }
    }
}

impl BlobStoreBase {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            BlobStoreBase::S3(inner) => inner.validate(errors),
            BlobStoreBase::Azure(inner) => inner.validate(errors),
            BlobStoreBase::FileSystem(inner) => inner.validate(errors),
            BlobStoreBase::FoundationDb(inner) => inner.validate(errors),
            BlobStoreBase::PostgreSql(inner) => inner.validate(errors),
            BlobStoreBase::MySql(inner) => inner.validate(errors),
        }
    }
}

impl Default for BlobStoreBase {
    fn default() -> Self {
        BlobStoreBase::S3(Default::default())
    }
}

impl Pickle for BlobStoreBase {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            BlobStoreBase::S3(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            BlobStoreBase::Azure(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            BlobStoreBase::FileSystem(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            BlobStoreBase::FoundationDb(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            BlobStoreBase::PostgreSql(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            BlobStoreBase::MySql(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(BlobStoreBase::S3),
            1 => Pickle::unpickle(stream).map(BlobStoreBase::Azure),
            2 => Pickle::unpickle(stream).map(BlobStoreBase::FileSystem),
            3 => Pickle::unpickle(stream).map(BlobStoreBase::FoundationDb),
            4 => Pickle::unpickle(stream).map(BlobStoreBase::PostgreSql),
            5 => Pickle::unpickle(stream).map(BlobStoreBase::MySql),
            _ => None,
        }
    }
}

impl IntoValue for BlobStoreBase {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            BlobStoreBase::S3(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("S3".into()));
                obj
            }
            BlobStoreBase::Azure(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Azure".into()));
                obj
            }
            BlobStoreBase::FileSystem(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FileSystem".into()));
                obj
            }
            BlobStoreBase::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            BlobStoreBase::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            BlobStoreBase::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for BlobStoreBase {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                BlobStoreBaseType::S3 => *self = BlobStoreBase::S3(Default::default()),
                BlobStoreBaseType::Azure => *self = BlobStoreBase::Azure(Default::default()),
                BlobStoreBaseType::FileSystem => {
                    *self = BlobStoreBase::FileSystem(Default::default())
                }
                BlobStoreBaseType::FoundationDb => {
                    *self = BlobStoreBase::FoundationDb(Default::default())
                }
                BlobStoreBaseType::PostgreSql => {
                    *self = BlobStoreBase::PostgreSql(Default::default())
                }
                BlobStoreBaseType::MySql => *self = BlobStoreBase::MySql(Default::default()),
            }
        }
        match self {
            BlobStoreBase::S3(inner) => inner.patch(pointer, value),
            BlobStoreBase::Azure(inner) => inner.patch(pointer, value),
            BlobStoreBase::FileSystem(inner) => inner.patch(pointer, value),
            BlobStoreBase::FoundationDb(inner) => inner.patch(pointer, value),
            BlobStoreBase::PostgreSql(inner) => inner.patch(pointer, value),
            BlobStoreBase::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl BlobStoreBase {
    pub fn object_type(&self) -> BlobStoreBaseType {
        match self {
            BlobStoreBase::S3(_) => BlobStoreBaseType::S3,
            BlobStoreBase::Azure(_) => BlobStoreBaseType::Azure,
            BlobStoreBase::FileSystem(_) => BlobStoreBaseType::FileSystem,
            BlobStoreBase::FoundationDb(_) => BlobStoreBaseType::FoundationDb,
            BlobStoreBase::PostgreSql(_) => BlobStoreBaseType::PostgreSql,
            BlobStoreBase::MySql(_) => BlobStoreBaseType::MySql,
        }
    }
}

impl ObjectImpl for BlockedIp {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::BlockedIp;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.address;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Address, value));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Address, &self.address);
    }
}

impl Pickle for BlockedIp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.address.pickle(out);
        self.reason.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.address = Pickle::unpickle(stream)?;
        this.reason = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for BlockedIp {
    fn default() -> Self {
        Self {
            address: Default::default(),
            reason: BlockReason::Manual,
            created_at: Default::default(),
            expires_at: Default::default(),
        }
    }
}

impl IntoValue for BlockedIp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Address, self.address.into_value());
        map.insert_unchecked(Property::Reason, self.reason.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for BlockedIp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Address) => self.address.patch(pointer.assert_read_only()?, value),
            Some(Property::Reason) => self.reason.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Bootstrap {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Bootstrap;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.server_hostname;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ServerHostname));
        }
        let value = &self.default_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultDomain));
        }
        let value = &self.data_store;
        value.validate(errors);
        let value = &self.blob_store;
        value.validate(errors);
        let value = &self.search_store;
        value.validate(errors);
        let value = &self.in_memory_store;
        value.validate(errors);
        let value = &self.directory;
        value.validate(errors);
        let value = &self.tracer;
        value.validate(errors);
        let value = &self.dns_server;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Bootstrap {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.server_hostname.pickle(out);
        self.default_domain.pickle(out);
        self.request_tls_certificate.pickle(out);
        self.generate_dkim_keys.pickle(out);
        self.data_store.pickle(out);
        self.blob_store.pickle(out);
        self.search_store.pickle(out);
        self.in_memory_store.pickle(out);
        self.directory.pickle(out);
        self.tracer.pickle(out);
        self.dns_server.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.server_hostname = Pickle::unpickle(stream)?;
        this.default_domain = Pickle::unpickle(stream)?;
        this.request_tls_certificate = Pickle::unpickle(stream)?;
        this.generate_dkim_keys = Pickle::unpickle(stream)?;
        this.data_store = Pickle::unpickle(stream)?;
        this.blob_store = Pickle::unpickle(stream)?;
        this.search_store = Pickle::unpickle(stream)?;
        this.in_memory_store = Pickle::unpickle(stream)?;
        this.directory = Pickle::unpickle(stream)?;
        this.tracer = Pickle::unpickle(stream)?;
        this.dns_server = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Bootstrap {
    fn default() -> Self {
        Self {
            server_hostname: Default::default(),
            default_domain: Default::default(),
            request_tls_certificate: true,
            generate_dkim_keys: true,
            data_store: DataStore::RocksDb(RocksDbStore {
                path: "/var/lib/stalwart/".to_string(),
                ..Default::default()
            }),
            blob_store: BlobStore::Default,
            search_store: SearchStore::Default,
            in_memory_store: InMemoryStore::Default,
            directory: DirectoryBootstrap::Internal,
            tracer: Tracer::Log(TracerLog {
                path: "/var/log/stalwart/".to_string(),
                ..Default::default()
            }),
            dns_server: DnsServerBootstrap::Manual,
        }
    }
}

impl IntoValue for Bootstrap {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::ServerHostname, self.server_hostname.into_value());
        map.insert_unchecked(Property::DefaultDomain, self.default_domain.into_value());
        map.insert_unchecked(
            Property::RequestTlsCertificate,
            self.request_tls_certificate.into_value(),
        );
        map.insert_unchecked(
            Property::GenerateDkimKeys,
            self.generate_dkim_keys.into_value(),
        );
        map.insert_unchecked(Property::DataStore, self.data_store.into_value());
        map.insert_unchecked(Property::BlobStore, self.blob_store.into_value());
        map.insert_unchecked(Property::SearchStore, self.search_store.into_value());
        map.insert_unchecked(Property::InMemoryStore, self.in_memory_store.into_value());
        map.insert_unchecked(Property::Directory, self.directory.into_value());
        map.insert_unchecked(Property::Tracer, self.tracer.into_value());
        map.insert_unchecked(Property::DnsServer, self.dns_server.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Bootstrap {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ServerHostname) => self.server_hostname.patch(pointer, value),
            Some(Property::DefaultDomain) => self.default_domain.patch(pointer, value),
            Some(Property::RequestTlsCertificate) => {
                self.request_tls_certificate.patch(pointer, value)
            }
            Some(Property::GenerateDkimKeys) => self.generate_dkim_keys.patch(pointer, value),
            Some(Property::DataStore) => self.data_store.patch(pointer, value),
            Some(Property::BlobStore) => self.blob_store.patch(pointer, value),
            Some(Property::SearchStore) => self.search_store.patch(pointer, value),
            Some(Property::InMemoryStore) => self.in_memory_store.patch(pointer, value),
            Some(Property::Directory) => self.directory.patch(pointer, value),
            Some(Property::Tracer) => self.tracer.patch(pointer, value),
            Some(Property::DnsServer) => self.dns_server.patch(pointer, value),
            Some(Property::Username) => pointer.assert_server_set(),
            Some(Property::Secret) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Cache {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Cache;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_tokens;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::AccessTokens, 2048));
        }
        let value = &self.contacts;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Contacts, 2048));
        }
        let value = &self.dns_ipv4;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsIpv4, 2048));
        }
        let value = &self.dns_ipv6;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsIpv6, 2048));
        }
        let value = &self.dns_mta_sts;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsMtaSts, 2048));
        }
        let value = &self.dns_mx;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsMx, 2048));
        }
        let value = &self.dns_ptr;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsPtr, 2048));
        }
        let value = &self.dns_rbl;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsRbl, 2048));
        }
        let value = &self.dns_tlsa;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsTlsa, 2048));
        }
        let value = &self.dns_txt;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DnsTxt, 2048));
        }
        let value = &self.events;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Events, 2048));
        }
        let value = &self.scheduling;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Scheduling, 2048));
        }
        let value = &self.files;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Files, 2048));
        }
        let value = &self.http_auth;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::HttpAuth, 2048));
        }
        let value = &self.messages;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Messages, 2048));
        }
        let value = &self.domains;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Domains, 2048));
        }
        let value = &self.domain_names;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DomainNames, 2048));
        }
        let value = &self.domain_names_negative;
        if *value < 2048 {
            errors.push(ValidationError::min_value(
                Property::DomainNamesNegative,
                2048,
            ));
        }
        let value = &self.email_addresses;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::EmailAddresses, 2048));
        }
        let value = &self.email_addresses_negative;
        if *value < 2048 {
            errors.push(ValidationError::min_value(
                Property::EmailAddressesNegative,
                2048,
            ));
        }
        let value = &self.accounts;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Accounts, 2048));
        }
        let value = &self.roles;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Roles, 2048));
        }
        let value = &self.tenants;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::Tenants, 2048));
        }
        let value = &self.mailing_lists;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::MailingLists, 2048));
        }
        let value = &self.dkim_signatures;
        if *value < 2048 {
            errors.push(ValidationError::min_value(Property::DkimSignatures, 2048));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Cache {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_tokens.pickle(out);
        self.contacts.pickle(out);
        self.dns_ipv4.pickle(out);
        self.dns_ipv6.pickle(out);
        self.dns_mta_sts.pickle(out);
        self.dns_mx.pickle(out);
        self.dns_ptr.pickle(out);
        self.dns_rbl.pickle(out);
        self.dns_tlsa.pickle(out);
        self.dns_txt.pickle(out);
        self.events.pickle(out);
        self.scheduling.pickle(out);
        self.files.pickle(out);
        self.http_auth.pickle(out);
        self.messages.pickle(out);
        self.domains.pickle(out);
        self.domain_names.pickle(out);
        self.domain_names_negative.pickle(out);
        self.email_addresses.pickle(out);
        self.email_addresses_negative.pickle(out);
        self.accounts.pickle(out);
        self.roles.pickle(out);
        self.tenants.pickle(out);
        self.mailing_lists.pickle(out);
        self.dkim_signatures.pickle(out);
        self.negative_ttl.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_tokens = Pickle::unpickle(stream)?;
        this.contacts = Pickle::unpickle(stream)?;
        this.dns_ipv4 = Pickle::unpickle(stream)?;
        this.dns_ipv6 = Pickle::unpickle(stream)?;
        this.dns_mta_sts = Pickle::unpickle(stream)?;
        this.dns_mx = Pickle::unpickle(stream)?;
        this.dns_ptr = Pickle::unpickle(stream)?;
        this.dns_rbl = Pickle::unpickle(stream)?;
        this.dns_tlsa = Pickle::unpickle(stream)?;
        this.dns_txt = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.scheduling = Pickle::unpickle(stream)?;
        this.files = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.messages = Pickle::unpickle(stream)?;
        this.domains = Pickle::unpickle(stream)?;
        this.domain_names = Pickle::unpickle(stream)?;
        this.domain_names_negative = Pickle::unpickle(stream)?;
        this.email_addresses = Pickle::unpickle(stream)?;
        this.email_addresses_negative = Pickle::unpickle(stream)?;
        this.accounts = Pickle::unpickle(stream)?;
        this.roles = Pickle::unpickle(stream)?;
        this.tenants = Pickle::unpickle(stream)?;
        this.mailing_lists = Pickle::unpickle(stream)?;
        this.dkim_signatures = Pickle::unpickle(stream)?;
        this.negative_ttl = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Cache {
    fn default() -> Self {
        Self {
            access_tokens: 10485760,
            contacts: 10485760,
            dns_ipv4: 5242880,
            dns_ipv6: 5242880,
            dns_mta_sts: 1048576,
            dns_mx: 5242880,
            dns_ptr: 1048576,
            dns_rbl: 5242880,
            dns_tlsa: 1048576,
            dns_txt: 5242880,
            events: 10485760,
            scheduling: 1048576,
            files: 10485760,
            http_auth: 1048576,
            messages: 52428800,
            domains: 5242880,
            domain_names: 10485760,
            domain_names_negative: 1048576,
            email_addresses: 10485760,
            email_addresses_negative: 2097152,
            accounts: 20971520,
            roles: 5242880,
            tenants: 5242880,
            mailing_lists: 2097152,
            dkim_signatures: 10485760,
            negative_ttl: Duration::from_millis(3600000),
        }
    }
}

impl IntoValue for Cache {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(28);
        map.insert_unchecked(Property::AccessTokens, self.access_tokens.into_value());
        map.insert_unchecked(Property::Contacts, self.contacts.into_value());
        map.insert_unchecked(Property::DnsIpv4, self.dns_ipv4.into_value());
        map.insert_unchecked(Property::DnsIpv6, self.dns_ipv6.into_value());
        map.insert_unchecked(Property::DnsMtaSts, self.dns_mta_sts.into_value());
        map.insert_unchecked(Property::DnsMx, self.dns_mx.into_value());
        map.insert_unchecked(Property::DnsPtr, self.dns_ptr.into_value());
        map.insert_unchecked(Property::DnsRbl, self.dns_rbl.into_value());
        map.insert_unchecked(Property::DnsTlsa, self.dns_tlsa.into_value());
        map.insert_unchecked(Property::DnsTxt, self.dns_txt.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::Scheduling, self.scheduling.into_value());
        map.insert_unchecked(Property::Files, self.files.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::Messages, self.messages.into_value());
        map.insert_unchecked(Property::Domains, self.domains.into_value());
        map.insert_unchecked(Property::DomainNames, self.domain_names.into_value());
        map.insert_unchecked(
            Property::DomainNamesNegative,
            self.domain_names_negative.into_value(),
        );
        map.insert_unchecked(Property::EmailAddresses, self.email_addresses.into_value());
        map.insert_unchecked(
            Property::EmailAddressesNegative,
            self.email_addresses_negative.into_value(),
        );
        map.insert_unchecked(Property::Accounts, self.accounts.into_value());
        map.insert_unchecked(Property::Roles, self.roles.into_value());
        map.insert_unchecked(Property::Tenants, self.tenants.into_value());
        map.insert_unchecked(Property::MailingLists, self.mailing_lists.into_value());
        map.insert_unchecked(Property::DkimSignatures, self.dkim_signatures.into_value());
        map.insert_unchecked(Property::NegativeTtl, self.negative_ttl.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Cache {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessTokens) => self.access_tokens.patch(pointer, value),
            Some(Property::Contacts) => self.contacts.patch(pointer, value),
            Some(Property::DnsIpv4) => self.dns_ipv4.patch(pointer, value),
            Some(Property::DnsIpv6) => self.dns_ipv6.patch(pointer, value),
            Some(Property::DnsMtaSts) => self.dns_mta_sts.patch(pointer, value),
            Some(Property::DnsMx) => self.dns_mx.patch(pointer, value),
            Some(Property::DnsPtr) => self.dns_ptr.patch(pointer, value),
            Some(Property::DnsRbl) => self.dns_rbl.patch(pointer, value),
            Some(Property::DnsTlsa) => self.dns_tlsa.patch(pointer, value),
            Some(Property::DnsTxt) => self.dns_txt.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::Scheduling) => self.scheduling.patch(pointer, value),
            Some(Property::Files) => self.files.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::Messages) => self.messages.patch(pointer, value),
            Some(Property::Domains) => self.domains.patch(pointer, value),
            Some(Property::DomainNames) => self.domain_names.patch(pointer, value),
            Some(Property::DomainNamesNegative) => self.domain_names_negative.patch(pointer, value),
            Some(Property::EmailAddresses) => self.email_addresses.patch(pointer, value),
            Some(Property::EmailAddressesNegative) => {
                self.email_addresses_negative.patch(pointer, value)
            }
            Some(Property::Accounts) => self.accounts.patch(pointer, value),
            Some(Property::Roles) => self.roles.patch(pointer, value),
            Some(Property::Tenants) => self.tenants.patch(pointer, value),
            Some(Property::MailingLists) => self.mailing_lists.patch(pointer, value),
            Some(Property::DkimSignatures) => self.dkim_signatures.patch(pointer, value),
            Some(Property::NegativeTtl) => self.negative_ttl.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Calendar {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Calendar;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.default_display_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DefaultDisplayName));
            }
        }
        if let Some(value) = &self.default_href_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DefaultHrefName));
            }
        }
        let value = &self.max_attendees;
        if *value > 100000 {
            errors.push(ValidationError::max_value(Property::MaxAttendees, 100000));
        }
        if let Some(value) = &self.max_calendars {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxCalendars, 1));
            }
        }
        if let Some(value) = &self.max_events {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxEvents, 1));
            }
        }
        if let Some(value) = &self.max_participant_identities {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::MaxParticipantIdentities,
                    1,
                ));
            }
        }
        if let Some(value) = &self.max_event_notifications {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::MaxEventNotifications,
                    1,
                ));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Calendar {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.default_display_name.pickle(out);
        self.default_href_name.pickle(out);
        self.max_attendees.pickle(out);
        self.max_recurrence_expansions.pickle(out);
        self.max_i_calendar_size.pickle(out);
        self.max_calendars.pickle(out);
        self.max_events.pickle(out);
        self.max_participant_identities.pickle(out);
        self.max_event_notifications.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.default_display_name = Pickle::unpickle(stream)?;
        this.default_href_name = Pickle::unpickle(stream)?;
        this.max_attendees = Pickle::unpickle(stream)?;
        this.max_recurrence_expansions = Pickle::unpickle(stream)?;
        this.max_i_calendar_size = Pickle::unpickle(stream)?;
        this.max_calendars = Pickle::unpickle(stream)?;
        this.max_events = Pickle::unpickle(stream)?;
        this.max_participant_identities = Pickle::unpickle(stream)?;
        this.max_event_notifications = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Calendar {
    fn default() -> Self {
        Self {
            default_display_name: Some("Stalwart Calendar".to_string()),
            default_href_name: Some("default".to_string()),
            max_attendees: 20u64,
            max_recurrence_expansions: 3000u64,
            max_i_calendar_size: 524288,
            max_calendars: Some(250u64),
            max_events: Default::default(),
            max_participant_identities: Some(100u64),
            max_event_notifications: Default::default(),
        }
    }
}

impl IntoValue for Calendar {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(
            Property::DefaultDisplayName,
            self.default_display_name.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultHrefName,
            self.default_href_name.into_value(),
        );
        map.insert_unchecked(Property::MaxAttendees, self.max_attendees.into_value());
        map.insert_unchecked(
            Property::MaxRecurrenceExpansions,
            self.max_recurrence_expansions.into_value(),
        );
        map.insert_unchecked(
            Property::MaxICalendarSize,
            self.max_i_calendar_size.into_value(),
        );
        map.insert_unchecked(Property::MaxCalendars, self.max_calendars.into_value());
        map.insert_unchecked(Property::MaxEvents, self.max_events.into_value());
        map.insert_unchecked(
            Property::MaxParticipantIdentities,
            self.max_participant_identities.into_value(),
        );
        map.insert_unchecked(
            Property::MaxEventNotifications,
            self.max_event_notifications.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Calendar {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DefaultDisplayName) => self
                .default_display_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DefaultHrefName) => self
                .default_href_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MaxAttendees) => self.max_attendees.patch(pointer, value),
            Some(Property::MaxRecurrenceExpansions) => {
                self.max_recurrence_expansions.patch(pointer, value)
            }
            Some(Property::MaxICalendarSize) => self.max_i_calendar_size.patch(pointer, value),
            Some(Property::MaxCalendars) => self.max_calendars.patch(pointer, value),
            Some(Property::MaxEvents) => self.max_events.patch(pointer, value),
            Some(Property::MaxParticipantIdentities) => {
                self.max_participant_identities.patch(pointer, value)
            }
            Some(Property::MaxEventNotifications) => {
                self.max_event_notifications.patch(pointer, value)
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for CalendarAlarm {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::CalendarAlarm;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.from_email {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FromEmail));
            }
        }
        let value = &self.from_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FromName));
        }
        if let Some(value) = &self.template {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Template));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for CalendarAlarm {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_external_rcpts.pickle(out);
        self.enable.pickle(out);
        self.from_email.pickle(out);
        self.from_name.pickle(out);
        self.min_trigger_interval.pickle(out);
        self.template.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_external_rcpts = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.from_email = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.min_trigger_interval = Pickle::unpickle(stream)?;
        this.template = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CalendarAlarm {
    fn default() -> Self {
        Self {
            allow_external_rcpts: false,
            enable: true,
            from_email: Default::default(),
            from_name: "Stalwart Calendar".to_string(),
            min_trigger_interval: Duration::from_millis(3600000),
            template: Default::default(),
        }
    }
}

impl IntoValue for CalendarAlarm {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(
            Property::AllowExternalRcpts,
            self.allow_external_rcpts.into_value(),
        );
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::FromEmail, self.from_email.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(
            Property::MinTriggerInterval,
            self.min_trigger_interval.into_value(),
        );
        map.insert_unchecked(Property::Template, self.template.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CalendarAlarm {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowExternalRcpts) => self.allow_external_rcpts.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::FromEmail) => self
                .from_email
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::FromName) => self
                .from_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MinTriggerInterval) => self.min_trigger_interval.patch(pointer, value),
            Some(Property::Template) => self.template.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for CalendarScheduling {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::CalendarScheduling;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.http_rsvp_url {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpRsvpUrl));
            }
        }
        let value = &self.itip_max_size;
        if *value < 100 {
            errors.push(ValidationError::min_value(Property::ItipMaxSize, 100));
        }
        let value = &self.max_recipients;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxRecipients, 1));
        }
        if let Some(value) = &self.email_template {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EmailTemplate));
            }
        }
        if let Some(value) = &self.http_rsvp_template {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpRsvpTemplate));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for CalendarScheduling {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable.pickle(out);
        self.http_rsvp_enable.pickle(out);
        self.http_rsvp_link_expiry.pickle(out);
        self.http_rsvp_url.pickle(out);
        self.auto_add_invitations.pickle(out);
        self.itip_max_size.pickle(out);
        self.max_recipients.pickle(out);
        self.email_template.pickle(out);
        self.http_rsvp_template.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable = Pickle::unpickle(stream)?;
        this.http_rsvp_enable = Pickle::unpickle(stream)?;
        this.http_rsvp_link_expiry = Pickle::unpickle(stream)?;
        this.http_rsvp_url = Pickle::unpickle(stream)?;
        this.auto_add_invitations = Pickle::unpickle(stream)?;
        this.itip_max_size = Pickle::unpickle(stream)?;
        this.max_recipients = Pickle::unpickle(stream)?;
        this.email_template = Pickle::unpickle(stream)?;
        this.http_rsvp_template = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CalendarScheduling {
    fn default() -> Self {
        Self {
            enable: true,
            http_rsvp_enable: true,
            http_rsvp_link_expiry: Duration::from_millis(7776000000),
            http_rsvp_url: Default::default(),
            auto_add_invitations: false,
            itip_max_size: 524288,
            max_recipients: 100u64,
            email_template: Default::default(),
            http_rsvp_template: Default::default(),
        }
    }
}

impl IntoValue for CalendarScheduling {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::HttpRsvpEnable, self.http_rsvp_enable.into_value());
        map.insert_unchecked(
            Property::HttpRsvpLinkExpiry,
            self.http_rsvp_link_expiry.into_value(),
        );
        map.insert_unchecked(Property::HttpRsvpUrl, self.http_rsvp_url.into_value());
        map.insert_unchecked(
            Property::AutoAddInvitations,
            self.auto_add_invitations.into_value(),
        );
        map.insert_unchecked(Property::ItipMaxSize, self.itip_max_size.into_value());
        map.insert_unchecked(Property::MaxRecipients, self.max_recipients.into_value());
        map.insert_unchecked(Property::EmailTemplate, self.email_template.into_value());
        map.insert_unchecked(
            Property::HttpRsvpTemplate,
            self.http_rsvp_template.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CalendarScheduling {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::HttpRsvpEnable) => self.http_rsvp_enable.patch(pointer, value),
            Some(Property::HttpRsvpLinkExpiry) => self.http_rsvp_link_expiry.patch(pointer, value),
            Some(Property::HttpRsvpUrl) => self
                .http_rsvp_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AutoAddInvitations) => self.auto_add_invitations.patch(pointer, value),
            Some(Property::ItipMaxSize) => self.itip_max_size.patch(pointer, value),
            Some(Property::MaxRecipients) => self.max_recipients.patch(pointer, value),
            Some(Property::EmailTemplate) => self.email_template.patch(pointer, value),
            Some(Property::HttpRsvpTemplate) => self.http_rsvp_template.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Certificate {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Certificate;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.certificate;
        value.validate(errors);
        let value = &self.private_key;
        value.validate(errors);
        let value = &self.subject_alternative_names;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::SubjectAlternativeNames));
            }
        }
        let value = &self.not_valid_after;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::NotValidAfter, value));
        }
        let value = &self.not_valid_before;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::NotValidBefore, value));
        }
        let value = &self.issuer;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Issuer));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        for value in self.subject_alternative_names.iter() {
            i.text(Property::SubjectAlternativeNames, value);
        }
    }
}

impl Pickle for Certificate {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.certificate.pickle(out);
        self.private_key.pickle(out);
        self.subject_alternative_names.pickle(out);
        self.not_valid_after.pickle(out);
        self.not_valid_before.pickle(out);
        self.issuer.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.certificate = Pickle::unpickle(stream)?;
        this.private_key = Pickle::unpickle(stream)?;
        this.subject_alternative_names = Pickle::unpickle(stream)?;
        this.not_valid_after = Pickle::unpickle(stream)?;
        this.not_valid_before = Pickle::unpickle(stream)?;
        this.issuer = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Certificate {
    fn default() -> Self {
        Self {
            certificate: Default::default(),
            private_key: Default::default(),
            subject_alternative_names: Default::default(),
            not_valid_after: Default::default(),
            not_valid_before: Default::default(),
            issuer: Default::default(),
        }
    }
}

impl IntoValue for Certificate {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Certificate, self.certificate.into_value());
        map.insert_unchecked(Property::PrivateKey, self.private_key.into_value());
        map.insert_unchecked(
            Property::SubjectAlternativeNames,
            self.subject_alternative_names.into_value(),
        );
        map.insert_unchecked(Property::NotValidAfter, self.not_valid_after.into_value());
        map.insert_unchecked(Property::NotValidBefore, self.not_valid_before.into_value());
        map.insert_unchecked(Property::Issuer, self.issuer.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Certificate {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Certificate) => self.certificate.patch(pointer, value),
            Some(Property::PrivateKey) => self.private_key.patch(pointer, value),
            Some(Property::SubjectAlternativeNames) => pointer.assert_server_set(),
            Some(Property::NotValidAfter) => pointer.assert_server_set(),
            Some(Property::NotValidBefore) => pointer.assert_server_set(),
            Some(Property::Issuer) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl CertificateManagement {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            CertificateManagement::Manual => true,
            CertificateManagement::Automatic(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            CertificateManagement::Manual => {}
            CertificateManagement::Automatic(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for CertificateManagement {
    fn default() -> Self {
        CertificateManagement::Manual
    }
}

impl Pickle for CertificateManagement {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            CertificateManagement::Manual => {
                0u16.pickle(out);
            }
            CertificateManagement::Automatic(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(CertificateManagement::Manual),
            1 => Pickle::unpickle(stream).map(CertificateManagement::Automatic),
            _ => None,
        }
    }
}

impl IntoValue for CertificateManagement {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            CertificateManagement::Manual => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Manual".into()));
                JmapValue::Object(obj)
            }
            CertificateManagement::Automatic(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Automatic".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for CertificateManagement {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                CertificateManagementType::Manual => *self = CertificateManagement::Manual,
                CertificateManagementType::Automatic => {
                    *self = CertificateManagement::Automatic(Default::default())
                }
            }
        }
        match self {
            CertificateManagement::Manual => pointer.assert_eof(),
            CertificateManagement::Automatic(inner) => inner.patch(pointer, value),
        }
    }
}

impl CertificateManagement {
    pub fn object_type(&self) -> CertificateManagementType {
        match self {
            CertificateManagement::Manual => CertificateManagementType::Manual,
            CertificateManagement::Automatic(_) => CertificateManagementType::Automatic,
        }
    }
}

impl CertificateManagementProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.acme_provider_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AcmeProviderId));
        }
        let value = &self.subject_alternative_names;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::SubjectAlternativeNames));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::AcmeProvider, self.acme_provider_id.into(), None);
    }
}

impl Pickle for CertificateManagementProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.acme_provider_id.pickle(out);
        self.subject_alternative_names.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.acme_provider_id = Pickle::unpickle(stream)?;
        this.subject_alternative_names = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CertificateManagementProperties {
    fn default() -> Self {
        Self {
            acme_provider_id: Default::default(),
            subject_alternative_names: Default::default(),
        }
    }
}

impl IntoValue for CertificateManagementProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::AcmeProviderId, self.acme_provider_id.into_value());
        map.insert_unchecked(
            Property::SubjectAlternativeNames,
            self.subject_alternative_names.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CertificateManagementProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AcmeProviderId) => self.acme_provider_id.patch(pointer, value),
            Some(Property::SubjectAlternativeNames) => self
                .subject_alternative_names
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ClusterListenerGroup {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            ClusterListenerGroup::EnableAll => true,
            ClusterListenerGroup::DisableAll => true,
            ClusterListenerGroup::EnableSome(inner) => inner.validate(errors),
            ClusterListenerGroup::DisableSome(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            ClusterListenerGroup::EnableAll => {}
            ClusterListenerGroup::DisableAll => {}
            ClusterListenerGroup::EnableSome(object) => {
                object.index(i);
            }
            ClusterListenerGroup::DisableSome(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for ClusterListenerGroup {
    fn default() -> Self {
        ClusterListenerGroup::EnableAll
    }
}

impl Pickle for ClusterListenerGroup {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            ClusterListenerGroup::EnableAll => {
                0u16.pickle(out);
            }
            ClusterListenerGroup::DisableAll => {
                1u16.pickle(out);
            }
            ClusterListenerGroup::EnableSome(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            ClusterListenerGroup::DisableSome(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(ClusterListenerGroup::EnableAll),
            1 => Some(ClusterListenerGroup::DisableAll),
            2 => Pickle::unpickle(stream).map(ClusterListenerGroup::EnableSome),
            3 => Pickle::unpickle(stream).map(ClusterListenerGroup::DisableSome),
            _ => None,
        }
    }
}

impl IntoValue for ClusterListenerGroup {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            ClusterListenerGroup::EnableAll => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EnableAll".into()));
                JmapValue::Object(obj)
            }
            ClusterListenerGroup::DisableAll => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DisableAll".into()));
                JmapValue::Object(obj)
            }
            ClusterListenerGroup::EnableSome(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnableSome".into()));
                obj
            }
            ClusterListenerGroup::DisableSome(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DisableSome".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for ClusterListenerGroup {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                ClusterListenerGroupType::EnableAll => *self = ClusterListenerGroup::EnableAll,
                ClusterListenerGroupType::DisableAll => *self = ClusterListenerGroup::DisableAll,
                ClusterListenerGroupType::EnableSome => {
                    *self = ClusterListenerGroup::EnableSome(Default::default())
                }
                ClusterListenerGroupType::DisableSome => {
                    *self = ClusterListenerGroup::DisableSome(Default::default())
                }
            }
        }
        match self {
            ClusterListenerGroup::EnableAll => pointer.assert_eof(),
            ClusterListenerGroup::DisableAll => pointer.assert_eof(),
            ClusterListenerGroup::EnableSome(inner) => inner.patch(pointer, value),
            ClusterListenerGroup::DisableSome(inner) => inner.patch(pointer, value),
        }
    }
}

impl ClusterListenerGroup {
    pub fn object_type(&self) -> ClusterListenerGroupType {
        match self {
            ClusterListenerGroup::EnableAll => ClusterListenerGroupType::EnableAll,
            ClusterListenerGroup::DisableAll => ClusterListenerGroupType::DisableAll,
            ClusterListenerGroup::EnableSome(_) => ClusterListenerGroupType::EnableSome,
            ClusterListenerGroup::DisableSome(_) => ClusterListenerGroupType::DisableSome,
        }
    }
}

impl ClusterListenerGroupProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.listener_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::ListenerIds));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        for id in self.listener_ids.iter() {
            i.foreign_key(ObjectType::NetworkListener, Some(*id), None);
        }
    }
}

impl Pickle for ClusterListenerGroupProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.listener_ids.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.listener_ids = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ClusterListenerGroupProperties {
    fn default() -> Self {
        Self {
            listener_ids: Default::default(),
        }
    }
}

impl IntoValue for ClusterListenerGroupProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::ListenerIds, self.listener_ids.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ClusterListenerGroupProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ListenerIds) => self.listener_ids.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ClusterNode {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ClusterNode;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.hostname;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Hostname));
        }
        let value = &self.last_renewal;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::LastRenewal, value));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for ClusterNode {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.node_id.pickle(out);
        self.hostname.pickle(out);
        self.last_renewal.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.node_id = Pickle::unpickle(stream)?;
        this.hostname = Pickle::unpickle(stream)?;
        this.last_renewal = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ClusterNode {
    fn default() -> Self {
        Self {
            node_id: 1u64,
            hostname: Default::default(),
            last_renewal: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for ClusterNode {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::NodeId, self.node_id.into_value());
        map.insert_unchecked(Property::Hostname, self.hostname.into_value());
        map.insert_unchecked(Property::LastRenewal, self.last_renewal.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ClusterNode {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::NodeId) => self.node_id.patch(pointer, value),
            Some(Property::Hostname) => self.hostname.patch(pointer, value),
            Some(Property::LastRenewal) => self.last_renewal.patch(pointer, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ClusterRole {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ClusterRole;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.tasks;
        value.validate(errors);
        let value = &self.listeners;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
        self.listeners.index(i);
    }
}

impl Pickle for ClusterRole {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.tasks.pickle(out);
        self.listeners.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.tasks = Pickle::unpickle(stream)?;
        this.listeners = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ClusterRole {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            tasks: Default::default(),
            listeners: Default::default(),
        }
    }
}

impl IntoValue for ClusterRole {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Tasks, self.tasks.into_value());
        map.insert_unchecked(Property::Listeners, self.listeners.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ClusterRole {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Tasks) => self.tasks.patch(pointer, value),
            Some(Property::Listeners) => self.listeners.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ClusterTaskGroup {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            ClusterTaskGroup::EnableAll => true,
            ClusterTaskGroup::DisableAll => true,
            ClusterTaskGroup::EnableSome(inner) => inner.validate(errors),
            ClusterTaskGroup::DisableSome(inner) => inner.validate(errors),
        }
    }
}

impl Default for ClusterTaskGroup {
    fn default() -> Self {
        ClusterTaskGroup::EnableAll
    }
}

impl Pickle for ClusterTaskGroup {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            ClusterTaskGroup::EnableAll => {
                0u16.pickle(out);
            }
            ClusterTaskGroup::DisableAll => {
                1u16.pickle(out);
            }
            ClusterTaskGroup::EnableSome(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            ClusterTaskGroup::DisableSome(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(ClusterTaskGroup::EnableAll),
            1 => Some(ClusterTaskGroup::DisableAll),
            2 => Pickle::unpickle(stream).map(ClusterTaskGroup::EnableSome),
            3 => Pickle::unpickle(stream).map(ClusterTaskGroup::DisableSome),
            _ => None,
        }
    }
}

impl IntoValue for ClusterTaskGroup {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            ClusterTaskGroup::EnableAll => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EnableAll".into()));
                JmapValue::Object(obj)
            }
            ClusterTaskGroup::DisableAll => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DisableAll".into()));
                JmapValue::Object(obj)
            }
            ClusterTaskGroup::EnableSome(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnableSome".into()));
                obj
            }
            ClusterTaskGroup::DisableSome(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DisableSome".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for ClusterTaskGroup {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                ClusterTaskGroupType::EnableAll => *self = ClusterTaskGroup::EnableAll,
                ClusterTaskGroupType::DisableAll => *self = ClusterTaskGroup::DisableAll,
                ClusterTaskGroupType::EnableSome => {
                    *self = ClusterTaskGroup::EnableSome(Default::default())
                }
                ClusterTaskGroupType::DisableSome => {
                    *self = ClusterTaskGroup::DisableSome(Default::default())
                }
            }
        }
        match self {
            ClusterTaskGroup::EnableAll => pointer.assert_eof(),
            ClusterTaskGroup::DisableAll => pointer.assert_eof(),
            ClusterTaskGroup::EnableSome(inner) => inner.patch(pointer, value),
            ClusterTaskGroup::DisableSome(inner) => inner.patch(pointer, value),
        }
    }
}

impl ClusterTaskGroup {
    pub fn object_type(&self) -> ClusterTaskGroupType {
        match self {
            ClusterTaskGroup::EnableAll => ClusterTaskGroupType::EnableAll,
            ClusterTaskGroup::DisableAll => ClusterTaskGroupType::DisableAll,
            ClusterTaskGroup::EnableSome(_) => ClusterTaskGroupType::EnableSome,
            ClusterTaskGroup::DisableSome(_) => ClusterTaskGroupType::DisableSome,
        }
    }
}

impl ClusterTaskGroupProperties {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for ClusterTaskGroupProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.task_types.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.task_types = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ClusterTaskGroupProperties {
    fn default() -> Self {
        Self {
            task_types: Default::default(),
        }
    }
}

impl IntoValue for ClusterTaskGroupProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::TaskTypes, self.task_types.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ClusterTaskGroupProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TaskTypes) => self.task_types.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Coordinator {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Coordinator;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Coordinator::Disabled => true,
            Coordinator::Default => true,
            Coordinator::Kafka(inner) => inner.validate(errors),
            Coordinator::Nats(inner) => inner.validate(errors),
            Coordinator::Zenoh(inner) => inner.validate(errors),
            Coordinator::Redis(inner) => inner.validate(errors),
            Coordinator::RedisCluster(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for Coordinator {
    fn default() -> Self {
        Coordinator::Disabled
    }
}

impl Pickle for Coordinator {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Coordinator::Disabled => {
                0u16.pickle(out);
            }
            Coordinator::Default => {
                1u16.pickle(out);
            }
            Coordinator::Kafka(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            Coordinator::Nats(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            Coordinator::Zenoh(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            Coordinator::Redis(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            Coordinator::RedisCluster(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(Coordinator::Disabled),
            1 => Some(Coordinator::Default),
            2 => Pickle::unpickle(stream).map(Coordinator::Kafka),
            3 => Pickle::unpickle(stream).map(Coordinator::Nats),
            4 => Pickle::unpickle(stream).map(Coordinator::Zenoh),
            5 => Pickle::unpickle(stream).map(Coordinator::Redis),
            6 => Pickle::unpickle(stream).map(Coordinator::RedisCluster),
            _ => None,
        }
    }
}

impl IntoValue for Coordinator {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Coordinator::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            Coordinator::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            Coordinator::Kafka(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Kafka".into()));
                obj
            }
            Coordinator::Nats(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Nats".into()));
                obj
            }
            Coordinator::Zenoh(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Zenoh".into()));
                obj
            }
            Coordinator::Redis(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Redis".into()));
                obj
            }
            Coordinator::RedisCluster(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Coordinator {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                CoordinatorType::Disabled => *self = Coordinator::Disabled,
                CoordinatorType::Default => *self = Coordinator::Default,
                CoordinatorType::Kafka => *self = Coordinator::Kafka(Default::default()),
                CoordinatorType::Nats => *self = Coordinator::Nats(Default::default()),
                CoordinatorType::Zenoh => *self = Coordinator::Zenoh(Default::default()),
                CoordinatorType::Redis => *self = Coordinator::Redis(Default::default()),
                CoordinatorType::RedisCluster => {
                    *self = Coordinator::RedisCluster(Default::default())
                }
            }
        }
        match self {
            Coordinator::Disabled => pointer.assert_eof(),
            Coordinator::Default => pointer.assert_eof(),
            Coordinator::Kafka(inner) => inner.patch(pointer, value),
            Coordinator::Nats(inner) => inner.patch(pointer, value),
            Coordinator::Zenoh(inner) => inner.patch(pointer, value),
            Coordinator::Redis(inner) => inner.patch(pointer, value),
            Coordinator::RedisCluster(inner) => inner.patch(pointer, value),
        }
    }
}

impl Coordinator {
    pub fn object_type(&self) -> CoordinatorType {
        match self {
            Coordinator::Disabled => CoordinatorType::Disabled,
            Coordinator::Default => CoordinatorType::Default,
            Coordinator::Kafka(_) => CoordinatorType::Kafka,
            Coordinator::Nats(_) => CoordinatorType::Nats,
            Coordinator::Zenoh(_) => CoordinatorType::Zenoh,
            Coordinator::Redis(_) => CoordinatorType::Redis,
            Coordinator::RedisCluster(_) => CoordinatorType::RedisCluster,
        }
    }
}

impl Credential {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Credential::Password(inner) => inner.validate(errors),
            Credential::AppPassword(inner) => inner.validate(errors),
            Credential::ApiKey(inner) => inner.validate(errors),
        }
    }
}

impl Default for Credential {
    fn default() -> Self {
        Credential::Password(Default::default())
    }
}

impl Pickle for Credential {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Credential::Password(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Credential::AppPassword(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Credential::ApiKey(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Credential::Password),
            1 => Pickle::unpickle(stream).map(Credential::AppPassword),
            2 => Pickle::unpickle(stream).map(Credential::ApiKey),
            _ => None,
        }
    }
}

impl IntoValue for Credential {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Credential::Password(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Password".into()));
                obj
            }
            Credential::AppPassword(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("AppPassword".into()));
                obj
            }
            Credential::ApiKey(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ApiKey".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Credential {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                CredentialType::Password => *self = Credential::Password(Default::default()),
                CredentialType::AppPassword => *self = Credential::AppPassword(Default::default()),
                CredentialType::ApiKey => *self = Credential::ApiKey(Default::default()),
            }
        }
        match self {
            Credential::Password(inner) => inner.patch(pointer, value),
            Credential::AppPassword(inner) => inner.patch(pointer, value),
            Credential::ApiKey(inner) => inner.patch(pointer, value),
        }
    }
}

impl Credential {
    pub fn object_type(&self) -> CredentialType {
        match self {
            Credential::Password(_) => CredentialType::Password,
            Credential::AppPassword(_) => CredentialType::AppPassword,
            Credential::ApiKey(_) => CredentialType::ApiKey,
        }
    }
}

impl CredentialPermissions {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            CredentialPermissions::Inherit => true,
            CredentialPermissions::Disable(inner) => inner.validate(errors),
            CredentialPermissions::Replace(inner) => inner.validate(errors),
        }
    }
}

impl Default for CredentialPermissions {
    fn default() -> Self {
        CredentialPermissions::Inherit
    }
}

impl Pickle for CredentialPermissions {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            CredentialPermissions::Inherit => {
                0u16.pickle(out);
            }
            CredentialPermissions::Disable(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            CredentialPermissions::Replace(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(CredentialPermissions::Inherit),
            1 => Pickle::unpickle(stream).map(CredentialPermissions::Disable),
            2 => Pickle::unpickle(stream).map(CredentialPermissions::Replace),
            _ => None,
        }
    }
}

impl IntoValue for CredentialPermissions {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            CredentialPermissions::Inherit => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Inherit".into()));
                JmapValue::Object(obj)
            }
            CredentialPermissions::Disable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Disable".into()));
                obj
            }
            CredentialPermissions::Replace(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Replace".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for CredentialPermissions {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                CredentialPermissionsType::Inherit => *self = CredentialPermissions::Inherit,
                CredentialPermissionsType::Disable => {
                    *self = CredentialPermissions::Disable(Default::default())
                }
                CredentialPermissionsType::Replace => {
                    *self = CredentialPermissions::Replace(Default::default())
                }
            }
        }
        match self {
            CredentialPermissions::Inherit => pointer.assert_eof(),
            CredentialPermissions::Disable(inner) => inner.patch(pointer, value),
            CredentialPermissions::Replace(inner) => inner.patch(pointer, value),
        }
    }
}

impl CredentialPermissions {
    pub fn object_type(&self) -> CredentialPermissionsType {
        match self {
            CredentialPermissions::Inherit => CredentialPermissionsType::Inherit,
            CredentialPermissions::Disable(_) => CredentialPermissionsType::Disable,
            CredentialPermissions::Replace(_) => CredentialPermissionsType::Replace,
        }
    }
}

impl CredentialPermissionsList {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for CredentialPermissionsList {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.permissions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.permissions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CredentialPermissionsList {
    fn default() -> Self {
        Self {
            permissions: Default::default(),
        }
    }
}

impl IntoValue for CredentialPermissionsList {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CredentialPermissionsList {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Cron {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Cron::Daily(inner) => inner.validate(errors),
            Cron::Weekly(inner) => inner.validate(errors),
            Cron::Hourly(inner) => inner.validate(errors),
        }
    }
}

impl Default for Cron {
    fn default() -> Self {
        Cron::Daily(Default::default())
    }
}

impl Pickle for Cron {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Cron::Daily(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Cron::Weekly(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Cron::Hourly(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Cron::Daily),
            1 => Pickle::unpickle(stream).map(Cron::Weekly),
            2 => Pickle::unpickle(stream).map(Cron::Hourly),
            _ => None,
        }
    }
}

impl IntoValue for Cron {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Cron::Daily(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Daily".into()));
                obj
            }
            Cron::Weekly(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Weekly".into()));
                obj
            }
            Cron::Hourly(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hourly".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Cron {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                CronType::Daily => *self = Cron::Daily(Default::default()),
                CronType::Weekly => *self = Cron::Weekly(Default::default()),
                CronType::Hourly => *self = Cron::Hourly(Default::default()),
            }
        }
        match self {
            Cron::Daily(inner) => inner.patch(pointer, value),
            Cron::Weekly(inner) => inner.patch(pointer, value),
            Cron::Hourly(inner) => inner.patch(pointer, value),
        }
    }
}

impl Cron {
    pub fn object_type(&self) -> CronType {
        match self {
            Cron::Daily(_) => CronType::Daily,
            Cron::Weekly(_) => CronType::Weekly,
            Cron::Hourly(_) => CronType::Hourly,
        }
    }
}

impl CronDaily {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.hour;
        if *value > 23 {
            errors.push(ValidationError::max_value(Property::Hour, 23));
        }
        let value = &self.minute;
        if *value > 59 {
            errors.push(ValidationError::max_value(Property::Minute, 59));
        }
        errors.len() == neb
    }
}

impl Pickle for CronDaily {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.hour.pickle(out);
        self.minute.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.hour = Pickle::unpickle(stream)?;
        this.minute = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CronDaily {
    fn default() -> Self {
        Self {
            hour: 0u64,
            minute: 0u64,
        }
    }
}

impl IntoValue for CronDaily {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Hour, self.hour.into_value());
        map.insert_unchecked(Property::Minute, self.minute.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CronDaily {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Hour) => self.hour.patch(pointer, value),
            Some(Property::Minute) => self.minute.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl CronHourly {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.minute;
        if *value > 59 {
            errors.push(ValidationError::max_value(Property::Minute, 59));
        }
        errors.len() == neb
    }
}

impl Pickle for CronHourly {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.minute.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.minute = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CronHourly {
    fn default() -> Self {
        Self { minute: 0u64 }
    }
}

impl IntoValue for CronHourly {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Minute, self.minute.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CronHourly {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Minute) => self.minute.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl CronWeekly {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.day;
        if *value > 6 {
            errors.push(ValidationError::max_value(Property::Day, 6));
        }
        let value = &self.hour;
        if *value > 23 {
            errors.push(ValidationError::max_value(Property::Hour, 23));
        }
        let value = &self.minute;
        if *value > 59 {
            errors.push(ValidationError::max_value(Property::Minute, 59));
        }
        errors.len() == neb
    }
}

impl Pickle for CronWeekly {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.day.pickle(out);
        self.hour.pickle(out);
        self.minute.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.day = Pickle::unpickle(stream)?;
        this.hour = Pickle::unpickle(stream)?;
        this.minute = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CronWeekly {
    fn default() -> Self {
        Self {
            day: 0u64,
            hour: 0u64,
            minute: 0u64,
        }
    }
}

impl IntoValue for CronWeekly {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Day, self.day.into_value());
        map.insert_unchecked(Property::Hour, self.hour.into_value());
        map.insert_unchecked(Property::Minute, self.minute.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CronWeekly {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Day) => self.day.patch(pointer, value),
            Some(Property::Hour) => self.hour.patch(pointer, value),
            Some(Property::Minute) => self.minute.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl CustomRoles {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::RoleIds));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        for id in self.role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
    }
}

impl Pickle for CustomRoles {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.role_ids.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.role_ids = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for CustomRoles {
    fn default() -> Self {
        Self {
            role_ids: Default::default(),
        }
    }
}

impl IntoValue for CustomRoles {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::RoleIds, self.role_ids.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for CustomRoles {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::RoleIds) => self.role_ids.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DataRetention {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DataRetention;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.expunge_schedule;
        value.validate(errors);
        let value = &self.data_cleanup_schedule;
        value.validate(errors);
        let value = &self.blob_cleanup_schedule;
        value.validate(errors);
        let value = &self.metrics_collection_interval;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for DataRetention {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.expunge_trash_after.pickle(out);
        self.expunge_submissions_after.pickle(out);
        self.expunge_share_notify_after.pickle(out);
        self.expunge_scheduling_inbox_after.pickle(out);
        self.expunge_schedule.pickle(out);
        self.data_cleanup_schedule.pickle(out);
        self.blob_cleanup_schedule.pickle(out);
        self.max_changes_history.pickle(out);
        self.archive_deleted_items_for.pickle(out);
        self.archive_deleted_accounts_for.pickle(out);
        self.hold_mta_reports_for.pickle(out);
        self.hold_traces_for.pickle(out);
        self.hold_metrics_for.pickle(out);
        self.metrics_collection_interval.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.expunge_trash_after = Pickle::unpickle(stream)?;
        this.expunge_submissions_after = Pickle::unpickle(stream)?;
        this.expunge_share_notify_after = Pickle::unpickle(stream)?;
        this.expunge_scheduling_inbox_after = Pickle::unpickle(stream)?;
        this.expunge_schedule = Pickle::unpickle(stream)?;
        this.data_cleanup_schedule = Pickle::unpickle(stream)?;
        this.blob_cleanup_schedule = Pickle::unpickle(stream)?;
        this.max_changes_history = Pickle::unpickle(stream)?;
        this.archive_deleted_items_for = Pickle::unpickle(stream)?;
        this.archive_deleted_accounts_for = Pickle::unpickle(stream)?;
        this.hold_mta_reports_for = Pickle::unpickle(stream)?;
        this.hold_traces_for = Pickle::unpickle(stream)?;
        this.hold_metrics_for = Pickle::unpickle(stream)?;
        this.metrics_collection_interval = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DataRetention {
    fn default() -> Self {
        Self {
            expunge_trash_after: Some(Duration::from_millis(2592000000)),
            expunge_submissions_after: Some(Duration::from_millis(259200000)),
            expunge_share_notify_after: Some(Duration::from_millis(2592000000)),
            expunge_scheduling_inbox_after: Some(Duration::from_millis(2592000000)),
            expunge_schedule: Cron::Daily(CronDaily {
                hour: 0u64,
                minute: 0u64,
            }),
            data_cleanup_schedule: Cron::Daily(CronDaily {
                hour: 2u64,
                minute: 0u64,
            }),
            blob_cleanup_schedule: Cron::Daily(CronDaily {
                hour: 4u64,
                minute: 0u64,
            }),
            max_changes_history: Some(10000u64),
            archive_deleted_items_for: Default::default(),
            archive_deleted_accounts_for: Default::default(),
            hold_mta_reports_for: Some(Duration::from_millis(2592000000)),
            hold_traces_for: Some(Duration::from_millis(2592000000)),
            hold_metrics_for: Some(Duration::from_millis(7776000000)),
            metrics_collection_interval: Cron::Hourly(CronHourly { minute: 0u64 }),
        }
    }
}

impl IntoValue for DataRetention {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(
            Property::ExpungeTrashAfter,
            self.expunge_trash_after.into_value(),
        );
        map.insert_unchecked(
            Property::ExpungeSubmissionsAfter,
            self.expunge_submissions_after.into_value(),
        );
        map.insert_unchecked(
            Property::ExpungeShareNotifyAfter,
            self.expunge_share_notify_after.into_value(),
        );
        map.insert_unchecked(
            Property::ExpungeSchedulingInboxAfter,
            self.expunge_scheduling_inbox_after.into_value(),
        );
        map.insert_unchecked(
            Property::ExpungeSchedule,
            self.expunge_schedule.into_value(),
        );
        map.insert_unchecked(
            Property::DataCleanupSchedule,
            self.data_cleanup_schedule.into_value(),
        );
        map.insert_unchecked(
            Property::BlobCleanupSchedule,
            self.blob_cleanup_schedule.into_value(),
        );
        map.insert_unchecked(
            Property::MaxChangesHistory,
            self.max_changes_history.into_value(),
        );
        map.insert_unchecked(
            Property::ArchiveDeletedItemsFor,
            self.archive_deleted_items_for.into_value(),
        );
        map.insert_unchecked(
            Property::ArchiveDeletedAccountsFor,
            self.archive_deleted_accounts_for.into_value(),
        );
        map.insert_unchecked(
            Property::HoldMtaReportsFor,
            self.hold_mta_reports_for.into_value(),
        );
        map.insert_unchecked(Property::HoldTracesFor, self.hold_traces_for.into_value());
        map.insert_unchecked(Property::HoldMetricsFor, self.hold_metrics_for.into_value());
        map.insert_unchecked(
            Property::MetricsCollectionInterval,
            self.metrics_collection_interval.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DataRetention {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ExpungeTrashAfter) => self.expunge_trash_after.patch(pointer, value),
            Some(Property::ExpungeSubmissionsAfter) => {
                self.expunge_submissions_after.patch(pointer, value)
            }
            Some(Property::ExpungeShareNotifyAfter) => {
                self.expunge_share_notify_after.patch(pointer, value)
            }
            Some(Property::ExpungeSchedulingInboxAfter) => {
                self.expunge_scheduling_inbox_after.patch(pointer, value)
            }
            Some(Property::ExpungeSchedule) => self.expunge_schedule.patch(pointer, value),
            Some(Property::DataCleanupSchedule) => self.data_cleanup_schedule.patch(pointer, value),
            Some(Property::BlobCleanupSchedule) => self.blob_cleanup_schedule.patch(pointer, value),
            Some(Property::MaxChangesHistory) => self.max_changes_history.patch(pointer, value),
            Some(Property::ArchiveDeletedItemsFor) => {
                self.archive_deleted_items_for.patch(pointer, value)
            }
            Some(Property::ArchiveDeletedAccountsFor) => {
                self.archive_deleted_accounts_for.patch(pointer, value)
            }
            Some(Property::HoldMtaReportsFor) => self.hold_mta_reports_for.patch(pointer, value),
            Some(Property::HoldTracesFor) => self.hold_traces_for.patch(pointer, value),
            Some(Property::HoldMetricsFor) => self.hold_metrics_for.patch(pointer, value),
            Some(Property::MetricsCollectionInterval) => {
                self.metrics_collection_interval.patch(pointer, value)
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DataStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DataStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DataStore::RocksDb(inner) => inner.validate(errors),
            DataStore::Sqlite(inner) => inner.validate(errors),
            DataStore::FoundationDb(inner) => inner.validate(errors),
            DataStore::PostgreSql(inner) => inner.validate(errors),
            DataStore::MySql(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for DataStore {
    fn default() -> Self {
        DataStore::RocksDb(Default::default())
    }
}

impl Pickle for DataStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DataStore::RocksDb(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            DataStore::Sqlite(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            DataStore::FoundationDb(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            DataStore::PostgreSql(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            DataStore::MySql(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(DataStore::RocksDb),
            1 => Pickle::unpickle(stream).map(DataStore::Sqlite),
            2 => Pickle::unpickle(stream).map(DataStore::FoundationDb),
            3 => Pickle::unpickle(stream).map(DataStore::PostgreSql),
            4 => Pickle::unpickle(stream).map(DataStore::MySql),
            _ => None,
        }
    }
}

impl IntoValue for DataStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DataStore::RocksDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RocksDb".into()));
                obj
            }
            DataStore::Sqlite(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sqlite".into()));
                obj
            }
            DataStore::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            DataStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            DataStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DataStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DataStoreType::RocksDb => *self = DataStore::RocksDb(Default::default()),
                DataStoreType::Sqlite => *self = DataStore::Sqlite(Default::default()),
                DataStoreType::FoundationDb => *self = DataStore::FoundationDb(Default::default()),
                DataStoreType::PostgreSql => *self = DataStore::PostgreSql(Default::default()),
                DataStoreType::MySql => *self = DataStore::MySql(Default::default()),
            }
        }
        match self {
            DataStore::RocksDb(inner) => inner.patch(pointer, value),
            DataStore::Sqlite(inner) => inner.patch(pointer, value),
            DataStore::FoundationDb(inner) => inner.patch(pointer, value),
            DataStore::PostgreSql(inner) => inner.patch(pointer, value),
            DataStore::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl DataStore {
    pub fn object_type(&self) -> DataStoreType {
        match self {
            DataStore::RocksDb(_) => DataStoreType::RocksDb,
            DataStore::Sqlite(_) => DataStoreType::Sqlite,
            DataStore::FoundationDb(_) => DataStoreType::FoundationDb,
            DataStore::PostgreSql(_) => DataStoreType::PostgreSql,
            DataStore::MySql(_) => DataStoreType::MySql,
        }
    }
}

impl DeliveryError {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.error_message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ErrorMessage));
            }
        }
        if let Some(value) = &self.error_command {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ErrorCommand));
            }
        }
        if let Some(value) = &self.response_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseHostname));
            }
        }
        if let Some(value) = &self.response_code {
            if *value < 100 {
                errors.push(ValidationError::min_value(Property::ResponseCode, 100));
            }
            if *value > 599 {
                errors.push(ValidationError::max_value(Property::ResponseCode, 599));
            }
        }
        if let Some(value) = &self.response_enhanced {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseEnhanced));
            }
        }
        if let Some(value) = &self.response_message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseMessage));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for DeliveryError {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.error_type.pickle(out);
        self.error_message.pickle(out);
        self.error_command.pickle(out);
        self.response_hostname.pickle(out);
        self.response_code.pickle(out);
        self.response_enhanced.pickle(out);
        self.response_message.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.error_type = Pickle::unpickle(stream)?;
        this.error_message = Pickle::unpickle(stream)?;
        this.error_command = Pickle::unpickle(stream)?;
        this.response_hostname = Pickle::unpickle(stream)?;
        this.response_code = Pickle::unpickle(stream)?;
        this.response_enhanced = Pickle::unpickle(stream)?;
        this.response_message = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DeliveryError {
    fn default() -> Self {
        Self {
            error_type: Default::default(),
            error_message: Default::default(),
            error_command: Default::default(),
            response_hostname: Default::default(),
            response_code: Default::default(),
            response_enhanced: Default::default(),
            response_message: Default::default(),
        }
    }
}

impl IntoValue for DeliveryError {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::ErrorType, self.error_type.into_value());
        map.insert_unchecked(Property::ErrorMessage, self.error_message.into_value());
        map.insert_unchecked(Property::ErrorCommand, self.error_command.into_value());
        map.insert_unchecked(
            Property::ResponseHostname,
            self.response_hostname.into_value(),
        );
        map.insert_unchecked(Property::ResponseCode, self.response_code.into_value());
        map.insert_unchecked(
            Property::ResponseEnhanced,
            self.response_enhanced.into_value(),
        );
        map.insert_unchecked(
            Property::ResponseMessage,
            self.response_message.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DeliveryError {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ErrorType) => self.error_type.patch(pointer, value),
            Some(Property::ErrorMessage) => self.error_message.patch(pointer, value),
            Some(Property::ErrorCommand) => self.error_command.patch(pointer, value),
            Some(Property::ResponseHostname) => self.response_hostname.patch(pointer, value),
            Some(Property::ResponseCode) => self.response_code.patch(pointer, value),
            Some(Property::ResponseEnhanced) => self.response_enhanced.patch(pointer, value),
            Some(Property::ResponseMessage) => self.response_message.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Directory {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Directory;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Directory::Ldap(inner) => inner.validate(errors),
            Directory::Sql(inner) => inner.validate(errors),
            Directory::Oidc(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            Directory::Ldap(object) => {
                object.index(i);
            }
            Directory::Sql(object) => {
                object.index(i);
            }
            Directory::Oidc(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for Directory {
    fn default() -> Self {
        Directory::Ldap(Default::default())
    }
}

impl Pickle for Directory {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Directory::Ldap(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Directory::Sql(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Directory::Oidc(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Directory::Ldap),
            1 => Pickle::unpickle(stream).map(Directory::Sql),
            2 => Pickle::unpickle(stream).map(Directory::Oidc),
            _ => None,
        }
    }
}

impl IntoValue for Directory {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Directory::Ldap(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ldap".into()));
                obj
            }
            Directory::Sql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sql".into()));
                obj
            }
            Directory::Oidc(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Oidc".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Directory {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DirectoryType::Ldap => *self = Directory::Ldap(Default::default()),
                DirectoryType::Sql => *self = Directory::Sql(Default::default()),
                DirectoryType::Oidc => *self = Directory::Oidc(Default::default()),
            }
        }
        match self {
            Directory::Ldap(inner) => inner.patch(pointer, value),
            Directory::Sql(inner) => inner.patch(pointer, value),
            Directory::Oidc(inner) => inner.patch(pointer, value),
        }
    }
}

impl Directory {
    pub fn object_type(&self) -> DirectoryType {
        match self {
            Directory::Ldap(_) => DirectoryType::Ldap,
            Directory::Sql(_) => DirectoryType::Sql,
            Directory::Oidc(_) => DirectoryType::Oidc,
        }
    }
}

impl DirectoryBootstrap {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DirectoryBootstrap::Internal => true,
            DirectoryBootstrap::Ldap(inner) => inner.validate(errors),
            DirectoryBootstrap::Sql(inner) => inner.validate(errors),
            DirectoryBootstrap::Oidc(inner) => inner.validate(errors),
        }
    }
}

impl Default for DirectoryBootstrap {
    fn default() -> Self {
        DirectoryBootstrap::Internal
    }
}

impl Pickle for DirectoryBootstrap {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DirectoryBootstrap::Internal => {
                0u16.pickle(out);
            }
            DirectoryBootstrap::Ldap(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            DirectoryBootstrap::Sql(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            DirectoryBootstrap::Oidc(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(DirectoryBootstrap::Internal),
            1 => Pickle::unpickle(stream).map(DirectoryBootstrap::Ldap),
            2 => Pickle::unpickle(stream).map(DirectoryBootstrap::Sql),
            3 => Pickle::unpickle(stream).map(DirectoryBootstrap::Oidc),
            _ => None,
        }
    }
}

impl IntoValue for DirectoryBootstrap {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DirectoryBootstrap::Internal => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Internal".into()));
                JmapValue::Object(obj)
            }
            DirectoryBootstrap::Ldap(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ldap".into()));
                obj
            }
            DirectoryBootstrap::Sql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sql".into()));
                obj
            }
            DirectoryBootstrap::Oidc(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Oidc".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DirectoryBootstrap {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DirectoryBootstrapType::Internal => *self = DirectoryBootstrap::Internal,
                DirectoryBootstrapType::Ldap => {
                    *self = DirectoryBootstrap::Ldap(Default::default())
                }
                DirectoryBootstrapType::Sql => *self = DirectoryBootstrap::Sql(Default::default()),
                DirectoryBootstrapType::Oidc => {
                    *self = DirectoryBootstrap::Oidc(Default::default())
                }
            }
        }
        match self {
            DirectoryBootstrap::Internal => pointer.assert_eof(),
            DirectoryBootstrap::Ldap(inner) => inner.patch(pointer, value),
            DirectoryBootstrap::Sql(inner) => inner.patch(pointer, value),
            DirectoryBootstrap::Oidc(inner) => inner.patch(pointer, value),
        }
    }
}

impl DirectoryBootstrap {
    pub fn object_type(&self) -> DirectoryBootstrapType {
        match self {
            DirectoryBootstrap::Internal => DirectoryBootstrapType::Internal,
            DirectoryBootstrap::Ldap(_) => DirectoryBootstrapType::Ldap,
            DirectoryBootstrap::Sql(_) => DirectoryBootstrapType::Sql,
            DirectoryBootstrap::Oidc(_) => DirectoryBootstrapType::Oidc,
        }
    }
}

impl Dkim1Signature {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.auid {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Auid));
            }
        }
        let value = &self.headers;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Headers));
            }
        }
        let value = &self.private_key;
        value.validate(errors);
        if let Some(value) = &self.third_party {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ThirdParty));
            }
        }
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.selector;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Selector));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.next_transition_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::NextTransitionAt, value));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
        i.search(Property::DomainId, &self.domain_id);
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for Dkim1Signature {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auid.pickle(out);
        self.canonicalization.pickle(out);
        self.expire.pickle(out);
        self.headers.pickle(out);
        self.private_key.pickle(out);
        self.report.pickle(out);
        self.third_party.pickle(out);
        self.third_party_hash.pickle(out);
        self.domain_id.pickle(out);
        self.member_tenant_id.pickle(out);
        self.selector.pickle(out);
        self.created_at.pickle(out);
        self.next_transition_at.pickle(out);
        self.stage.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auid = Pickle::unpickle(stream)?;
        this.canonicalization = Pickle::unpickle(stream)?;
        this.expire = Pickle::unpickle(stream)?;
        this.headers = Pickle::unpickle(stream)?;
        this.private_key = Pickle::unpickle(stream)?;
        this.report = Pickle::unpickle(stream)?;
        this.third_party = Pickle::unpickle(stream)?;
        this.third_party_hash = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.selector = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.next_transition_at = Pickle::unpickle(stream)?;
        this.stage = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Dkim1Signature {
    fn default() -> Self {
        Self {
            auid: Default::default(),
            canonicalization: DkimCanonicalization::RelaxedRelaxed,
            expire: Default::default(),
            headers: Map::new(vec![
                "From".to_string(),
                "To".to_string(),
                "Date".to_string(),
                "Subject".to_string(),
                "Message-ID".to_string(),
            ]),
            private_key: Default::default(),
            report: true,
            third_party: Default::default(),
            third_party_hash: Default::default(),
            domain_id: Default::default(),
            member_tenant_id: Default::default(),
            selector: Default::default(),
            created_at: Default::default(),
            next_transition_at: Default::default(),
            stage: DkimRotationStage::Active,
        }
    }
}

impl IntoValue for Dkim1Signature {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(Property::Auid, self.auid.into_value());
        map.insert_unchecked(
            Property::Canonicalization,
            self.canonicalization.into_value(),
        );
        map.insert_unchecked(Property::Expire, self.expire.into_value());
        map.insert_unchecked(Property::Headers, self.headers.into_value());
        map.insert_unchecked(Property::PrivateKey, self.private_key.into_value());
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::ThirdParty, self.third_party.into_value());
        map.insert_unchecked(Property::ThirdPartyHash, self.third_party_hash.into_value());
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Selector, self.selector.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(
            Property::NextTransitionAt,
            self.next_transition_at.into_value(),
        );
        map.insert_unchecked(Property::Stage, self.stage.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Dkim1Signature {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Auid) => self
                .auid
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Canonicalization) => self.canonicalization.patch(pointer, value),
            Some(Property::Expire) => self.expire.patch(pointer, value),
            Some(Property::Headers) => self
                .headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PrivateKey) => self.private_key.patch(pointer, value),
            Some(Property::PublicKey) => pointer.assert_server_set(),
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::ThirdParty) => self
                .third_party
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ThirdPartyHash) => self.third_party_hash.patch(pointer, value),
            Some(Property::DomainId) => self.domain_id.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Selector) => self
                .selector
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::NextTransitionAt) => self.next_transition_at.patch(pointer, value),
            Some(Property::Stage) => self.stage.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DkimManagement {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DkimManagement::Automatic(inner) => inner.validate(errors),
            DkimManagement::Manual => true,
        }
    }
}

impl Default for DkimManagement {
    fn default() -> Self {
        DkimManagement::Automatic(Default::default())
    }
}

impl Pickle for DkimManagement {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DkimManagement::Automatic(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            DkimManagement::Manual => {
                1u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(DkimManagement::Automatic),
            1 => Some(DkimManagement::Manual),
            _ => None,
        }
    }
}

impl IntoValue for DkimManagement {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DkimManagement::Automatic(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Automatic".into()));
                obj
            }
            DkimManagement::Manual => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Manual".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for DkimManagement {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DkimManagementType::Automatic => {
                    *self = DkimManagement::Automatic(Default::default())
                }
                DkimManagementType::Manual => *self = DkimManagement::Manual,
            }
        }
        match self {
            DkimManagement::Automatic(inner) => inner.patch(pointer, value),
            DkimManagement::Manual => pointer.assert_eof(),
        }
    }
}

impl DkimManagement {
    pub fn object_type(&self) -> DkimManagementType {
        match self {
            DkimManagement::Automatic(_) => DkimManagementType::Automatic,
            DkimManagement::Manual => DkimManagementType::Manual,
        }
    }
}

impl DkimManagementProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.selector_template;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::SelectorTemplate));
        }
        errors.len() == neb
    }
}

impl Pickle for DkimManagementProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.algorithms.pickle(out);
        self.selector_template.pickle(out);
        self.rotate_after.pickle(out);
        self.retire_after.pickle(out);
        self.delete_after.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.algorithms = Pickle::unpickle(stream)?;
        this.selector_template = Pickle::unpickle(stream)?;
        this.rotate_after = Pickle::unpickle(stream)?;
        this.retire_after = Pickle::unpickle(stream)?;
        this.delete_after = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DkimManagementProperties {
    fn default() -> Self {
        Self {
            algorithms: Map::new(vec![
                DkimSignatureType::Dkim1Ed25519Sha256,
                DkimSignatureType::Dkim1RsaSha256,
            ]),
            selector_template: "v{version}-{algorithm}-{date-%Y%m%d}".to_string(),
            rotate_after: Duration::from_millis(7776000000),
            retire_after: Duration::from_millis(604800000),
            delete_after: Duration::from_millis(2592000000),
        }
    }
}

impl IntoValue for DkimManagementProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Algorithms, self.algorithms.into_value());
        map.insert_unchecked(
            Property::SelectorTemplate,
            self.selector_template.into_value(),
        );
        map.insert_unchecked(Property::RotateAfter, self.rotate_after.into_value());
        map.insert_unchecked(Property::RetireAfter, self.retire_after.into_value());
        map.insert_unchecked(Property::DeleteAfter, self.delete_after.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DkimManagementProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Algorithms) => self.algorithms.patch(pointer, value),
            Some(Property::SelectorTemplate) => self
                .selector_template
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::RotateAfter) => self.rotate_after.patch(pointer, value),
            Some(Property::RetireAfter) => self.retire_after.patch(pointer, value),
            Some(Property::DeleteAfter) => self.delete_after.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DkimReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DkimReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from_address;
        value.validate(errors);
        let value = &self.from_name;
        value.validate(errors);
        let value = &self.send_frequency;
        value.validate(errors);
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        let value = &self.subject;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl DkimReportSettings {
    pub fn ctx_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_address,
            default: Some(Expression {
                else_: "'noreply-dkim@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FromAddress,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_name,
            default: Some(Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::FromName,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_send_frequency(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.send_frequency,
            default: Some(Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            }),
            property: Property::SendFrequency,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_subject(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.subject,
            default: Some(Expression {
                else_: "'DKIM Authentication Failure Report'".to_string(),
                ..Default::default()
            }),
            property: Property::Subject,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_from_address(),
            self.ctx_from_name(),
            self.ctx_send_frequency(),
            self.ctx_dkim_sign_domain(),
            self.ctx_subject(),
        ]
    }
}

impl Pickle for DkimReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from_address.pickle(out);
        self.from_name.pickle(out);
        self.send_frequency.pickle(out);
        self.dkim_sign_domain.pickle(out);
        self.subject.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from_address = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.send_frequency = Pickle::unpickle(stream)?;
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DkimReportSettings {
    fn default() -> Self {
        Self {
            from_address: Expression {
                else_: "'noreply-dkim@' + system('domain')".to_string(),
                ..Default::default()
            },
            from_name: Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            },
            send_frequency: Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            },
            dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            subject: Expression {
                else_: "'DKIM Authentication Failure Report'".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for DkimReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::FromAddress, self.from_address.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(Property::SendFrequency, self.send_frequency.into_value());
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DkimReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::FromAddress) => self.from_address.patch(pointer, value),
            Some(Property::FromName) => self.from_name.patch(pointer, value),
            Some(Property::SendFrequency) => self.send_frequency.patch(pointer, value),
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DkimSignature {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DkimSignature;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DkimSignature::Dkim1Ed25519Sha256(inner) => inner.validate(errors),
            DkimSignature::Dkim1RsaSha256(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            DkimSignature::Dkim1Ed25519Sha256(object) => {
                object.index(i);
            }
            DkimSignature::Dkim1RsaSha256(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for DkimSignature {
    fn default() -> Self {
        DkimSignature::Dkim1Ed25519Sha256(Default::default())
    }
}

impl Pickle for DkimSignature {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DkimSignature::Dkim1Ed25519Sha256(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            DkimSignature::Dkim1RsaSha256(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(DkimSignature::Dkim1Ed25519Sha256),
            1 => Pickle::unpickle(stream).map(DkimSignature::Dkim1RsaSha256),
            _ => None,
        }
    }
}

impl IntoValue for DkimSignature {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DkimSignature::Dkim1Ed25519Sha256(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dkim1Ed25519Sha256".into()));
                obj
            }
            DkimSignature::Dkim1RsaSha256(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dkim1RsaSha256".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DkimSignature {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DkimSignatureType::Dkim1Ed25519Sha256 => {
                    *self = DkimSignature::Dkim1Ed25519Sha256(Default::default())
                }
                DkimSignatureType::Dkim1RsaSha256 => {
                    *self = DkimSignature::Dkim1RsaSha256(Default::default())
                }
            }
        }
        match self {
            DkimSignature::Dkim1Ed25519Sha256(inner) => inner.patch(pointer, value),
            DkimSignature::Dkim1RsaSha256(inner) => inner.patch(pointer, value),
        }
    }
}

impl DkimSignature {
    pub fn object_type(&self) -> DkimSignatureType {
        match self {
            DkimSignature::Dkim1Ed25519Sha256(_) => DkimSignatureType::Dkim1Ed25519Sha256,
            DkimSignature::Dkim1RsaSha256(_) => DkimSignatureType::Dkim1RsaSha256,
        }
    }
}

impl DmarcDkimResult {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Domain));
        }
        let value = &self.selector;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Selector));
        }
        if let Some(value) = &self.human_result {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HumanResult));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcDkimResult {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.domain.pickle(out);
        self.selector.pickle(out);
        self.result.pickle(out);
        self.human_result.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.domain = Pickle::unpickle(stream)?;
        this.selector = Pickle::unpickle(stream)?;
        this.result = Pickle::unpickle(stream)?;
        this.human_result = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcDkimResult {
    fn default() -> Self {
        Self {
            domain: Default::default(),
            selector: Default::default(),
            result: Default::default(),
            human_result: Default::default(),
        }
    }
}

impl IntoValue for DmarcDkimResult {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Domain, self.domain.into_value());
        map.insert_unchecked(Property::Selector, self.selector.into_value());
        map.insert_unchecked(Property::Result, self.result.into_value());
        map.insert_unchecked(Property::HumanResult, self.human_result.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcDkimResult {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Domain) => self
                .domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::Selector) => self.selector.patch(pointer, value),
            Some(Property::Result) => self.result.patch(pointer, value),
            Some(Property::HumanResult) => self.human_result.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcExtension {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.definition;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Definition));
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcExtension {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.definition.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.definition = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcExtension {
    fn default() -> Self {
        Self {
            name: Default::default(),
            definition: Default::default(),
        }
    }
}

impl IntoValue for DmarcExtension {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Definition, self.definition.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcExtension {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer, value),
            Some(Property::Definition) => self.definition.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DmarcExternalReport {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DmarcExternalReport;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.report;
        value.validate(errors);
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::To));
            }
        }
        let value = &self.received_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ReceivedAt, value));
        }
        let value = &self.expires_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ExpiresAt, value));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
    }
}

impl Pickle for DmarcExternalReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.report.pickle(out);
        self.from.pickle(out);
        self.subject.pickle(out);
        self.to.pickle(out);
        self.received_at.pickle(out);
        self.expires_at.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.report = Pickle::unpickle(stream)?;
        this.from = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.to = Pickle::unpickle(stream)?;
        this.received_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcExternalReport {
    fn default() -> Self {
        Self {
            report: Default::default(),
            from: Default::default(),
            subject: Default::default(),
            to: Default::default(),
            received_at: Default::default(),
            expires_at: Default::default(),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for DmarcExternalReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::To, self.to.into_value());
        map.insert_unchecked(Property::ReceivedAt, self.received_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcExternalReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::From) => self
                .from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::To) => self
                .to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::ReceivedAt) => self.received_at.patch(pointer, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DmarcInternalReport {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DmarcInternalReport;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.rua;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Rua));
            }
        }
        let value = &self.report;
        value.validate(errors);
        let value = &self.domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Domain));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.deliver_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DeliverAt, value));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for DmarcInternalReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.rua.pickle(out);
        self.policy_identifier.pickle(out);
        self.report.pickle(out);
        self.domain.pickle(out);
        self.created_at.pickle(out);
        self.deliver_at.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.rua = Pickle::unpickle(stream)?;
        this.policy_identifier = Pickle::unpickle(stream)?;
        this.report = Pickle::unpickle(stream)?;
        this.domain = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.deliver_at = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcInternalReport {
    fn default() -> Self {
        Self {
            rua: Default::default(),
            policy_identifier: 0u64,
            report: Default::default(),
            domain: Default::default(),
            created_at: Default::default(),
            deliver_at: Default::default(),
        }
    }
}

impl IntoValue for DmarcInternalReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Rua, self.rua.into_value());
        map.insert_unchecked(
            Property::PolicyIdentifier,
            self.policy_identifier.into_value(),
        );
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::Domain, self.domain.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::DeliverAt, self.deliver_at.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcInternalReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Rua) => self
                .rua
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::PolicyIdentifier) => self.policy_identifier.patch(pointer, value),
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::Domain) => self
                .domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::CreatedAt) => self.created_at.patch(pointer, value),
            Some(Property::DeliverAt) => self.deliver_at.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcPolicyOverrideReason {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.comment {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Comment));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcPolicyOverrideReason {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.override_type.pickle(out);
        self.comment.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.override_type = Pickle::unpickle(stream)?;
        this.comment = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcPolicyOverrideReason {
    fn default() -> Self {
        Self {
            override_type: Default::default(),
            comment: Default::default(),
        }
    }
}

impl IntoValue for DmarcPolicyOverrideReason {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::OverrideType, self.override_type.into_value());
        map.insert_unchecked(Property::Comment, self.comment.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcPolicyOverrideReason {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::OverrideType) => self.override_type.patch(pointer, value),
            Some(Property::Comment) => self.comment.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcReport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.org_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::OrgName));
        }
        let value = &self.email;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Email));
        }
        if let Some(value) = &self.extra_contact_info {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ExtraContactInfo));
            }
        }
        let value = &self.report_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ReportId));
        }
        let value = &self.date_range_begin;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DateRangeBegin, value));
        }
        let value = &self.date_range_end;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DateRangeEnd, value));
        }
        let value = &self.errors;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Errors));
            }
        }
        let value = &self.policy_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::PolicyDomain));
        }
        if let Some(value) = &self.policy_version {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::PolicyVersion));
            }
        }
        let value = &self.records;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.extensions;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.version.pickle(out);
        self.org_name.pickle(out);
        self.email.pickle(out);
        self.extra_contact_info.pickle(out);
        self.report_id.pickle(out);
        self.date_range_begin.pickle(out);
        self.date_range_end.pickle(out);
        self.errors.pickle(out);
        self.policy_domain.pickle(out);
        self.policy_version.pickle(out);
        self.policy_adkim.pickle(out);
        self.policy_aspf.pickle(out);
        self.policy_disposition.pickle(out);
        self.policy_subdomain_disposition.pickle(out);
        self.policy_testing_mode.pickle(out);
        self.policy_failure_reporting_options.pickle(out);
        self.records.pickle(out);
        self.extensions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.version = Pickle::unpickle(stream)?;
        this.org_name = Pickle::unpickle(stream)?;
        this.email = Pickle::unpickle(stream)?;
        this.extra_contact_info = Pickle::unpickle(stream)?;
        this.report_id = Pickle::unpickle(stream)?;
        this.date_range_begin = Pickle::unpickle(stream)?;
        this.date_range_end = Pickle::unpickle(stream)?;
        this.errors = Pickle::unpickle(stream)?;
        this.policy_domain = Pickle::unpickle(stream)?;
        this.policy_version = Pickle::unpickle(stream)?;
        this.policy_adkim = Pickle::unpickle(stream)?;
        this.policy_aspf = Pickle::unpickle(stream)?;
        this.policy_disposition = Pickle::unpickle(stream)?;
        this.policy_subdomain_disposition = Pickle::unpickle(stream)?;
        this.policy_testing_mode = Pickle::unpickle(stream)?;
        this.policy_failure_reporting_options = Pickle::unpickle(stream)?;
        this.records = Pickle::unpickle(stream)?;
        this.extensions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcReport {
    fn default() -> Self {
        Self {
            version: Float::new(1.0f64),
            org_name: Default::default(),
            email: Default::default(),
            extra_contact_info: Default::default(),
            report_id: Default::default(),
            date_range_begin: Default::default(),
            date_range_end: Default::default(),
            errors: Default::default(),
            policy_domain: Default::default(),
            policy_version: Default::default(),
            policy_adkim: Default::default(),
            policy_aspf: Default::default(),
            policy_disposition: Default::default(),
            policy_subdomain_disposition: Default::default(),
            policy_testing_mode: false,
            policy_failure_reporting_options: Default::default(),
            records: Default::default(),
            extensions: Default::default(),
        }
    }
}

impl IntoValue for DmarcReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(20);
        map.insert_unchecked(Property::Version, self.version.into_value());
        map.insert_unchecked(Property::OrgName, self.org_name.into_value());
        map.insert_unchecked(Property::Email, self.email.into_value());
        map.insert_unchecked(
            Property::ExtraContactInfo,
            self.extra_contact_info.into_value(),
        );
        map.insert_unchecked(Property::ReportId, self.report_id.into_value());
        map.insert_unchecked(Property::DateRangeBegin, self.date_range_begin.into_value());
        map.insert_unchecked(Property::DateRangeEnd, self.date_range_end.into_value());
        map.insert_unchecked(Property::Errors, self.errors.into_value());
        map.insert_unchecked(Property::PolicyDomain, self.policy_domain.into_value());
        map.insert_unchecked(Property::PolicyVersion, self.policy_version.into_value());
        map.insert_unchecked(Property::PolicyAdkim, self.policy_adkim.into_value());
        map.insert_unchecked(Property::PolicyAspf, self.policy_aspf.into_value());
        map.insert_unchecked(
            Property::PolicyDisposition,
            self.policy_disposition.into_value(),
        );
        map.insert_unchecked(
            Property::PolicySubdomainDisposition,
            self.policy_subdomain_disposition.into_value(),
        );
        map.insert_unchecked(
            Property::PolicyTestingMode,
            self.policy_testing_mode.into_value(),
        );
        map.insert_unchecked(
            Property::PolicyFailureReportingOptions,
            self.policy_failure_reporting_options.into_value(),
        );
        map.insert_unchecked(Property::Records, self.records.into_value());
        map.insert_unchecked(Property::Extensions, self.extensions.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Version) => self.version.patch(pointer, value),
            Some(Property::OrgName) => self.org_name.patch(pointer, value),
            Some(Property::Email) => self
                .email
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::ExtraContactInfo) => self.extra_contact_info.patch(pointer, value),
            Some(Property::ReportId) => self.report_id.patch(pointer, value),
            Some(Property::DateRangeBegin) => self.date_range_begin.patch(pointer, value),
            Some(Property::DateRangeEnd) => self.date_range_end.patch(pointer, value),
            Some(Property::Errors) => self.errors.patch(pointer, value),
            Some(Property::PolicyDomain) => self.policy_domain.patch(pointer, value),
            Some(Property::PolicyVersion) => self.policy_version.patch(pointer, value),
            Some(Property::PolicyAdkim) => self.policy_adkim.patch(pointer, value),
            Some(Property::PolicyAspf) => self.policy_aspf.patch(pointer, value),
            Some(Property::PolicyDisposition) => self.policy_disposition.patch(pointer, value),
            Some(Property::PolicySubdomainDisposition) => {
                self.policy_subdomain_disposition.patch(pointer, value)
            }
            Some(Property::PolicyTestingMode) => self.policy_testing_mode.patch(pointer, value),
            Some(Property::PolicyFailureReportingOptions) => {
                self.policy_failure_reporting_options.patch(pointer, value)
            }
            Some(Property::Records) => self.records.patch(pointer, value),
            Some(Property::Extensions) => self.extensions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcReportRecord {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.source_ip {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::SourceIp, value));
            }
        }
        let value = &self.policy_override_reasons;
        for value in value.values() {
            value.validate(errors);
        }
        if let Some(value) = &self.envelope_to {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EnvelopeTo));
            }
        }
        let value = &self.envelope_from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::EnvelopeFrom));
        }
        let value = &self.header_from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::HeaderFrom));
        }
        let value = &self.dkim_results;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.spf_results;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.extensions;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcReportRecord {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.source_ip.pickle(out);
        self.count.pickle(out);
        self.evaluated_disposition.pickle(out);
        self.evaluated_dkim.pickle(out);
        self.evaluated_spf.pickle(out);
        self.policy_override_reasons.pickle(out);
        self.envelope_to.pickle(out);
        self.envelope_from.pickle(out);
        self.header_from.pickle(out);
        self.dkim_results.pickle(out);
        self.spf_results.pickle(out);
        self.extensions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.source_ip = Pickle::unpickle(stream)?;
        this.count = Pickle::unpickle(stream)?;
        this.evaluated_disposition = Pickle::unpickle(stream)?;
        this.evaluated_dkim = Pickle::unpickle(stream)?;
        this.evaluated_spf = Pickle::unpickle(stream)?;
        this.policy_override_reasons = Pickle::unpickle(stream)?;
        this.envelope_to = Pickle::unpickle(stream)?;
        this.envelope_from = Pickle::unpickle(stream)?;
        this.header_from = Pickle::unpickle(stream)?;
        this.dkim_results = Pickle::unpickle(stream)?;
        this.spf_results = Pickle::unpickle(stream)?;
        this.extensions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcReportRecord {
    fn default() -> Self {
        Self {
            source_ip: Default::default(),
            count: 0u64,
            evaluated_disposition: Default::default(),
            evaluated_dkim: Default::default(),
            evaluated_spf: Default::default(),
            policy_override_reasons: Default::default(),
            envelope_to: Default::default(),
            envelope_from: Default::default(),
            header_from: Default::default(),
            dkim_results: Default::default(),
            spf_results: Default::default(),
            extensions: Default::default(),
        }
    }
}

impl IntoValue for DmarcReportRecord {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::SourceIp, self.source_ip.into_value());
        map.insert_unchecked(Property::Count, self.count.into_value());
        map.insert_unchecked(
            Property::EvaluatedDisposition,
            self.evaluated_disposition.into_value(),
        );
        map.insert_unchecked(Property::EvaluatedDkim, self.evaluated_dkim.into_value());
        map.insert_unchecked(Property::EvaluatedSpf, self.evaluated_spf.into_value());
        map.insert_unchecked(
            Property::PolicyOverrideReasons,
            self.policy_override_reasons.into_value(),
        );
        map.insert_unchecked(Property::EnvelopeTo, self.envelope_to.into_value());
        map.insert_unchecked(Property::EnvelopeFrom, self.envelope_from.into_value());
        map.insert_unchecked(Property::HeaderFrom, self.header_from.into_value());
        map.insert_unchecked(Property::DkimResults, self.dkim_results.into_value());
        map.insert_unchecked(Property::SpfResults, self.spf_results.into_value());
        map.insert_unchecked(Property::Extensions, self.extensions.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcReportRecord {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::SourceIp) => self.source_ip.patch(pointer, value),
            Some(Property::Count) => self.count.patch(pointer, value),
            Some(Property::EvaluatedDisposition) => {
                self.evaluated_disposition.patch(pointer, value)
            }
            Some(Property::EvaluatedDkim) => self.evaluated_dkim.patch(pointer, value),
            Some(Property::EvaluatedSpf) => self.evaluated_spf.patch(pointer, value),
            Some(Property::PolicyOverrideReasons) => {
                self.policy_override_reasons.patch(pointer, value)
            }
            Some(Property::EnvelopeTo) => self.envelope_to.patch(pointer, value),
            Some(Property::EnvelopeFrom) => self.envelope_from.patch(pointer, value),
            Some(Property::HeaderFrom) => self.header_from.patch(pointer, value),
            Some(Property::DkimResults) => self.dkim_results.patch(pointer, value),
            Some(Property::SpfResults) => self.spf_results.patch(pointer, value),
            Some(Property::Extensions) => self.extensions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DmarcReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DmarcReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.aggregate_contact_info;
        value.validate(errors);
        let value = &self.aggregate_from_address;
        value.validate(errors);
        let value = &self.aggregate_from_name;
        value.validate(errors);
        let value = &self.aggregate_max_report_size;
        value.validate(errors);
        let value = &self.aggregate_org_name;
        value.validate(errors);
        let value = &self.aggregate_send_frequency;
        value.validate(errors);
        let value = &self.aggregate_dkim_sign_domain;
        value.validate(errors);
        let value = &self.aggregate_subject;
        value.validate(errors);
        let value = &self.failure_from_address;
        value.validate(errors);
        let value = &self.failure_from_name;
        value.validate(errors);
        let value = &self.failure_send_frequency;
        value.validate(errors);
        let value = &self.failure_dkim_sign_domain;
        value.validate(errors);
        let value = &self.failure_subject;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl DmarcReportSettings {
    pub fn ctx_aggregate_contact_info(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_contact_info,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateContactInfo,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_from_address,
            default: Some(Expression {
                else_: "'noreply-dmarc@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateFromAddress,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_from_name,
            default: Some(Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateFromName,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_max_report_size(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_max_report_size,
            default: Some(Expression {
                else_: "5242880".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateMaxReportSize,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_org_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_org_name,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateOrgName,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_send_frequency(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_send_frequency,
            default: Some(Expression {
                else_: "daily".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateSendFrequency,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: MTA_AGGREGATE_CONSTANT,
        }
    }

    pub fn ctx_aggregate_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateDkimSignDomain,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_aggregate_subject(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.aggregate_subject,
            default: Some(Expression {
                else_: "'DMARC Aggregate Report'".to_string(),
                ..Default::default()
            }),
            property: Property::AggregateSubject,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_failure_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.failure_from_address,
            default: Some(Expression {
                else_: "'noreply-dmarc@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FailureFromAddress,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_failure_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.failure_from_name,
            default: Some(Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::FailureFromName,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_failure_send_frequency(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.failure_send_frequency,
            default: Some(Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            }),
            property: Property::FailureSendFrequency,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_failure_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.failure_dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FailureDkimSignDomain,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_failure_subject(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.failure_subject,
            default: Some(Expression {
                else_: "'DMARC Authentication Failure Report'".to_string(),
                ..Default::default()
            }),
            property: Property::FailureSubject,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_aggregate_contact_info(),
            self.ctx_aggregate_from_address(),
            self.ctx_aggregate_from_name(),
            self.ctx_aggregate_max_report_size(),
            self.ctx_aggregate_org_name(),
            self.ctx_aggregate_send_frequency(),
            self.ctx_aggregate_dkim_sign_domain(),
            self.ctx_aggregate_subject(),
            self.ctx_failure_from_address(),
            self.ctx_failure_from_name(),
            self.ctx_failure_send_frequency(),
            self.ctx_failure_dkim_sign_domain(),
            self.ctx_failure_subject(),
        ]
    }
}

impl Pickle for DmarcReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.aggregate_contact_info.pickle(out);
        self.aggregate_from_address.pickle(out);
        self.aggregate_from_name.pickle(out);
        self.aggregate_max_report_size.pickle(out);
        self.aggregate_org_name.pickle(out);
        self.aggregate_send_frequency.pickle(out);
        self.aggregate_dkim_sign_domain.pickle(out);
        self.aggregate_subject.pickle(out);
        self.failure_from_address.pickle(out);
        self.failure_from_name.pickle(out);
        self.failure_send_frequency.pickle(out);
        self.failure_dkim_sign_domain.pickle(out);
        self.failure_subject.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.aggregate_contact_info = Pickle::unpickle(stream)?;
        this.aggregate_from_address = Pickle::unpickle(stream)?;
        this.aggregate_from_name = Pickle::unpickle(stream)?;
        this.aggregate_max_report_size = Pickle::unpickle(stream)?;
        this.aggregate_org_name = Pickle::unpickle(stream)?;
        this.aggregate_send_frequency = Pickle::unpickle(stream)?;
        this.aggregate_dkim_sign_domain = Pickle::unpickle(stream)?;
        this.aggregate_subject = Pickle::unpickle(stream)?;
        this.failure_from_address = Pickle::unpickle(stream)?;
        this.failure_from_name = Pickle::unpickle(stream)?;
        this.failure_send_frequency = Pickle::unpickle(stream)?;
        this.failure_dkim_sign_domain = Pickle::unpickle(stream)?;
        this.failure_subject = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcReportSettings {
    fn default() -> Self {
        Self {
            aggregate_contact_info: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
            aggregate_from_address: Expression {
                else_: "'noreply-dmarc@' + system('domain')".to_string(),
                ..Default::default()
            },
            aggregate_from_name: Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            },
            aggregate_max_report_size: Expression {
                else_: "5242880".to_string(),
                ..Default::default()
            },
            aggregate_org_name: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            aggregate_send_frequency: Expression {
                else_: "daily".to_string(),
                ..Default::default()
            },
            aggregate_dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            aggregate_subject: Expression {
                else_: "'DMARC Aggregate Report'".to_string(),
                ..Default::default()
            },
            failure_from_address: Expression {
                else_: "'noreply-dmarc@' + system('domain')".to_string(),
                ..Default::default()
            },
            failure_from_name: Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            },
            failure_send_frequency: Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            },
            failure_dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            failure_subject: Expression {
                else_: "'DMARC Authentication Failure Report'".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for DmarcReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(
            Property::AggregateContactInfo,
            self.aggregate_contact_info.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateFromAddress,
            self.aggregate_from_address.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateFromName,
            self.aggregate_from_name.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateMaxReportSize,
            self.aggregate_max_report_size.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateOrgName,
            self.aggregate_org_name.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateSendFrequency,
            self.aggregate_send_frequency.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateDkimSignDomain,
            self.aggregate_dkim_sign_domain.into_value(),
        );
        map.insert_unchecked(
            Property::AggregateSubject,
            self.aggregate_subject.into_value(),
        );
        map.insert_unchecked(
            Property::FailureFromAddress,
            self.failure_from_address.into_value(),
        );
        map.insert_unchecked(
            Property::FailureFromName,
            self.failure_from_name.into_value(),
        );
        map.insert_unchecked(
            Property::FailureSendFrequency,
            self.failure_send_frequency.into_value(),
        );
        map.insert_unchecked(
            Property::FailureDkimSignDomain,
            self.failure_dkim_sign_domain.into_value(),
        );
        map.insert_unchecked(Property::FailureSubject, self.failure_subject.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AggregateContactInfo) => {
                self.aggregate_contact_info.patch(pointer, value)
            }
            Some(Property::AggregateFromAddress) => {
                self.aggregate_from_address.patch(pointer, value)
            }
            Some(Property::AggregateFromName) => self.aggregate_from_name.patch(pointer, value),
            Some(Property::AggregateMaxReportSize) => {
                self.aggregate_max_report_size.patch(pointer, value)
            }
            Some(Property::AggregateOrgName) => self.aggregate_org_name.patch(pointer, value),
            Some(Property::AggregateSendFrequency) => {
                self.aggregate_send_frequency.patch(pointer, value)
            }
            Some(Property::AggregateDkimSignDomain) => {
                self.aggregate_dkim_sign_domain.patch(pointer, value)
            }
            Some(Property::AggregateSubject) => self.aggregate_subject.patch(pointer, value),
            Some(Property::FailureFromAddress) => self.failure_from_address.patch(pointer, value),
            Some(Property::FailureFromName) => self.failure_from_name.patch(pointer, value),
            Some(Property::FailureSendFrequency) => {
                self.failure_send_frequency.patch(pointer, value)
            }
            Some(Property::FailureDkimSignDomain) => {
                self.failure_dkim_sign_domain.patch(pointer, value)
            }
            Some(Property::FailureSubject) => self.failure_subject.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcSpfResult {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Domain));
        }
        if let Some(value) = &self.human_result {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HumanResult));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcSpfResult {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.domain.pickle(out);
        self.scope.pickle(out);
        self.result.pickle(out);
        self.human_result.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.domain = Pickle::unpickle(stream)?;
        this.scope = Pickle::unpickle(stream)?;
        this.result = Pickle::unpickle(stream)?;
        this.human_result = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcSpfResult {
    fn default() -> Self {
        Self {
            domain: Default::default(),
            scope: Default::default(),
            result: Default::default(),
            human_result: Default::default(),
        }
    }
}

impl IntoValue for DmarcSpfResult {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Domain, self.domain.into_value());
        map.insert_unchecked(Property::Scope, self.scope.into_value());
        map.insert_unchecked(Property::Result, self.result.into_value());
        map.insert_unchecked(Property::HumanResult, self.human_result.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcSpfResult {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Domain) => self
                .domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::Scope) => self.scope.patch(pointer, value),
            Some(Property::Result) => self.result.patch(pointer, value),
            Some(Property::HumanResult) => self.human_result.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcTroubleshoot {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.remote_ip;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::RemoteIp, value));
        }
        let value = &self.ehlo_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::EhloDomain));
        }
        let value = &self.mail_from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::MailFrom));
        }
        if let Some(value) = &self.message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Message));
            }
        }
        let value = &self.spf_ehlo_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::SpfEhloDomain));
        }
        let value = &self.spf_ehlo_result;
        value.validate(errors);
        let value = &self.spf_mail_from_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::SpfMailFromDomain));
        }
        let value = &self.spf_mail_from_result;
        value.validate(errors);
        let value = &self.ip_rev_result;
        value.validate(errors);
        let value = &self.ip_rev_ptr;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::IpRevPtr));
            }
        }
        let value = &self.dkim_results;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.arc_result;
        value.validate(errors);
        let value = &self.dmarc_result;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for DmarcTroubleshoot {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.remote_ip.pickle(out);
        self.ehlo_domain.pickle(out);
        self.mail_from.pickle(out);
        self.message.pickle(out);
        self.spf_ehlo_domain.pickle(out);
        self.spf_ehlo_result.pickle(out);
        self.spf_mail_from_domain.pickle(out);
        self.spf_mail_from_result.pickle(out);
        self.ip_rev_result.pickle(out);
        self.ip_rev_ptr.pickle(out);
        self.dkim_results.pickle(out);
        self.dkim_pass.pickle(out);
        self.arc_result.pickle(out);
        self.dmarc_result.pickle(out);
        self.dmarc_pass.pickle(out);
        self.dmarc_policy.pickle(out);
        self.elapsed.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.remote_ip = Pickle::unpickle(stream)?;
        this.ehlo_domain = Pickle::unpickle(stream)?;
        this.mail_from = Pickle::unpickle(stream)?;
        this.message = Pickle::unpickle(stream)?;
        this.spf_ehlo_domain = Pickle::unpickle(stream)?;
        this.spf_ehlo_result = Pickle::unpickle(stream)?;
        this.spf_mail_from_domain = Pickle::unpickle(stream)?;
        this.spf_mail_from_result = Pickle::unpickle(stream)?;
        this.ip_rev_result = Pickle::unpickle(stream)?;
        this.ip_rev_ptr = Pickle::unpickle(stream)?;
        this.dkim_results = Pickle::unpickle(stream)?;
        this.dkim_pass = Pickle::unpickle(stream)?;
        this.arc_result = Pickle::unpickle(stream)?;
        this.dmarc_result = Pickle::unpickle(stream)?;
        this.dmarc_pass = Pickle::unpickle(stream)?;
        this.dmarc_policy = Pickle::unpickle(stream)?;
        this.elapsed = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcTroubleshoot {
    fn default() -> Self {
        Self {
            remote_ip: Default::default(),
            ehlo_domain: Default::default(),
            mail_from: Default::default(),
            message: Default::default(),
            spf_ehlo_domain: Default::default(),
            spf_ehlo_result: Default::default(),
            spf_mail_from_domain: Default::default(),
            spf_mail_from_result: Default::default(),
            ip_rev_result: Default::default(),
            ip_rev_ptr: Default::default(),
            dkim_results: Default::default(),
            dkim_pass: false,
            arc_result: Default::default(),
            dmarc_result: Default::default(),
            dmarc_pass: false,
            dmarc_policy: Default::default(),
            elapsed: Duration::from_millis(0),
        }
    }
}

impl IntoValue for DmarcTroubleshoot {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(19);
        map.insert_unchecked(Property::RemoteIp, self.remote_ip.into_value());
        map.insert_unchecked(Property::EhloDomain, self.ehlo_domain.into_value());
        map.insert_unchecked(Property::MailFrom, self.mail_from.into_value());
        map.insert_unchecked(Property::Message, self.message.into_value());
        map.insert_unchecked(Property::SpfEhloDomain, self.spf_ehlo_domain.into_value());
        map.insert_unchecked(Property::SpfEhloResult, self.spf_ehlo_result.into_value());
        map.insert_unchecked(
            Property::SpfMailFromDomain,
            self.spf_mail_from_domain.into_value(),
        );
        map.insert_unchecked(
            Property::SpfMailFromResult,
            self.spf_mail_from_result.into_value(),
        );
        map.insert_unchecked(Property::IpRevResult, self.ip_rev_result.into_value());
        map.insert_unchecked(Property::IpRevPtr, self.ip_rev_ptr.into_value());
        map.insert_unchecked(Property::DkimResults, self.dkim_results.into_value());
        map.insert_unchecked(Property::DkimPass, self.dkim_pass.into_value());
        map.insert_unchecked(Property::ArcResult, self.arc_result.into_value());
        map.insert_unchecked(Property::DmarcResult, self.dmarc_result.into_value());
        map.insert_unchecked(Property::DmarcPass, self.dmarc_pass.into_value());
        map.insert_unchecked(Property::DmarcPolicy, self.dmarc_policy.into_value());
        map.insert_unchecked(Property::Elapsed, self.elapsed.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcTroubleshoot {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::RemoteIp) => self.remote_ip.patch(pointer, value),
            Some(Property::EhloDomain) => self.ehlo_domain.patch(pointer, value),
            Some(Property::MailFrom) => self
                .mail_from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Message) => self.message.patch(pointer, value),
            Some(Property::SpfEhloDomain) => self.spf_ehlo_domain.patch(pointer, value),
            Some(Property::SpfEhloResult) => pointer.assert_server_set(),
            Some(Property::SpfMailFromDomain) => self.spf_mail_from_domain.patch(pointer, value),
            Some(Property::SpfMailFromResult) => pointer.assert_server_set(),
            Some(Property::IpRevResult) => pointer.assert_server_set(),
            Some(Property::IpRevPtr) => pointer.assert_server_set(),
            Some(Property::DkimResults) => pointer.assert_server_set(),
            Some(Property::DkimPass) => pointer.assert_server_set(),
            Some(Property::ArcResult) => pointer.assert_server_set(),
            Some(Property::DmarcResult) => pointer.assert_server_set(),
            Some(Property::DmarcPass) => pointer.assert_server_set(),
            Some(Property::DmarcPolicy) => pointer.assert_server_set(),
            Some(Property::Elapsed) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DmarcTroubleshootAuthResult {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DmarcTroubleshootAuthResult::Pass => true,
            DmarcTroubleshootAuthResult::Fail(inner) => inner.validate(errors),
            DmarcTroubleshootAuthResult::SoftFail(inner) => inner.validate(errors),
            DmarcTroubleshootAuthResult::TempError(inner) => inner.validate(errors),
            DmarcTroubleshootAuthResult::PermError(inner) => inner.validate(errors),
            DmarcTroubleshootAuthResult::Neutral(inner) => inner.validate(errors),
            DmarcTroubleshootAuthResult::None => true,
        }
    }
}

impl Default for DmarcTroubleshootAuthResult {
    fn default() -> Self {
        DmarcTroubleshootAuthResult::Pass
    }
}

impl Pickle for DmarcTroubleshootAuthResult {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DmarcTroubleshootAuthResult::Pass => {
                0u16.pickle(out);
            }
            DmarcTroubleshootAuthResult::Fail(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            DmarcTroubleshootAuthResult::SoftFail(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            DmarcTroubleshootAuthResult::TempError(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            DmarcTroubleshootAuthResult::PermError(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            DmarcTroubleshootAuthResult::Neutral(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            DmarcTroubleshootAuthResult::None => {
                6u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(DmarcTroubleshootAuthResult::Pass),
            1 => Pickle::unpickle(stream).map(DmarcTroubleshootAuthResult::Fail),
            2 => Pickle::unpickle(stream).map(DmarcTroubleshootAuthResult::SoftFail),
            3 => Pickle::unpickle(stream).map(DmarcTroubleshootAuthResult::TempError),
            4 => Pickle::unpickle(stream).map(DmarcTroubleshootAuthResult::PermError),
            5 => Pickle::unpickle(stream).map(DmarcTroubleshootAuthResult::Neutral),
            6 => Some(DmarcTroubleshootAuthResult::None),
            _ => None,
        }
    }
}

impl IntoValue for DmarcTroubleshootAuthResult {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DmarcTroubleshootAuthResult::Pass => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Pass".into()));
                JmapValue::Object(obj)
            }
            DmarcTroubleshootAuthResult::Fail(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Fail".into()));
                obj
            }
            DmarcTroubleshootAuthResult::SoftFail(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("SoftFail".into()));
                obj
            }
            DmarcTroubleshootAuthResult::TempError(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TempError".into()));
                obj
            }
            DmarcTroubleshootAuthResult::PermError(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PermError".into()));
                obj
            }
            DmarcTroubleshootAuthResult::Neutral(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Neutral".into()));
                obj
            }
            DmarcTroubleshootAuthResult::None => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("None".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for DmarcTroubleshootAuthResult {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DmarcTroubleshootAuthResultType::Pass => *self = DmarcTroubleshootAuthResult::Pass,
                DmarcTroubleshootAuthResultType::Fail => {
                    *self = DmarcTroubleshootAuthResult::Fail(Default::default())
                }
                DmarcTroubleshootAuthResultType::SoftFail => {
                    *self = DmarcTroubleshootAuthResult::SoftFail(Default::default())
                }
                DmarcTroubleshootAuthResultType::TempError => {
                    *self = DmarcTroubleshootAuthResult::TempError(Default::default())
                }
                DmarcTroubleshootAuthResultType::PermError => {
                    *self = DmarcTroubleshootAuthResult::PermError(Default::default())
                }
                DmarcTroubleshootAuthResultType::Neutral => {
                    *self = DmarcTroubleshootAuthResult::Neutral(Default::default())
                }
                DmarcTroubleshootAuthResultType::None => *self = DmarcTroubleshootAuthResult::None,
            }
        }
        match self {
            DmarcTroubleshootAuthResult::Pass => pointer.assert_eof(),
            DmarcTroubleshootAuthResult::Fail(inner) => inner.patch(pointer, value),
            DmarcTroubleshootAuthResult::SoftFail(inner) => inner.patch(pointer, value),
            DmarcTroubleshootAuthResult::TempError(inner) => inner.patch(pointer, value),
            DmarcTroubleshootAuthResult::PermError(inner) => inner.patch(pointer, value),
            DmarcTroubleshootAuthResult::Neutral(inner) => inner.patch(pointer, value),
            DmarcTroubleshootAuthResult::None => pointer.assert_eof(),
        }
    }
}

impl DmarcTroubleshootAuthResult {
    pub fn object_type(&self) -> DmarcTroubleshootAuthResultType {
        match self {
            DmarcTroubleshootAuthResult::Pass => DmarcTroubleshootAuthResultType::Pass,
            DmarcTroubleshootAuthResult::Fail(_) => DmarcTroubleshootAuthResultType::Fail,
            DmarcTroubleshootAuthResult::SoftFail(_) => DmarcTroubleshootAuthResultType::SoftFail,
            DmarcTroubleshootAuthResult::TempError(_) => DmarcTroubleshootAuthResultType::TempError,
            DmarcTroubleshootAuthResult::PermError(_) => DmarcTroubleshootAuthResultType::PermError,
            DmarcTroubleshootAuthResult::Neutral(_) => DmarcTroubleshootAuthResultType::Neutral,
            DmarcTroubleshootAuthResult::None => DmarcTroubleshootAuthResultType::None,
        }
    }
}

impl DmarcTroubleshootDetails {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.details {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Details));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for DmarcTroubleshootDetails {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.details.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.details = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DmarcTroubleshootDetails {
    fn default() -> Self {
        Self {
            details: Default::default(),
        }
    }
}

impl IntoValue for DmarcTroubleshootDetails {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Details, self.details.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DmarcTroubleshootDetails {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Details) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsCustomResolver {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.address;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Address, value));
        }
        let value = &self.port;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        errors.len() == neb
    }
}

impl Pickle for DnsCustomResolver {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.protocol.pickle(out);
        self.address.pickle(out);
        self.port.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.protocol = Pickle::unpickle(stream)?;
        this.address = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsCustomResolver {
    fn default() -> Self {
        Self {
            protocol: DnsResolverProtocol::Udp,
            address: IpAddr::from_str("127.0.0.1").unwrap(),
            port: 53u64,
        }
    }
}

impl IntoValue for DnsCustomResolver {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Protocol, self.protocol.into_value());
        map.insert_unchecked(Property::Address, self.address.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsCustomResolver {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Protocol) => self.protocol.patch(pointer, value),
            Some(Property::Address) => self
                .address
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsManagement {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DnsManagement::Manual => true,
            DnsManagement::Automatic(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            DnsManagement::Manual => {}
            DnsManagement::Automatic(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for DnsManagement {
    fn default() -> Self {
        DnsManagement::Manual
    }
}

impl Pickle for DnsManagement {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DnsManagement::Manual => {
                0u16.pickle(out);
            }
            DnsManagement::Automatic(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(DnsManagement::Manual),
            1 => Pickle::unpickle(stream).map(DnsManagement::Automatic),
            _ => None,
        }
    }
}

impl IntoValue for DnsManagement {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DnsManagement::Manual => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Manual".into()));
                JmapValue::Object(obj)
            }
            DnsManagement::Automatic(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Automatic".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DnsManagement {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DnsManagementType::Manual => *self = DnsManagement::Manual,
                DnsManagementType::Automatic => {
                    *self = DnsManagement::Automatic(Default::default())
                }
            }
        }
        match self {
            DnsManagement::Manual => pointer.assert_eof(),
            DnsManagement::Automatic(inner) => inner.patch(pointer, value),
        }
    }
}

impl DnsManagement {
    pub fn object_type(&self) -> DnsManagementType {
        match self {
            DnsManagement::Manual => DnsManagementType::Manual,
            DnsManagement::Automatic(_) => DnsManagementType::Automatic,
        }
    }
}

impl DnsManagementProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.dns_server_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DnsServerId));
        }
        if let Some(value) = &self.origin {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Origin));
            }
        }
        let value = &self.publish_records;
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::PublishRecords, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::DnsServer, self.dns_server_id.into(), None);
    }
}

impl Pickle for DnsManagementProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.dns_server_id.pickle(out);
        self.origin.pickle(out);
        self.publish_records.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.dns_server_id = Pickle::unpickle(stream)?;
        this.origin = Pickle::unpickle(stream)?;
        this.publish_records = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsManagementProperties {
    fn default() -> Self {
        Self {
            dns_server_id: Default::default(),
            origin: Default::default(),
            publish_records: Map::new(vec![
                DnsRecordType::Dkim,
                DnsRecordType::Spf,
                DnsRecordType::Mx,
                DnsRecordType::Dmarc,
                DnsRecordType::Srv,
                DnsRecordType::MtaSts,
                DnsRecordType::TlsRpt,
                DnsRecordType::Caa,
                DnsRecordType::AutoConfig,
                DnsRecordType::AutoConfigLegacy,
                DnsRecordType::AutoDiscover,
            ]),
        }
    }
}

impl IntoValue for DnsManagementProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::DnsServerId, self.dns_server_id.into_value());
        map.insert_unchecked(Property::Origin, self.origin.into_value());
        map.insert_unchecked(Property::PublishRecords, self.publish_records.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsManagementProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DnsServerId) => self.dns_server_id.patch(pointer, value),
            Some(Property::Origin) => self
                .origin
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PublishRecords) => self.publish_records.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DnsResolver {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DnsResolver;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DnsResolver::System(inner) => inner.validate(errors),
            DnsResolver::Custom(inner) => inner.validate(errors),
            DnsResolver::Cloudflare(inner) => inner.validate(errors),
            DnsResolver::Quad9(inner) => inner.validate(errors),
            DnsResolver::Google(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for DnsResolver {
    fn default() -> Self {
        DnsResolver::System(Default::default())
    }
}

impl Pickle for DnsResolver {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DnsResolver::System(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            DnsResolver::Custom(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            DnsResolver::Cloudflare(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            DnsResolver::Quad9(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            DnsResolver::Google(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(DnsResolver::System),
            1 => Pickle::unpickle(stream).map(DnsResolver::Custom),
            2 => Pickle::unpickle(stream).map(DnsResolver::Cloudflare),
            3 => Pickle::unpickle(stream).map(DnsResolver::Quad9),
            4 => Pickle::unpickle(stream).map(DnsResolver::Google),
            _ => None,
        }
    }
}

impl IntoValue for DnsResolver {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DnsResolver::System(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("System".into()));
                obj
            }
            DnsResolver::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
            DnsResolver::Cloudflare(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Cloudflare".into()));
                obj
            }
            DnsResolver::Quad9(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Quad9".into()));
                obj
            }
            DnsResolver::Google(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Google".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DnsResolver {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DnsResolverType::System => *self = DnsResolver::System(Default::default()),
                DnsResolverType::Custom => *self = DnsResolver::Custom(Default::default()),
                DnsResolverType::Cloudflare => *self = DnsResolver::Cloudflare(Default::default()),
                DnsResolverType::Quad9 => *self = DnsResolver::Quad9(Default::default()),
                DnsResolverType::Google => *self = DnsResolver::Google(Default::default()),
            }
        }
        match self {
            DnsResolver::System(inner) => inner.patch(pointer, value),
            DnsResolver::Custom(inner) => inner.patch(pointer, value),
            DnsResolver::Cloudflare(inner) => inner.patch(pointer, value),
            DnsResolver::Quad9(inner) => inner.patch(pointer, value),
            DnsResolver::Google(inner) => inner.patch(pointer, value),
        }
    }
}

impl DnsResolver {
    pub fn object_type(&self) -> DnsResolverType {
        match self {
            DnsResolver::System(_) => DnsResolverType::System,
            DnsResolver::Custom(_) => DnsResolverType::Custom,
            DnsResolver::Cloudflare(_) => DnsResolverType::Cloudflare,
            DnsResolver::Quad9(_) => DnsResolverType::Quad9,
            DnsResolver::Google(_) => DnsResolverType::Google,
        }
    }
}

impl DnsResolverCommon {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for DnsResolverCommon {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.attempts.pickle(out);
        self.concurrency.pickle(out);
        self.enable_edns.pickle(out);
        self.preserve_intermediates.pickle(out);
        self.timeout.pickle(out);
        self.tcp_on_error.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.attempts = Pickle::unpickle(stream)?;
        this.concurrency = Pickle::unpickle(stream)?;
        this.enable_edns = Pickle::unpickle(stream)?;
        this.preserve_intermediates = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.tcp_on_error = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsResolverCommon {
    fn default() -> Self {
        Self {
            attempts: 2u64,
            concurrency: 2u64,
            enable_edns: true,
            preserve_intermediates: true,
            timeout: Duration::from_millis(5000),
            tcp_on_error: true,
        }
    }
}

impl IntoValue for DnsResolverCommon {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Attempts, self.attempts.into_value());
        map.insert_unchecked(Property::Concurrency, self.concurrency.into_value());
        map.insert_unchecked(Property::EnableEdns, self.enable_edns.into_value());
        map.insert_unchecked(
            Property::PreserveIntermediates,
            self.preserve_intermediates.into_value(),
        );
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::TcpOnError, self.tcp_on_error.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsResolverCommon {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Attempts) => self.attempts.patch(pointer, value),
            Some(Property::Concurrency) => self.concurrency.patch(pointer, value),
            Some(Property::EnableEdns) => self.enable_edns.patch(pointer, value),
            Some(Property::PreserveIntermediates) => {
                self.preserve_intermediates.patch(pointer, value)
            }
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::TcpOnError) => self.tcp_on_error.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsResolverCustom {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.servers;
        for value in value.values() {
            value.validate(errors);
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Servers, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for DnsResolverCustom {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.servers.pickle(out);
        self.attempts.pickle(out);
        self.concurrency.pickle(out);
        self.enable_edns.pickle(out);
        self.preserve_intermediates.pickle(out);
        self.timeout.pickle(out);
        self.tcp_on_error.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.servers = Pickle::unpickle(stream)?;
        this.attempts = Pickle::unpickle(stream)?;
        this.concurrency = Pickle::unpickle(stream)?;
        this.enable_edns = Pickle::unpickle(stream)?;
        this.preserve_intermediates = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.tcp_on_error = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsResolverCustom {
    fn default() -> Self {
        Self {
            servers: Default::default(),
            attempts: 2u64,
            concurrency: 2u64,
            enable_edns: true,
            preserve_intermediates: true,
            timeout: Duration::from_millis(5000),
            tcp_on_error: true,
        }
    }
}

impl IntoValue for DnsResolverCustom {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Servers, self.servers.into_value());
        map.insert_unchecked(Property::Attempts, self.attempts.into_value());
        map.insert_unchecked(Property::Concurrency, self.concurrency.into_value());
        map.insert_unchecked(Property::EnableEdns, self.enable_edns.into_value());
        map.insert_unchecked(
            Property::PreserveIntermediates,
            self.preserve_intermediates.into_value(),
        );
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::TcpOnError, self.tcp_on_error.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsResolverCustom {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Servers) => self.servers.patch(pointer, value),
            Some(Property::Attempts) => self.attempts.patch(pointer, value),
            Some(Property::Concurrency) => self.concurrency.patch(pointer, value),
            Some(Property::EnableEdns) => self.enable_edns.patch(pointer, value),
            Some(Property::PreserveIntermediates) => {
                self.preserve_intermediates.patch(pointer, value)
            }
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::TcpOnError) => self.tcp_on_error.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsResolverTls {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for DnsResolverTls {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.use_tls.pickle(out);
        self.attempts.pickle(out);
        self.concurrency.pickle(out);
        self.enable_edns.pickle(out);
        self.preserve_intermediates.pickle(out);
        self.timeout.pickle(out);
        self.tcp_on_error.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.use_tls = Pickle::unpickle(stream)?;
        this.attempts = Pickle::unpickle(stream)?;
        this.concurrency = Pickle::unpickle(stream)?;
        this.enable_edns = Pickle::unpickle(stream)?;
        this.preserve_intermediates = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.tcp_on_error = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsResolverTls {
    fn default() -> Self {
        Self {
            use_tls: true,
            attempts: 2u64,
            concurrency: 2u64,
            enable_edns: true,
            preserve_intermediates: true,
            timeout: Duration::from_millis(5000),
            tcp_on_error: true,
        }
    }
}

impl IntoValue for DnsResolverTls {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(Property::Attempts, self.attempts.into_value());
        map.insert_unchecked(Property::Concurrency, self.concurrency.into_value());
        map.insert_unchecked(Property::EnableEdns, self.enable_edns.into_value());
        map.insert_unchecked(
            Property::PreserveIntermediates,
            self.preserve_intermediates.into_value(),
        );
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::TcpOnError, self.tcp_on_error.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsResolverTls {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::Attempts) => self.attempts.patch(pointer, value),
            Some(Property::Concurrency) => self.concurrency.patch(pointer, value),
            Some(Property::EnableEdns) => self.enable_edns.patch(pointer, value),
            Some(Property::PreserveIntermediates) => {
                self.preserve_intermediates.patch(pointer, value)
            }
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::TcpOnError) => self.tcp_on_error.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DnsServer {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 1;
    const OBJECT: ObjectType = ObjectType::DnsServer;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DnsServer::Tsig(inner) => inner.validate(errors),
            DnsServer::Deprecated1 => true,
            DnsServer::Cloudflare(inner) => inner.validate(errors),
            DnsServer::DigitalOcean(inner) => inner.validate(errors),
            DnsServer::DeSEC(inner) => inner.validate(errors),
            DnsServer::Ovh(inner) => inner.validate(errors),
            DnsServer::Bunny(inner) => inner.validate(errors),
            DnsServer::Porkbun(inner) => inner.validate(errors),
            DnsServer::Dnsimple(inner) => inner.validate(errors),
            DnsServer::Spaceship(inner) => inner.validate(errors),
            DnsServer::Route53(inner) => inner.validate(errors),
            DnsServer::GoogleCloudDns(inner) => inner.validate(errors),
            DnsServer::Alidns(inner) => inner.validate(errors),
            DnsServer::ArvanCloud(inner) => inner.validate(errors),
            DnsServer::Autodns(inner) => inner.validate(errors),
            DnsServer::AzureDns(inner) => inner.validate(errors),
            DnsServer::BaiduCloud(inner) => inner.validate(errors),
            DnsServer::BluecatV2(inner) => inner.validate(errors),
            DnsServer::ClouDns(inner) => inner.validate(errors),
            DnsServer::Constellix(inner) => inner.validate(errors),
            DnsServer::Cpanel(inner) => inner.validate(errors),
            DnsServer::Ddnss(inner) => inner.validate(errors),
            DnsServer::DnsMadeEasy(inner) => inner.validate(errors),
            DnsServer::Domeneshop(inner) => inner.validate(errors),
            DnsServer::Dreamhost(inner) => inner.validate(errors),
            DnsServer::DuckDns(inner) => inner.validate(errors),
            DnsServer::Dynu(inner) => inner.validate(errors),
            DnsServer::EasyDns(inner) => inner.validate(errors),
            DnsServer::EdgeDns(inner) => inner.validate(errors),
            DnsServer::Exoscale(inner) => inner.validate(errors),
            DnsServer::FreeMyIp(inner) => inner.validate(errors),
            DnsServer::GandiV5(inner) => inner.validate(errors),
            DnsServer::Gcore(inner) => inner.validate(errors),
            DnsServer::Glesys(inner) => inner.validate(errors),
            DnsServer::Godaddy(inner) => inner.validate(errors),
            DnsServer::Hetzner(inner) => inner.validate(errors),
            DnsServer::HostingDe(inner) => inner.validate(errors),
            DnsServer::Hostinger(inner) => inner.validate(errors),
            DnsServer::HuaweiCloud(inner) => inner.validate(errors),
            DnsServer::Hurricane(inner) => inner.validate(errors),
            DnsServer::IbmCloud(inner) => inner.validate(errors),
            DnsServer::Infoblox(inner) => inner.validate(errors),
            DnsServer::Infomaniak(inner) => inner.validate(errors),
            DnsServer::Inwx(inner) => inner.validate(errors),
            DnsServer::Ionos(inner) => inner.validate(errors),
            DnsServer::Ipv64(inner) => inner.validate(errors),
            DnsServer::Joker(inner) => inner.validate(errors),
            DnsServer::Lightsail(inner) => inner.validate(errors),
            DnsServer::Linode(inner) => inner.validate(errors),
            DnsServer::LuaDns(inner) => inner.validate(errors),
            DnsServer::MythicBeasts(inner) => inner.validate(errors),
            DnsServer::Namecheap(inner) => inner.validate(errors),
            DnsServer::NameDotCom(inner) => inner.validate(errors),
            DnsServer::NameSilo(inner) => inner.validate(errors),
            DnsServer::Netcup(inner) => inner.validate(errors),
            DnsServer::Netlify(inner) => inner.validate(errors),
            DnsServer::Nifcloud(inner) => inner.validate(errors),
            DnsServer::Ns1(inner) => inner.validate(errors),
            DnsServer::OracleCloud(inner) => inner.validate(errors),
            DnsServer::Plesk(inner) => inner.validate(errors),
            DnsServer::Safedns(inner) => inner.validate(errors),
            DnsServer::Scaleway(inner) => inner.validate(errors),
            DnsServer::TencentCloud(inner) => inner.validate(errors),
            DnsServer::Transip(inner) => inner.validate(errors),
            DnsServer::UltraDns(inner) => inner.validate(errors),
            DnsServer::Vercel(inner) => inner.validate(errors),
            DnsServer::Volcengine(inner) => inner.validate(errors),
            DnsServer::Vultr(inner) => inner.validate(errors),
            DnsServer::WebSupport(inner) => inner.validate(errors),
            DnsServer::YandexCloud(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            DnsServer::Tsig(object) => {
                object.index(i);
            }
            DnsServer::Deprecated1 => {}
            DnsServer::Cloudflare(object) => {
                object.index(i);
            }
            DnsServer::DigitalOcean(object) => {
                object.index(i);
            }
            DnsServer::DeSEC(object) => {
                object.index(i);
            }
            DnsServer::Ovh(object) => {
                object.index(i);
            }
            DnsServer::Bunny(object) => {
                object.index(i);
            }
            DnsServer::Porkbun(object) => {
                object.index(i);
            }
            DnsServer::Dnsimple(object) => {
                object.index(i);
            }
            DnsServer::Spaceship(object) => {
                object.index(i);
            }
            DnsServer::Route53(object) => {
                object.index(i);
            }
            DnsServer::GoogleCloudDns(object) => {
                object.index(i);
            }
            DnsServer::Alidns(object) => {
                object.index(i);
            }
            DnsServer::ArvanCloud(object) => {
                object.index(i);
            }
            DnsServer::Autodns(object) => {
                object.index(i);
            }
            DnsServer::AzureDns(object) => {
                object.index(i);
            }
            DnsServer::BaiduCloud(object) => {
                object.index(i);
            }
            DnsServer::BluecatV2(object) => {
                object.index(i);
            }
            DnsServer::ClouDns(object) => {
                object.index(i);
            }
            DnsServer::Constellix(object) => {
                object.index(i);
            }
            DnsServer::Cpanel(object) => {
                object.index(i);
            }
            DnsServer::Ddnss(object) => {
                object.index(i);
            }
            DnsServer::DnsMadeEasy(object) => {
                object.index(i);
            }
            DnsServer::Domeneshop(object) => {
                object.index(i);
            }
            DnsServer::Dreamhost(object) => {
                object.index(i);
            }
            DnsServer::DuckDns(object) => {
                object.index(i);
            }
            DnsServer::Dynu(object) => {
                object.index(i);
            }
            DnsServer::EasyDns(object) => {
                object.index(i);
            }
            DnsServer::EdgeDns(object) => {
                object.index(i);
            }
            DnsServer::Exoscale(object) => {
                object.index(i);
            }
            DnsServer::FreeMyIp(object) => {
                object.index(i);
            }
            DnsServer::GandiV5(object) => {
                object.index(i);
            }
            DnsServer::Gcore(object) => {
                object.index(i);
            }
            DnsServer::Glesys(object) => {
                object.index(i);
            }
            DnsServer::Godaddy(object) => {
                object.index(i);
            }
            DnsServer::Hetzner(object) => {
                object.index(i);
            }
            DnsServer::HostingDe(object) => {
                object.index(i);
            }
            DnsServer::Hostinger(object) => {
                object.index(i);
            }
            DnsServer::HuaweiCloud(object) => {
                object.index(i);
            }
            DnsServer::Hurricane(object) => {
                object.index(i);
            }
            DnsServer::IbmCloud(object) => {
                object.index(i);
            }
            DnsServer::Infoblox(object) => {
                object.index(i);
            }
            DnsServer::Infomaniak(object) => {
                object.index(i);
            }
            DnsServer::Inwx(object) => {
                object.index(i);
            }
            DnsServer::Ionos(object) => {
                object.index(i);
            }
            DnsServer::Ipv64(object) => {
                object.index(i);
            }
            DnsServer::Joker(object) => {
                object.index(i);
            }
            DnsServer::Lightsail(object) => {
                object.index(i);
            }
            DnsServer::Linode(object) => {
                object.index(i);
            }
            DnsServer::LuaDns(object) => {
                object.index(i);
            }
            DnsServer::MythicBeasts(object) => {
                object.index(i);
            }
            DnsServer::Namecheap(object) => {
                object.index(i);
            }
            DnsServer::NameDotCom(object) => {
                object.index(i);
            }
            DnsServer::NameSilo(object) => {
                object.index(i);
            }
            DnsServer::Netcup(object) => {
                object.index(i);
            }
            DnsServer::Netlify(object) => {
                object.index(i);
            }
            DnsServer::Nifcloud(object) => {
                object.index(i);
            }
            DnsServer::Ns1(object) => {
                object.index(i);
            }
            DnsServer::OracleCloud(object) => {
                object.index(i);
            }
            DnsServer::Plesk(object) => {
                object.index(i);
            }
            DnsServer::Safedns(object) => {
                object.index(i);
            }
            DnsServer::Scaleway(object) => {
                object.index(i);
            }
            DnsServer::TencentCloud(object) => {
                object.index(i);
            }
            DnsServer::Transip(object) => {
                object.index(i);
            }
            DnsServer::UltraDns(object) => {
                object.index(i);
            }
            DnsServer::Vercel(object) => {
                object.index(i);
            }
            DnsServer::Volcengine(object) => {
                object.index(i);
            }
            DnsServer::Vultr(object) => {
                object.index(i);
            }
            DnsServer::WebSupport(object) => {
                object.index(i);
            }
            DnsServer::YandexCloud(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for DnsServer {
    fn default() -> Self {
        DnsServer::Tsig(Default::default())
    }
}

impl Pickle for DnsServer {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DnsServer::Tsig(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Deprecated1 => {
                1u16.pickle(out);
            }
            DnsServer::Cloudflare(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::DigitalOcean(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::DeSEC(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Ovh(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Bunny(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Porkbun(inner) => {
                7u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Dnsimple(inner) => {
                8u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Spaceship(inner) => {
                9u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Route53(inner) => {
                10u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::GoogleCloudDns(inner) => {
                11u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Alidns(inner) => {
                12u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::ArvanCloud(inner) => {
                13u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Autodns(inner) => {
                14u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::AzureDns(inner) => {
                15u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::BaiduCloud(inner) => {
                16u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::BluecatV2(inner) => {
                17u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::ClouDns(inner) => {
                18u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Constellix(inner) => {
                19u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Cpanel(inner) => {
                20u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Ddnss(inner) => {
                21u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::DnsMadeEasy(inner) => {
                22u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Domeneshop(inner) => {
                23u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Dreamhost(inner) => {
                24u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::DuckDns(inner) => {
                25u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Dynu(inner) => {
                26u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::EasyDns(inner) => {
                27u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::EdgeDns(inner) => {
                28u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Exoscale(inner) => {
                29u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::FreeMyIp(inner) => {
                30u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::GandiV5(inner) => {
                31u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Gcore(inner) => {
                32u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Glesys(inner) => {
                33u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Godaddy(inner) => {
                34u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Hetzner(inner) => {
                35u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::HostingDe(inner) => {
                36u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Hostinger(inner) => {
                37u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::HuaweiCloud(inner) => {
                38u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Hurricane(inner) => {
                39u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::IbmCloud(inner) => {
                40u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Infoblox(inner) => {
                41u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Infomaniak(inner) => {
                42u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Inwx(inner) => {
                43u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Ionos(inner) => {
                44u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Ipv64(inner) => {
                45u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Joker(inner) => {
                46u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Lightsail(inner) => {
                47u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Linode(inner) => {
                48u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::LuaDns(inner) => {
                49u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::MythicBeasts(inner) => {
                50u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Namecheap(inner) => {
                51u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::NameDotCom(inner) => {
                52u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::NameSilo(inner) => {
                53u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Netcup(inner) => {
                54u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Netlify(inner) => {
                55u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Nifcloud(inner) => {
                56u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Ns1(inner) => {
                57u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::OracleCloud(inner) => {
                58u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Plesk(inner) => {
                59u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Safedns(inner) => {
                60u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Scaleway(inner) => {
                61u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::TencentCloud(inner) => {
                62u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Transip(inner) => {
                63u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::UltraDns(inner) => {
                64u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Vercel(inner) => {
                65u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Volcengine(inner) => {
                66u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::Vultr(inner) => {
                67u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::WebSupport(inner) => {
                68u16.pickle(out);
                inner.pickle(out);
            }
            DnsServer::YandexCloud(inner) => {
                69u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(DnsServer::Tsig),
            1 => Some(DnsServer::Deprecated1),
            2 => Pickle::unpickle(stream).map(DnsServer::Cloudflare),
            3 => Pickle::unpickle(stream).map(DnsServer::DigitalOcean),
            4 => Pickle::unpickle(stream).map(DnsServer::DeSEC),
            5 => Pickle::unpickle(stream).map(DnsServer::Ovh),
            6 => Pickle::unpickle(stream).map(DnsServer::Bunny),
            7 => Pickle::unpickle(stream).map(DnsServer::Porkbun),
            8 => Pickle::unpickle(stream).map(DnsServer::Dnsimple),
            9 => Pickle::unpickle(stream).map(DnsServer::Spaceship),
            10 => Pickle::unpickle(stream).map(DnsServer::Route53),
            11 => Pickle::unpickle(stream).map(DnsServer::GoogleCloudDns),
            12 => Pickle::unpickle(stream).map(DnsServer::Alidns),
            13 => Pickle::unpickle(stream).map(DnsServer::ArvanCloud),
            14 => Pickle::unpickle(stream).map(DnsServer::Autodns),
            15 => Pickle::unpickle(stream).map(DnsServer::AzureDns),
            16 => Pickle::unpickle(stream).map(DnsServer::BaiduCloud),
            17 => Pickle::unpickle(stream).map(DnsServer::BluecatV2),
            18 => Pickle::unpickle(stream).map(DnsServer::ClouDns),
            19 => Pickle::unpickle(stream).map(DnsServer::Constellix),
            20 => Pickle::unpickle(stream).map(DnsServer::Cpanel),
            21 => Pickle::unpickle(stream).map(DnsServer::Ddnss),
            22 => Pickle::unpickle(stream).map(DnsServer::DnsMadeEasy),
            23 => Pickle::unpickle(stream).map(DnsServer::Domeneshop),
            24 => Pickle::unpickle(stream).map(DnsServer::Dreamhost),
            25 => Pickle::unpickle(stream).map(DnsServer::DuckDns),
            26 => Pickle::unpickle(stream).map(DnsServer::Dynu),
            27 => Pickle::unpickle(stream).map(DnsServer::EasyDns),
            28 => Pickle::unpickle(stream).map(DnsServer::EdgeDns),
            29 => Pickle::unpickle(stream).map(DnsServer::Exoscale),
            30 => Pickle::unpickle(stream).map(DnsServer::FreeMyIp),
            31 => Pickle::unpickle(stream).map(DnsServer::GandiV5),
            32 => Pickle::unpickle(stream).map(DnsServer::Gcore),
            33 => Pickle::unpickle(stream).map(DnsServer::Glesys),
            34 => Pickle::unpickle(stream).map(DnsServer::Godaddy),
            35 => Pickle::unpickle(stream).map(DnsServer::Hetzner),
            36 => Pickle::unpickle(stream).map(DnsServer::HostingDe),
            37 => Pickle::unpickle(stream).map(DnsServer::Hostinger),
            38 => Pickle::unpickle(stream).map(DnsServer::HuaweiCloud),
            39 => Pickle::unpickle(stream).map(DnsServer::Hurricane),
            40 => Pickle::unpickle(stream).map(DnsServer::IbmCloud),
            41 => Pickle::unpickle(stream).map(DnsServer::Infoblox),
            42 => Pickle::unpickle(stream).map(DnsServer::Infomaniak),
            43 => Pickle::unpickle(stream).map(DnsServer::Inwx),
            44 => Pickle::unpickle(stream).map(DnsServer::Ionos),
            45 => Pickle::unpickle(stream).map(DnsServer::Ipv64),
            46 => Pickle::unpickle(stream).map(DnsServer::Joker),
            47 => Pickle::unpickle(stream).map(DnsServer::Lightsail),
            48 => Pickle::unpickle(stream).map(DnsServer::Linode),
            49 => Pickle::unpickle(stream).map(DnsServer::LuaDns),
            50 => Pickle::unpickle(stream).map(DnsServer::MythicBeasts),
            51 => Pickle::unpickle(stream).map(DnsServer::Namecheap),
            52 => Pickle::unpickle(stream).map(DnsServer::NameDotCom),
            53 => Pickle::unpickle(stream).map(DnsServer::NameSilo),
            54 => Pickle::unpickle(stream).map(DnsServer::Netcup),
            55 => Pickle::unpickle(stream).map(DnsServer::Netlify),
            56 => Pickle::unpickle(stream).map(DnsServer::Nifcloud),
            57 => Pickle::unpickle(stream).map(DnsServer::Ns1),
            58 => Pickle::unpickle(stream).map(DnsServer::OracleCloud),
            59 => Pickle::unpickle(stream).map(DnsServer::Plesk),
            60 => Pickle::unpickle(stream).map(DnsServer::Safedns),
            61 => Pickle::unpickle(stream).map(DnsServer::Scaleway),
            62 => Pickle::unpickle(stream).map(DnsServer::TencentCloud),
            63 => Pickle::unpickle(stream).map(DnsServer::Transip),
            64 => Pickle::unpickle(stream).map(DnsServer::UltraDns),
            65 => Pickle::unpickle(stream).map(DnsServer::Vercel),
            66 => Pickle::unpickle(stream).map(DnsServer::Volcengine),
            67 => Pickle::unpickle(stream).map(DnsServer::Vultr),
            68 => Pickle::unpickle(stream).map(DnsServer::WebSupport),
            69 => Pickle::unpickle(stream).map(DnsServer::YandexCloud),
            _ => None,
        }
    }
}

impl IntoValue for DnsServer {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DnsServer::Tsig(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Tsig".into()));
                obj
            }
            DnsServer::Deprecated1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Deprecated1".into()));
                JmapValue::Object(obj)
            }
            DnsServer::Cloudflare(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Cloudflare".into()));
                obj
            }
            DnsServer::DigitalOcean(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DigitalOcean".into()));
                obj
            }
            DnsServer::DeSEC(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DeSEC".into()));
                obj
            }
            DnsServer::Ovh(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ovh".into()));
                obj
            }
            DnsServer::Bunny(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Bunny".into()));
                obj
            }
            DnsServer::Porkbun(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Porkbun".into()));
                obj
            }
            DnsServer::Dnsimple(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dnsimple".into()));
                obj
            }
            DnsServer::Spaceship(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Spaceship".into()));
                obj
            }
            DnsServer::Route53(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Route53".into()));
                obj
            }
            DnsServer::GoogleCloudDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("GoogleCloudDns".into()));
                obj
            }
            DnsServer::Alidns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Alidns".into()));
                obj
            }
            DnsServer::ArvanCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ArvanCloud".into()));
                obj
            }
            DnsServer::Autodns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Autodns".into()));
                obj
            }
            DnsServer::AzureDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("AzureDns".into()));
                obj
            }
            DnsServer::BaiduCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("BaiduCloud".into()));
                obj
            }
            DnsServer::BluecatV2(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("BluecatV2".into()));
                obj
            }
            DnsServer::ClouDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ClouDns".into()));
                obj
            }
            DnsServer::Constellix(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Constellix".into()));
                obj
            }
            DnsServer::Cpanel(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Cpanel".into()));
                obj
            }
            DnsServer::Ddnss(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ddnss".into()));
                obj
            }
            DnsServer::DnsMadeEasy(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DnsMadeEasy".into()));
                obj
            }
            DnsServer::Domeneshop(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Domeneshop".into()));
                obj
            }
            DnsServer::Dreamhost(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dreamhost".into()));
                obj
            }
            DnsServer::DuckDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DuckDns".into()));
                obj
            }
            DnsServer::Dynu(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dynu".into()));
                obj
            }
            DnsServer::EasyDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EasyDns".into()));
                obj
            }
            DnsServer::EdgeDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EdgeDns".into()));
                obj
            }
            DnsServer::Exoscale(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Exoscale".into()));
                obj
            }
            DnsServer::FreeMyIp(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FreeMyIp".into()));
                obj
            }
            DnsServer::GandiV5(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("GandiV5".into()));
                obj
            }
            DnsServer::Gcore(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Gcore".into()));
                obj
            }
            DnsServer::Glesys(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Glesys".into()));
                obj
            }
            DnsServer::Godaddy(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Godaddy".into()));
                obj
            }
            DnsServer::Hetzner(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hetzner".into()));
                obj
            }
            DnsServer::HostingDe(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("HostingDe".into()));
                obj
            }
            DnsServer::Hostinger(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hostinger".into()));
                obj
            }
            DnsServer::HuaweiCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("HuaweiCloud".into()));
                obj
            }
            DnsServer::Hurricane(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hurricane".into()));
                obj
            }
            DnsServer::IbmCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("IbmCloud".into()));
                obj
            }
            DnsServer::Infoblox(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Infoblox".into()));
                obj
            }
            DnsServer::Infomaniak(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Infomaniak".into()));
                obj
            }
            DnsServer::Inwx(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Inwx".into()));
                obj
            }
            DnsServer::Ionos(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ionos".into()));
                obj
            }
            DnsServer::Ipv64(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ipv64".into()));
                obj
            }
            DnsServer::Joker(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Joker".into()));
                obj
            }
            DnsServer::Lightsail(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Lightsail".into()));
                obj
            }
            DnsServer::Linode(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Linode".into()));
                obj
            }
            DnsServer::LuaDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("LuaDns".into()));
                obj
            }
            DnsServer::MythicBeasts(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MythicBeasts".into()));
                obj
            }
            DnsServer::Namecheap(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Namecheap".into()));
                obj
            }
            DnsServer::NameDotCom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("NameDotCom".into()));
                obj
            }
            DnsServer::NameSilo(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("NameSilo".into()));
                obj
            }
            DnsServer::Netcup(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Netcup".into()));
                obj
            }
            DnsServer::Netlify(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Netlify".into()));
                obj
            }
            DnsServer::Nifcloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Nifcloud".into()));
                obj
            }
            DnsServer::Ns1(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ns1".into()));
                obj
            }
            DnsServer::OracleCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("OracleCloud".into()));
                obj
            }
            DnsServer::Plesk(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Plesk".into()));
                obj
            }
            DnsServer::Safedns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Safedns".into()));
                obj
            }
            DnsServer::Scaleway(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Scaleway".into()));
                obj
            }
            DnsServer::TencentCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TencentCloud".into()));
                obj
            }
            DnsServer::Transip(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Transip".into()));
                obj
            }
            DnsServer::UltraDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UltraDns".into()));
                obj
            }
            DnsServer::Vercel(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Vercel".into()));
                obj
            }
            DnsServer::Volcengine(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Volcengine".into()));
                obj
            }
            DnsServer::Vultr(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Vultr".into()));
                obj
            }
            DnsServer::WebSupport(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("WebSupport".into()));
                obj
            }
            DnsServer::YandexCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("YandexCloud".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DnsServer {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DnsServerType::Tsig => *self = DnsServer::Tsig(Default::default()),
                DnsServerType::Deprecated1 => *self = DnsServer::Deprecated1,
                DnsServerType::Cloudflare => *self = DnsServer::Cloudflare(Default::default()),
                DnsServerType::DigitalOcean => *self = DnsServer::DigitalOcean(Default::default()),
                DnsServerType::DeSEC => *self = DnsServer::DeSEC(Default::default()),
                DnsServerType::Ovh => *self = DnsServer::Ovh(Default::default()),
                DnsServerType::Bunny => *self = DnsServer::Bunny(Default::default()),
                DnsServerType::Porkbun => *self = DnsServer::Porkbun(Default::default()),
                DnsServerType::Dnsimple => *self = DnsServer::Dnsimple(Default::default()),
                DnsServerType::Spaceship => *self = DnsServer::Spaceship(Default::default()),
                DnsServerType::Route53 => *self = DnsServer::Route53(Default::default()),
                DnsServerType::GoogleCloudDns => {
                    *self = DnsServer::GoogleCloudDns(Default::default())
                }
                DnsServerType::Alidns => *self = DnsServer::Alidns(Default::default()),
                DnsServerType::ArvanCloud => *self = DnsServer::ArvanCloud(Default::default()),
                DnsServerType::Autodns => *self = DnsServer::Autodns(Default::default()),
                DnsServerType::AzureDns => *self = DnsServer::AzureDns(Default::default()),
                DnsServerType::BaiduCloud => *self = DnsServer::BaiduCloud(Default::default()),
                DnsServerType::BluecatV2 => *self = DnsServer::BluecatV2(Default::default()),
                DnsServerType::ClouDns => *self = DnsServer::ClouDns(Default::default()),
                DnsServerType::Constellix => *self = DnsServer::Constellix(Default::default()),
                DnsServerType::Cpanel => *self = DnsServer::Cpanel(Default::default()),
                DnsServerType::Ddnss => *self = DnsServer::Ddnss(Default::default()),
                DnsServerType::DnsMadeEasy => *self = DnsServer::DnsMadeEasy(Default::default()),
                DnsServerType::Domeneshop => *self = DnsServer::Domeneshop(Default::default()),
                DnsServerType::Dreamhost => *self = DnsServer::Dreamhost(Default::default()),
                DnsServerType::DuckDns => *self = DnsServer::DuckDns(Default::default()),
                DnsServerType::Dynu => *self = DnsServer::Dynu(Default::default()),
                DnsServerType::EasyDns => *self = DnsServer::EasyDns(Default::default()),
                DnsServerType::EdgeDns => *self = DnsServer::EdgeDns(Default::default()),
                DnsServerType::Exoscale => *self = DnsServer::Exoscale(Default::default()),
                DnsServerType::FreeMyIp => *self = DnsServer::FreeMyIp(Default::default()),
                DnsServerType::GandiV5 => *self = DnsServer::GandiV5(Default::default()),
                DnsServerType::Gcore => *self = DnsServer::Gcore(Default::default()),
                DnsServerType::Glesys => *self = DnsServer::Glesys(Default::default()),
                DnsServerType::Godaddy => *self = DnsServer::Godaddy(Default::default()),
                DnsServerType::Hetzner => *self = DnsServer::Hetzner(Default::default()),
                DnsServerType::HostingDe => *self = DnsServer::HostingDe(Default::default()),
                DnsServerType::Hostinger => *self = DnsServer::Hostinger(Default::default()),
                DnsServerType::HuaweiCloud => *self = DnsServer::HuaweiCloud(Default::default()),
                DnsServerType::Hurricane => *self = DnsServer::Hurricane(Default::default()),
                DnsServerType::IbmCloud => *self = DnsServer::IbmCloud(Default::default()),
                DnsServerType::Infoblox => *self = DnsServer::Infoblox(Default::default()),
                DnsServerType::Infomaniak => *self = DnsServer::Infomaniak(Default::default()),
                DnsServerType::Inwx => *self = DnsServer::Inwx(Default::default()),
                DnsServerType::Ionos => *self = DnsServer::Ionos(Default::default()),
                DnsServerType::Ipv64 => *self = DnsServer::Ipv64(Default::default()),
                DnsServerType::Joker => *self = DnsServer::Joker(Default::default()),
                DnsServerType::Lightsail => *self = DnsServer::Lightsail(Default::default()),
                DnsServerType::Linode => *self = DnsServer::Linode(Default::default()),
                DnsServerType::LuaDns => *self = DnsServer::LuaDns(Default::default()),
                DnsServerType::MythicBeasts => *self = DnsServer::MythicBeasts(Default::default()),
                DnsServerType::Namecheap => *self = DnsServer::Namecheap(Default::default()),
                DnsServerType::NameDotCom => *self = DnsServer::NameDotCom(Default::default()),
                DnsServerType::NameSilo => *self = DnsServer::NameSilo(Default::default()),
                DnsServerType::Netcup => *self = DnsServer::Netcup(Default::default()),
                DnsServerType::Netlify => *self = DnsServer::Netlify(Default::default()),
                DnsServerType::Nifcloud => *self = DnsServer::Nifcloud(Default::default()),
                DnsServerType::Ns1 => *self = DnsServer::Ns1(Default::default()),
                DnsServerType::OracleCloud => *self = DnsServer::OracleCloud(Default::default()),
                DnsServerType::Plesk => *self = DnsServer::Plesk(Default::default()),
                DnsServerType::Safedns => *self = DnsServer::Safedns(Default::default()),
                DnsServerType::Scaleway => *self = DnsServer::Scaleway(Default::default()),
                DnsServerType::TencentCloud => *self = DnsServer::TencentCloud(Default::default()),
                DnsServerType::Transip => *self = DnsServer::Transip(Default::default()),
                DnsServerType::UltraDns => *self = DnsServer::UltraDns(Default::default()),
                DnsServerType::Vercel => *self = DnsServer::Vercel(Default::default()),
                DnsServerType::Volcengine => *self = DnsServer::Volcengine(Default::default()),
                DnsServerType::Vultr => *self = DnsServer::Vultr(Default::default()),
                DnsServerType::WebSupport => *self = DnsServer::WebSupport(Default::default()),
                DnsServerType::YandexCloud => *self = DnsServer::YandexCloud(Default::default()),
            }
        }
        match self {
            DnsServer::Tsig(inner) => inner.patch(pointer, value),
            DnsServer::Deprecated1 => pointer.assert_eof(),
            DnsServer::Cloudflare(inner) => inner.patch(pointer, value),
            DnsServer::DigitalOcean(inner) => inner.patch(pointer, value),
            DnsServer::DeSEC(inner) => inner.patch(pointer, value),
            DnsServer::Ovh(inner) => inner.patch(pointer, value),
            DnsServer::Bunny(inner) => inner.patch(pointer, value),
            DnsServer::Porkbun(inner) => inner.patch(pointer, value),
            DnsServer::Dnsimple(inner) => inner.patch(pointer, value),
            DnsServer::Spaceship(inner) => inner.patch(pointer, value),
            DnsServer::Route53(inner) => inner.patch(pointer, value),
            DnsServer::GoogleCloudDns(inner) => inner.patch(pointer, value),
            DnsServer::Alidns(inner) => inner.patch(pointer, value),
            DnsServer::ArvanCloud(inner) => inner.patch(pointer, value),
            DnsServer::Autodns(inner) => inner.patch(pointer, value),
            DnsServer::AzureDns(inner) => inner.patch(pointer, value),
            DnsServer::BaiduCloud(inner) => inner.patch(pointer, value),
            DnsServer::BluecatV2(inner) => inner.patch(pointer, value),
            DnsServer::ClouDns(inner) => inner.patch(pointer, value),
            DnsServer::Constellix(inner) => inner.patch(pointer, value),
            DnsServer::Cpanel(inner) => inner.patch(pointer, value),
            DnsServer::Ddnss(inner) => inner.patch(pointer, value),
            DnsServer::DnsMadeEasy(inner) => inner.patch(pointer, value),
            DnsServer::Domeneshop(inner) => inner.patch(pointer, value),
            DnsServer::Dreamhost(inner) => inner.patch(pointer, value),
            DnsServer::DuckDns(inner) => inner.patch(pointer, value),
            DnsServer::Dynu(inner) => inner.patch(pointer, value),
            DnsServer::EasyDns(inner) => inner.patch(pointer, value),
            DnsServer::EdgeDns(inner) => inner.patch(pointer, value),
            DnsServer::Exoscale(inner) => inner.patch(pointer, value),
            DnsServer::FreeMyIp(inner) => inner.patch(pointer, value),
            DnsServer::GandiV5(inner) => inner.patch(pointer, value),
            DnsServer::Gcore(inner) => inner.patch(pointer, value),
            DnsServer::Glesys(inner) => inner.patch(pointer, value),
            DnsServer::Godaddy(inner) => inner.patch(pointer, value),
            DnsServer::Hetzner(inner) => inner.patch(pointer, value),
            DnsServer::HostingDe(inner) => inner.patch(pointer, value),
            DnsServer::Hostinger(inner) => inner.patch(pointer, value),
            DnsServer::HuaweiCloud(inner) => inner.patch(pointer, value),
            DnsServer::Hurricane(inner) => inner.patch(pointer, value),
            DnsServer::IbmCloud(inner) => inner.patch(pointer, value),
            DnsServer::Infoblox(inner) => inner.patch(pointer, value),
            DnsServer::Infomaniak(inner) => inner.patch(pointer, value),
            DnsServer::Inwx(inner) => inner.patch(pointer, value),
            DnsServer::Ionos(inner) => inner.patch(pointer, value),
            DnsServer::Ipv64(inner) => inner.patch(pointer, value),
            DnsServer::Joker(inner) => inner.patch(pointer, value),
            DnsServer::Lightsail(inner) => inner.patch(pointer, value),
            DnsServer::Linode(inner) => inner.patch(pointer, value),
            DnsServer::LuaDns(inner) => inner.patch(pointer, value),
            DnsServer::MythicBeasts(inner) => inner.patch(pointer, value),
            DnsServer::Namecheap(inner) => inner.patch(pointer, value),
            DnsServer::NameDotCom(inner) => inner.patch(pointer, value),
            DnsServer::NameSilo(inner) => inner.patch(pointer, value),
            DnsServer::Netcup(inner) => inner.patch(pointer, value),
            DnsServer::Netlify(inner) => inner.patch(pointer, value),
            DnsServer::Nifcloud(inner) => inner.patch(pointer, value),
            DnsServer::Ns1(inner) => inner.patch(pointer, value),
            DnsServer::OracleCloud(inner) => inner.patch(pointer, value),
            DnsServer::Plesk(inner) => inner.patch(pointer, value),
            DnsServer::Safedns(inner) => inner.patch(pointer, value),
            DnsServer::Scaleway(inner) => inner.patch(pointer, value),
            DnsServer::TencentCloud(inner) => inner.patch(pointer, value),
            DnsServer::Transip(inner) => inner.patch(pointer, value),
            DnsServer::UltraDns(inner) => inner.patch(pointer, value),
            DnsServer::Vercel(inner) => inner.patch(pointer, value),
            DnsServer::Volcengine(inner) => inner.patch(pointer, value),
            DnsServer::Vultr(inner) => inner.patch(pointer, value),
            DnsServer::WebSupport(inner) => inner.patch(pointer, value),
            DnsServer::YandexCloud(inner) => inner.patch(pointer, value),
        }
    }
}

impl DnsServer {
    pub fn object_type(&self) -> DnsServerType {
        match self {
            DnsServer::Tsig(_) => DnsServerType::Tsig,
            DnsServer::Deprecated1 => DnsServerType::Deprecated1,
            DnsServer::Cloudflare(_) => DnsServerType::Cloudflare,
            DnsServer::DigitalOcean(_) => DnsServerType::DigitalOcean,
            DnsServer::DeSEC(_) => DnsServerType::DeSEC,
            DnsServer::Ovh(_) => DnsServerType::Ovh,
            DnsServer::Bunny(_) => DnsServerType::Bunny,
            DnsServer::Porkbun(_) => DnsServerType::Porkbun,
            DnsServer::Dnsimple(_) => DnsServerType::Dnsimple,
            DnsServer::Spaceship(_) => DnsServerType::Spaceship,
            DnsServer::Route53(_) => DnsServerType::Route53,
            DnsServer::GoogleCloudDns(_) => DnsServerType::GoogleCloudDns,
            DnsServer::Alidns(_) => DnsServerType::Alidns,
            DnsServer::ArvanCloud(_) => DnsServerType::ArvanCloud,
            DnsServer::Autodns(_) => DnsServerType::Autodns,
            DnsServer::AzureDns(_) => DnsServerType::AzureDns,
            DnsServer::BaiduCloud(_) => DnsServerType::BaiduCloud,
            DnsServer::BluecatV2(_) => DnsServerType::BluecatV2,
            DnsServer::ClouDns(_) => DnsServerType::ClouDns,
            DnsServer::Constellix(_) => DnsServerType::Constellix,
            DnsServer::Cpanel(_) => DnsServerType::Cpanel,
            DnsServer::Ddnss(_) => DnsServerType::Ddnss,
            DnsServer::DnsMadeEasy(_) => DnsServerType::DnsMadeEasy,
            DnsServer::Domeneshop(_) => DnsServerType::Domeneshop,
            DnsServer::Dreamhost(_) => DnsServerType::Dreamhost,
            DnsServer::DuckDns(_) => DnsServerType::DuckDns,
            DnsServer::Dynu(_) => DnsServerType::Dynu,
            DnsServer::EasyDns(_) => DnsServerType::EasyDns,
            DnsServer::EdgeDns(_) => DnsServerType::EdgeDns,
            DnsServer::Exoscale(_) => DnsServerType::Exoscale,
            DnsServer::FreeMyIp(_) => DnsServerType::FreeMyIp,
            DnsServer::GandiV5(_) => DnsServerType::GandiV5,
            DnsServer::Gcore(_) => DnsServerType::Gcore,
            DnsServer::Glesys(_) => DnsServerType::Glesys,
            DnsServer::Godaddy(_) => DnsServerType::Godaddy,
            DnsServer::Hetzner(_) => DnsServerType::Hetzner,
            DnsServer::HostingDe(_) => DnsServerType::HostingDe,
            DnsServer::Hostinger(_) => DnsServerType::Hostinger,
            DnsServer::HuaweiCloud(_) => DnsServerType::HuaweiCloud,
            DnsServer::Hurricane(_) => DnsServerType::Hurricane,
            DnsServer::IbmCloud(_) => DnsServerType::IbmCloud,
            DnsServer::Infoblox(_) => DnsServerType::Infoblox,
            DnsServer::Infomaniak(_) => DnsServerType::Infomaniak,
            DnsServer::Inwx(_) => DnsServerType::Inwx,
            DnsServer::Ionos(_) => DnsServerType::Ionos,
            DnsServer::Ipv64(_) => DnsServerType::Ipv64,
            DnsServer::Joker(_) => DnsServerType::Joker,
            DnsServer::Lightsail(_) => DnsServerType::Lightsail,
            DnsServer::Linode(_) => DnsServerType::Linode,
            DnsServer::LuaDns(_) => DnsServerType::LuaDns,
            DnsServer::MythicBeasts(_) => DnsServerType::MythicBeasts,
            DnsServer::Namecheap(_) => DnsServerType::Namecheap,
            DnsServer::NameDotCom(_) => DnsServerType::NameDotCom,
            DnsServer::NameSilo(_) => DnsServerType::NameSilo,
            DnsServer::Netcup(_) => DnsServerType::Netcup,
            DnsServer::Netlify(_) => DnsServerType::Netlify,
            DnsServer::Nifcloud(_) => DnsServerType::Nifcloud,
            DnsServer::Ns1(_) => DnsServerType::Ns1,
            DnsServer::OracleCloud(_) => DnsServerType::OracleCloud,
            DnsServer::Plesk(_) => DnsServerType::Plesk,
            DnsServer::Safedns(_) => DnsServerType::Safedns,
            DnsServer::Scaleway(_) => DnsServerType::Scaleway,
            DnsServer::TencentCloud(_) => DnsServerType::TencentCloud,
            DnsServer::Transip(_) => DnsServerType::Transip,
            DnsServer::UltraDns(_) => DnsServerType::UltraDns,
            DnsServer::Vercel(_) => DnsServerType::Vercel,
            DnsServer::Volcengine(_) => DnsServerType::Volcengine,
            DnsServer::Vultr(_) => DnsServerType::Vultr,
            DnsServer::WebSupport(_) => DnsServerType::WebSupport,
            DnsServer::YandexCloud(_) => DnsServerType::YandexCloud,
        }
    }
}

impl DnsServerAlidns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        if let Some(value) = &self.region {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Region));
            }
        }
        let value = &self.security_token;
        value.validate(errors);
        if let Some(value) = &self.line {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Line));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerAlidns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.region.pickle(out);
        self.security_token.pickle(out);
        self.line.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.security_token = Pickle::unpickle(stream)?;
        this.line = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerAlidns {
    fn default() -> Self {
        Self {
            access_key: Default::default(),
            secret_key: Default::default(),
            region: Default::default(),
            security_token: Default::default(),
            line: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerAlidns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::SecurityToken, self.security_token.into_value());
        map.insert_unchecked(Property::Line, self.line.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerAlidns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecurityToken) => self.security_token.patch(pointer, value),
            Some(Property::Line) => self
                .line
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerAutodns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerAutodns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.password.pickle(out);
        self.context.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.context = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerAutodns {
    fn default() -> Self {
        Self {
            username: Default::default(),
            password: Default::default(),
            context: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerAutodns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::Context, self.context.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerAutodns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Context) => self.context.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerAzureDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tenant_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::TenantId));
        }
        let value = &self.client_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ClientId));
        }
        let value = &self.client_secret;
        value.validate(errors);
        let value = &self.subscription_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::SubscriptionId));
        }
        let value = &self.resource_group;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ResourceGroup));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerAzureDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tenant_id.pickle(out);
        self.client_id.pickle(out);
        self.client_secret.pickle(out);
        self.subscription_id.pickle(out);
        self.resource_group.pickle(out);
        self.environment.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tenant_id = Pickle::unpickle(stream)?;
        this.client_id = Pickle::unpickle(stream)?;
        this.client_secret = Pickle::unpickle(stream)?;
        this.subscription_id = Pickle::unpickle(stream)?;
        this.resource_group = Pickle::unpickle(stream)?;
        this.environment = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerAzureDns {
    fn default() -> Self {
        Self {
            tenant_id: Default::default(),
            client_id: Default::default(),
            client_secret: Default::default(),
            subscription_id: Default::default(),
            resource_group: Default::default(),
            environment: AzureEnvironment::Public,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerAzureDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::TenantId, self.tenant_id.into_value());
        map.insert_unchecked(Property::ClientId, self.client_id.into_value());
        map.insert_unchecked(Property::ClientSecret, self.client_secret.into_value());
        map.insert_unchecked(Property::SubscriptionId, self.subscription_id.into_value());
        map.insert_unchecked(Property::ResourceGroup, self.resource_group.into_value());
        map.insert_unchecked(Property::Environment, self.environment.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerAzureDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TenantId) => self
                .tenant_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClientId) => self
                .client_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClientSecret) => self.client_secret.patch(pointer, value),
            Some(Property::SubscriptionId) => self
                .subscription_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ResourceGroup) => self
                .resource_group
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Environment) => self.environment.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerBaiduCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerBaiduCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerBaiduCloud {
    fn default() -> Self {
        Self {
            access_key: Default::default(),
            secret_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerBaiduCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerBaiduCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerBluecatV2 {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.base_url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BaseUrl));
        }
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.config_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ConfigName));
        }
        let value = &self.view_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ViewName));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerBluecatV2 {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.base_url.pickle(out);
        self.username.pickle(out);
        self.password.pickle(out);
        self.config_name.pickle(out);
        self.view_name.pickle(out);
        self.skip_deploy.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.base_url = Pickle::unpickle(stream)?;
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.config_name = Pickle::unpickle(stream)?;
        this.view_name = Pickle::unpickle(stream)?;
        this.skip_deploy = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerBluecatV2 {
    fn default() -> Self {
        Self {
            base_url: Default::default(),
            username: Default::default(),
            password: Default::default(),
            config_name: Default::default(),
            view_name: Default::default(),
            skip_deploy: false,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerBluecatV2 {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::BaseUrl, self.base_url.into_value());
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::ConfigName, self.config_name.into_value());
        map.insert_unchecked(Property::ViewName, self.view_name.into_value());
        map.insert_unchecked(Property::SkipDeploy, self.skip_deploy.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerBluecatV2 {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BaseUrl) => self
                .base_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::ConfigName) => self
                .config_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ViewName) => self
                .view_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SkipDeploy) => self.skip_deploy.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerBootstrap {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            DnsServerBootstrap::Manual => true,
            DnsServerBootstrap::Tsig(inner) => inner.validate(errors),
            DnsServerBootstrap::Deprecated1 => true,
            DnsServerBootstrap::Cloudflare(inner) => inner.validate(errors),
            DnsServerBootstrap::DigitalOcean(inner) => inner.validate(errors),
            DnsServerBootstrap::DeSEC(inner) => inner.validate(errors),
            DnsServerBootstrap::Ovh(inner) => inner.validate(errors),
            DnsServerBootstrap::Bunny(inner) => inner.validate(errors),
            DnsServerBootstrap::Porkbun(inner) => inner.validate(errors),
            DnsServerBootstrap::Dnsimple(inner) => inner.validate(errors),
            DnsServerBootstrap::Spaceship(inner) => inner.validate(errors),
            DnsServerBootstrap::Route53(inner) => inner.validate(errors),
            DnsServerBootstrap::GoogleCloudDns(inner) => inner.validate(errors),
            DnsServerBootstrap::Alidns(inner) => inner.validate(errors),
            DnsServerBootstrap::ArvanCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Autodns(inner) => inner.validate(errors),
            DnsServerBootstrap::AzureDns(inner) => inner.validate(errors),
            DnsServerBootstrap::BaiduCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::BluecatV2(inner) => inner.validate(errors),
            DnsServerBootstrap::ClouDns(inner) => inner.validate(errors),
            DnsServerBootstrap::Constellix(inner) => inner.validate(errors),
            DnsServerBootstrap::Cpanel(inner) => inner.validate(errors),
            DnsServerBootstrap::Ddnss(inner) => inner.validate(errors),
            DnsServerBootstrap::DnsMadeEasy(inner) => inner.validate(errors),
            DnsServerBootstrap::Domeneshop(inner) => inner.validate(errors),
            DnsServerBootstrap::Dreamhost(inner) => inner.validate(errors),
            DnsServerBootstrap::DuckDns(inner) => inner.validate(errors),
            DnsServerBootstrap::Dynu(inner) => inner.validate(errors),
            DnsServerBootstrap::EasyDns(inner) => inner.validate(errors),
            DnsServerBootstrap::EdgeDns(inner) => inner.validate(errors),
            DnsServerBootstrap::Exoscale(inner) => inner.validate(errors),
            DnsServerBootstrap::FreeMyIp(inner) => inner.validate(errors),
            DnsServerBootstrap::GandiV5(inner) => inner.validate(errors),
            DnsServerBootstrap::Gcore(inner) => inner.validate(errors),
            DnsServerBootstrap::Glesys(inner) => inner.validate(errors),
            DnsServerBootstrap::Godaddy(inner) => inner.validate(errors),
            DnsServerBootstrap::Hetzner(inner) => inner.validate(errors),
            DnsServerBootstrap::HostingDe(inner) => inner.validate(errors),
            DnsServerBootstrap::Hostinger(inner) => inner.validate(errors),
            DnsServerBootstrap::HuaweiCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Hurricane(inner) => inner.validate(errors),
            DnsServerBootstrap::IbmCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Infoblox(inner) => inner.validate(errors),
            DnsServerBootstrap::Infomaniak(inner) => inner.validate(errors),
            DnsServerBootstrap::Inwx(inner) => inner.validate(errors),
            DnsServerBootstrap::Ionos(inner) => inner.validate(errors),
            DnsServerBootstrap::Ipv64(inner) => inner.validate(errors),
            DnsServerBootstrap::Joker(inner) => inner.validate(errors),
            DnsServerBootstrap::Lightsail(inner) => inner.validate(errors),
            DnsServerBootstrap::Linode(inner) => inner.validate(errors),
            DnsServerBootstrap::LuaDns(inner) => inner.validate(errors),
            DnsServerBootstrap::MythicBeasts(inner) => inner.validate(errors),
            DnsServerBootstrap::Namecheap(inner) => inner.validate(errors),
            DnsServerBootstrap::NameDotCom(inner) => inner.validate(errors),
            DnsServerBootstrap::NameSilo(inner) => inner.validate(errors),
            DnsServerBootstrap::Netcup(inner) => inner.validate(errors),
            DnsServerBootstrap::Netlify(inner) => inner.validate(errors),
            DnsServerBootstrap::Nifcloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Ns1(inner) => inner.validate(errors),
            DnsServerBootstrap::OracleCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Plesk(inner) => inner.validate(errors),
            DnsServerBootstrap::Safedns(inner) => inner.validate(errors),
            DnsServerBootstrap::Scaleway(inner) => inner.validate(errors),
            DnsServerBootstrap::TencentCloud(inner) => inner.validate(errors),
            DnsServerBootstrap::Transip(inner) => inner.validate(errors),
            DnsServerBootstrap::UltraDns(inner) => inner.validate(errors),
            DnsServerBootstrap::Vercel(inner) => inner.validate(errors),
            DnsServerBootstrap::Volcengine(inner) => inner.validate(errors),
            DnsServerBootstrap::Vultr(inner) => inner.validate(errors),
            DnsServerBootstrap::WebSupport(inner) => inner.validate(errors),
            DnsServerBootstrap::YandexCloud(inner) => inner.validate(errors),
        }
    }
}

impl Default for DnsServerBootstrap {
    fn default() -> Self {
        DnsServerBootstrap::Manual
    }
}

impl Pickle for DnsServerBootstrap {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            DnsServerBootstrap::Manual => {
                0u16.pickle(out);
            }
            DnsServerBootstrap::Tsig(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Deprecated1 => {
                2u16.pickle(out);
            }
            DnsServerBootstrap::Cloudflare(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::DigitalOcean(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::DeSEC(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Ovh(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Bunny(inner) => {
                7u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Porkbun(inner) => {
                8u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Dnsimple(inner) => {
                9u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Spaceship(inner) => {
                10u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Route53(inner) => {
                11u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::GoogleCloudDns(inner) => {
                12u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Alidns(inner) => {
                13u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::ArvanCloud(inner) => {
                14u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Autodns(inner) => {
                15u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::AzureDns(inner) => {
                16u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::BaiduCloud(inner) => {
                17u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::BluecatV2(inner) => {
                18u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::ClouDns(inner) => {
                19u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Constellix(inner) => {
                20u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Cpanel(inner) => {
                21u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Ddnss(inner) => {
                22u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::DnsMadeEasy(inner) => {
                23u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Domeneshop(inner) => {
                24u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Dreamhost(inner) => {
                25u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::DuckDns(inner) => {
                26u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Dynu(inner) => {
                27u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::EasyDns(inner) => {
                28u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::EdgeDns(inner) => {
                29u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Exoscale(inner) => {
                30u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::FreeMyIp(inner) => {
                31u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::GandiV5(inner) => {
                32u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Gcore(inner) => {
                33u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Glesys(inner) => {
                34u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Godaddy(inner) => {
                35u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Hetzner(inner) => {
                36u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::HostingDe(inner) => {
                37u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Hostinger(inner) => {
                38u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::HuaweiCloud(inner) => {
                39u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Hurricane(inner) => {
                40u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::IbmCloud(inner) => {
                41u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Infoblox(inner) => {
                42u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Infomaniak(inner) => {
                43u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Inwx(inner) => {
                44u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Ionos(inner) => {
                45u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Ipv64(inner) => {
                46u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Joker(inner) => {
                47u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Lightsail(inner) => {
                48u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Linode(inner) => {
                49u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::LuaDns(inner) => {
                50u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::MythicBeasts(inner) => {
                51u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Namecheap(inner) => {
                52u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::NameDotCom(inner) => {
                53u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::NameSilo(inner) => {
                54u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Netcup(inner) => {
                55u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Netlify(inner) => {
                56u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Nifcloud(inner) => {
                57u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Ns1(inner) => {
                58u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::OracleCloud(inner) => {
                59u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Plesk(inner) => {
                60u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Safedns(inner) => {
                61u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Scaleway(inner) => {
                62u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::TencentCloud(inner) => {
                63u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Transip(inner) => {
                64u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::UltraDns(inner) => {
                65u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Vercel(inner) => {
                66u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Volcengine(inner) => {
                67u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::Vultr(inner) => {
                68u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::WebSupport(inner) => {
                69u16.pickle(out);
                inner.pickle(out);
            }
            DnsServerBootstrap::YandexCloud(inner) => {
                70u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(DnsServerBootstrap::Manual),
            1 => Pickle::unpickle(stream).map(DnsServerBootstrap::Tsig),
            2 => Some(DnsServerBootstrap::Deprecated1),
            3 => Pickle::unpickle(stream).map(DnsServerBootstrap::Cloudflare),
            4 => Pickle::unpickle(stream).map(DnsServerBootstrap::DigitalOcean),
            5 => Pickle::unpickle(stream).map(DnsServerBootstrap::DeSEC),
            6 => Pickle::unpickle(stream).map(DnsServerBootstrap::Ovh),
            7 => Pickle::unpickle(stream).map(DnsServerBootstrap::Bunny),
            8 => Pickle::unpickle(stream).map(DnsServerBootstrap::Porkbun),
            9 => Pickle::unpickle(stream).map(DnsServerBootstrap::Dnsimple),
            10 => Pickle::unpickle(stream).map(DnsServerBootstrap::Spaceship),
            11 => Pickle::unpickle(stream).map(DnsServerBootstrap::Route53),
            12 => Pickle::unpickle(stream).map(DnsServerBootstrap::GoogleCloudDns),
            13 => Pickle::unpickle(stream).map(DnsServerBootstrap::Alidns),
            14 => Pickle::unpickle(stream).map(DnsServerBootstrap::ArvanCloud),
            15 => Pickle::unpickle(stream).map(DnsServerBootstrap::Autodns),
            16 => Pickle::unpickle(stream).map(DnsServerBootstrap::AzureDns),
            17 => Pickle::unpickle(stream).map(DnsServerBootstrap::BaiduCloud),
            18 => Pickle::unpickle(stream).map(DnsServerBootstrap::BluecatV2),
            19 => Pickle::unpickle(stream).map(DnsServerBootstrap::ClouDns),
            20 => Pickle::unpickle(stream).map(DnsServerBootstrap::Constellix),
            21 => Pickle::unpickle(stream).map(DnsServerBootstrap::Cpanel),
            22 => Pickle::unpickle(stream).map(DnsServerBootstrap::Ddnss),
            23 => Pickle::unpickle(stream).map(DnsServerBootstrap::DnsMadeEasy),
            24 => Pickle::unpickle(stream).map(DnsServerBootstrap::Domeneshop),
            25 => Pickle::unpickle(stream).map(DnsServerBootstrap::Dreamhost),
            26 => Pickle::unpickle(stream).map(DnsServerBootstrap::DuckDns),
            27 => Pickle::unpickle(stream).map(DnsServerBootstrap::Dynu),
            28 => Pickle::unpickle(stream).map(DnsServerBootstrap::EasyDns),
            29 => Pickle::unpickle(stream).map(DnsServerBootstrap::EdgeDns),
            30 => Pickle::unpickle(stream).map(DnsServerBootstrap::Exoscale),
            31 => Pickle::unpickle(stream).map(DnsServerBootstrap::FreeMyIp),
            32 => Pickle::unpickle(stream).map(DnsServerBootstrap::GandiV5),
            33 => Pickle::unpickle(stream).map(DnsServerBootstrap::Gcore),
            34 => Pickle::unpickle(stream).map(DnsServerBootstrap::Glesys),
            35 => Pickle::unpickle(stream).map(DnsServerBootstrap::Godaddy),
            36 => Pickle::unpickle(stream).map(DnsServerBootstrap::Hetzner),
            37 => Pickle::unpickle(stream).map(DnsServerBootstrap::HostingDe),
            38 => Pickle::unpickle(stream).map(DnsServerBootstrap::Hostinger),
            39 => Pickle::unpickle(stream).map(DnsServerBootstrap::HuaweiCloud),
            40 => Pickle::unpickle(stream).map(DnsServerBootstrap::Hurricane),
            41 => Pickle::unpickle(stream).map(DnsServerBootstrap::IbmCloud),
            42 => Pickle::unpickle(stream).map(DnsServerBootstrap::Infoblox),
            43 => Pickle::unpickle(stream).map(DnsServerBootstrap::Infomaniak),
            44 => Pickle::unpickle(stream).map(DnsServerBootstrap::Inwx),
            45 => Pickle::unpickle(stream).map(DnsServerBootstrap::Ionos),
            46 => Pickle::unpickle(stream).map(DnsServerBootstrap::Ipv64),
            47 => Pickle::unpickle(stream).map(DnsServerBootstrap::Joker),
            48 => Pickle::unpickle(stream).map(DnsServerBootstrap::Lightsail),
            49 => Pickle::unpickle(stream).map(DnsServerBootstrap::Linode),
            50 => Pickle::unpickle(stream).map(DnsServerBootstrap::LuaDns),
            51 => Pickle::unpickle(stream).map(DnsServerBootstrap::MythicBeasts),
            52 => Pickle::unpickle(stream).map(DnsServerBootstrap::Namecheap),
            53 => Pickle::unpickle(stream).map(DnsServerBootstrap::NameDotCom),
            54 => Pickle::unpickle(stream).map(DnsServerBootstrap::NameSilo),
            55 => Pickle::unpickle(stream).map(DnsServerBootstrap::Netcup),
            56 => Pickle::unpickle(stream).map(DnsServerBootstrap::Netlify),
            57 => Pickle::unpickle(stream).map(DnsServerBootstrap::Nifcloud),
            58 => Pickle::unpickle(stream).map(DnsServerBootstrap::Ns1),
            59 => Pickle::unpickle(stream).map(DnsServerBootstrap::OracleCloud),
            60 => Pickle::unpickle(stream).map(DnsServerBootstrap::Plesk),
            61 => Pickle::unpickle(stream).map(DnsServerBootstrap::Safedns),
            62 => Pickle::unpickle(stream).map(DnsServerBootstrap::Scaleway),
            63 => Pickle::unpickle(stream).map(DnsServerBootstrap::TencentCloud),
            64 => Pickle::unpickle(stream).map(DnsServerBootstrap::Transip),
            65 => Pickle::unpickle(stream).map(DnsServerBootstrap::UltraDns),
            66 => Pickle::unpickle(stream).map(DnsServerBootstrap::Vercel),
            67 => Pickle::unpickle(stream).map(DnsServerBootstrap::Volcengine),
            68 => Pickle::unpickle(stream).map(DnsServerBootstrap::Vultr),
            69 => Pickle::unpickle(stream).map(DnsServerBootstrap::WebSupport),
            70 => Pickle::unpickle(stream).map(DnsServerBootstrap::YandexCloud),
            _ => None,
        }
    }
}

impl IntoValue for DnsServerBootstrap {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            DnsServerBootstrap::Manual => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Manual".into()));
                JmapValue::Object(obj)
            }
            DnsServerBootstrap::Tsig(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Tsig".into()));
                obj
            }
            DnsServerBootstrap::Deprecated1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Deprecated1".into()));
                JmapValue::Object(obj)
            }
            DnsServerBootstrap::Cloudflare(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Cloudflare".into()));
                obj
            }
            DnsServerBootstrap::DigitalOcean(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DigitalOcean".into()));
                obj
            }
            DnsServerBootstrap::DeSEC(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DeSEC".into()));
                obj
            }
            DnsServerBootstrap::Ovh(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ovh".into()));
                obj
            }
            DnsServerBootstrap::Bunny(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Bunny".into()));
                obj
            }
            DnsServerBootstrap::Porkbun(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Porkbun".into()));
                obj
            }
            DnsServerBootstrap::Dnsimple(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dnsimple".into()));
                obj
            }
            DnsServerBootstrap::Spaceship(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Spaceship".into()));
                obj
            }
            DnsServerBootstrap::Route53(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Route53".into()));
                obj
            }
            DnsServerBootstrap::GoogleCloudDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("GoogleCloudDns".into()));
                obj
            }
            DnsServerBootstrap::Alidns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Alidns".into()));
                obj
            }
            DnsServerBootstrap::ArvanCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ArvanCloud".into()));
                obj
            }
            DnsServerBootstrap::Autodns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Autodns".into()));
                obj
            }
            DnsServerBootstrap::AzureDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("AzureDns".into()));
                obj
            }
            DnsServerBootstrap::BaiduCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("BaiduCloud".into()));
                obj
            }
            DnsServerBootstrap::BluecatV2(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("BluecatV2".into()));
                obj
            }
            DnsServerBootstrap::ClouDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ClouDns".into()));
                obj
            }
            DnsServerBootstrap::Constellix(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Constellix".into()));
                obj
            }
            DnsServerBootstrap::Cpanel(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Cpanel".into()));
                obj
            }
            DnsServerBootstrap::Ddnss(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ddnss".into()));
                obj
            }
            DnsServerBootstrap::DnsMadeEasy(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DnsMadeEasy".into()));
                obj
            }
            DnsServerBootstrap::Domeneshop(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Domeneshop".into()));
                obj
            }
            DnsServerBootstrap::Dreamhost(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dreamhost".into()));
                obj
            }
            DnsServerBootstrap::DuckDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DuckDns".into()));
                obj
            }
            DnsServerBootstrap::Dynu(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Dynu".into()));
                obj
            }
            DnsServerBootstrap::EasyDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EasyDns".into()));
                obj
            }
            DnsServerBootstrap::EdgeDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EdgeDns".into()));
                obj
            }
            DnsServerBootstrap::Exoscale(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Exoscale".into()));
                obj
            }
            DnsServerBootstrap::FreeMyIp(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FreeMyIp".into()));
                obj
            }
            DnsServerBootstrap::GandiV5(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("GandiV5".into()));
                obj
            }
            DnsServerBootstrap::Gcore(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Gcore".into()));
                obj
            }
            DnsServerBootstrap::Glesys(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Glesys".into()));
                obj
            }
            DnsServerBootstrap::Godaddy(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Godaddy".into()));
                obj
            }
            DnsServerBootstrap::Hetzner(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hetzner".into()));
                obj
            }
            DnsServerBootstrap::HostingDe(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("HostingDe".into()));
                obj
            }
            DnsServerBootstrap::Hostinger(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hostinger".into()));
                obj
            }
            DnsServerBootstrap::HuaweiCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("HuaweiCloud".into()));
                obj
            }
            DnsServerBootstrap::Hurricane(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Hurricane".into()));
                obj
            }
            DnsServerBootstrap::IbmCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("IbmCloud".into()));
                obj
            }
            DnsServerBootstrap::Infoblox(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Infoblox".into()));
                obj
            }
            DnsServerBootstrap::Infomaniak(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Infomaniak".into()));
                obj
            }
            DnsServerBootstrap::Inwx(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Inwx".into()));
                obj
            }
            DnsServerBootstrap::Ionos(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ionos".into()));
                obj
            }
            DnsServerBootstrap::Ipv64(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ipv64".into()));
                obj
            }
            DnsServerBootstrap::Joker(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Joker".into()));
                obj
            }
            DnsServerBootstrap::Lightsail(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Lightsail".into()));
                obj
            }
            DnsServerBootstrap::Linode(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Linode".into()));
                obj
            }
            DnsServerBootstrap::LuaDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("LuaDns".into()));
                obj
            }
            DnsServerBootstrap::MythicBeasts(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MythicBeasts".into()));
                obj
            }
            DnsServerBootstrap::Namecheap(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Namecheap".into()));
                obj
            }
            DnsServerBootstrap::NameDotCom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("NameDotCom".into()));
                obj
            }
            DnsServerBootstrap::NameSilo(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("NameSilo".into()));
                obj
            }
            DnsServerBootstrap::Netcup(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Netcup".into()));
                obj
            }
            DnsServerBootstrap::Netlify(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Netlify".into()));
                obj
            }
            DnsServerBootstrap::Nifcloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Nifcloud".into()));
                obj
            }
            DnsServerBootstrap::Ns1(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ns1".into()));
                obj
            }
            DnsServerBootstrap::OracleCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("OracleCloud".into()));
                obj
            }
            DnsServerBootstrap::Plesk(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Plesk".into()));
                obj
            }
            DnsServerBootstrap::Safedns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Safedns".into()));
                obj
            }
            DnsServerBootstrap::Scaleway(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Scaleway".into()));
                obj
            }
            DnsServerBootstrap::TencentCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TencentCloud".into()));
                obj
            }
            DnsServerBootstrap::Transip(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Transip".into()));
                obj
            }
            DnsServerBootstrap::UltraDns(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UltraDns".into()));
                obj
            }
            DnsServerBootstrap::Vercel(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Vercel".into()));
                obj
            }
            DnsServerBootstrap::Volcengine(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Volcengine".into()));
                obj
            }
            DnsServerBootstrap::Vultr(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Vultr".into()));
                obj
            }
            DnsServerBootstrap::WebSupport(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("WebSupport".into()));
                obj
            }
            DnsServerBootstrap::YandexCloud(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("YandexCloud".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for DnsServerBootstrap {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                DnsServerBootstrapType::Manual => *self = DnsServerBootstrap::Manual,
                DnsServerBootstrapType::Tsig => {
                    *self = DnsServerBootstrap::Tsig(Default::default())
                }
                DnsServerBootstrapType::Deprecated1 => *self = DnsServerBootstrap::Deprecated1,
                DnsServerBootstrapType::Cloudflare => {
                    *self = DnsServerBootstrap::Cloudflare(Default::default())
                }
                DnsServerBootstrapType::DigitalOcean => {
                    *self = DnsServerBootstrap::DigitalOcean(Default::default())
                }
                DnsServerBootstrapType::DeSEC => {
                    *self = DnsServerBootstrap::DeSEC(Default::default())
                }
                DnsServerBootstrapType::Ovh => *self = DnsServerBootstrap::Ovh(Default::default()),
                DnsServerBootstrapType::Bunny => {
                    *self = DnsServerBootstrap::Bunny(Default::default())
                }
                DnsServerBootstrapType::Porkbun => {
                    *self = DnsServerBootstrap::Porkbun(Default::default())
                }
                DnsServerBootstrapType::Dnsimple => {
                    *self = DnsServerBootstrap::Dnsimple(Default::default())
                }
                DnsServerBootstrapType::Spaceship => {
                    *self = DnsServerBootstrap::Spaceship(Default::default())
                }
                DnsServerBootstrapType::Route53 => {
                    *self = DnsServerBootstrap::Route53(Default::default())
                }
                DnsServerBootstrapType::GoogleCloudDns => {
                    *self = DnsServerBootstrap::GoogleCloudDns(Default::default())
                }
                DnsServerBootstrapType::Alidns => {
                    *self = DnsServerBootstrap::Alidns(Default::default())
                }
                DnsServerBootstrapType::ArvanCloud => {
                    *self = DnsServerBootstrap::ArvanCloud(Default::default())
                }
                DnsServerBootstrapType::Autodns => {
                    *self = DnsServerBootstrap::Autodns(Default::default())
                }
                DnsServerBootstrapType::AzureDns => {
                    *self = DnsServerBootstrap::AzureDns(Default::default())
                }
                DnsServerBootstrapType::BaiduCloud => {
                    *self = DnsServerBootstrap::BaiduCloud(Default::default())
                }
                DnsServerBootstrapType::BluecatV2 => {
                    *self = DnsServerBootstrap::BluecatV2(Default::default())
                }
                DnsServerBootstrapType::ClouDns => {
                    *self = DnsServerBootstrap::ClouDns(Default::default())
                }
                DnsServerBootstrapType::Constellix => {
                    *self = DnsServerBootstrap::Constellix(Default::default())
                }
                DnsServerBootstrapType::Cpanel => {
                    *self = DnsServerBootstrap::Cpanel(Default::default())
                }
                DnsServerBootstrapType::Ddnss => {
                    *self = DnsServerBootstrap::Ddnss(Default::default())
                }
                DnsServerBootstrapType::DnsMadeEasy => {
                    *self = DnsServerBootstrap::DnsMadeEasy(Default::default())
                }
                DnsServerBootstrapType::Domeneshop => {
                    *self = DnsServerBootstrap::Domeneshop(Default::default())
                }
                DnsServerBootstrapType::Dreamhost => {
                    *self = DnsServerBootstrap::Dreamhost(Default::default())
                }
                DnsServerBootstrapType::DuckDns => {
                    *self = DnsServerBootstrap::DuckDns(Default::default())
                }
                DnsServerBootstrapType::Dynu => {
                    *self = DnsServerBootstrap::Dynu(Default::default())
                }
                DnsServerBootstrapType::EasyDns => {
                    *self = DnsServerBootstrap::EasyDns(Default::default())
                }
                DnsServerBootstrapType::EdgeDns => {
                    *self = DnsServerBootstrap::EdgeDns(Default::default())
                }
                DnsServerBootstrapType::Exoscale => {
                    *self = DnsServerBootstrap::Exoscale(Default::default())
                }
                DnsServerBootstrapType::FreeMyIp => {
                    *self = DnsServerBootstrap::FreeMyIp(Default::default())
                }
                DnsServerBootstrapType::GandiV5 => {
                    *self = DnsServerBootstrap::GandiV5(Default::default())
                }
                DnsServerBootstrapType::Gcore => {
                    *self = DnsServerBootstrap::Gcore(Default::default())
                }
                DnsServerBootstrapType::Glesys => {
                    *self = DnsServerBootstrap::Glesys(Default::default())
                }
                DnsServerBootstrapType::Godaddy => {
                    *self = DnsServerBootstrap::Godaddy(Default::default())
                }
                DnsServerBootstrapType::Hetzner => {
                    *self = DnsServerBootstrap::Hetzner(Default::default())
                }
                DnsServerBootstrapType::HostingDe => {
                    *self = DnsServerBootstrap::HostingDe(Default::default())
                }
                DnsServerBootstrapType::Hostinger => {
                    *self = DnsServerBootstrap::Hostinger(Default::default())
                }
                DnsServerBootstrapType::HuaweiCloud => {
                    *self = DnsServerBootstrap::HuaweiCloud(Default::default())
                }
                DnsServerBootstrapType::Hurricane => {
                    *self = DnsServerBootstrap::Hurricane(Default::default())
                }
                DnsServerBootstrapType::IbmCloud => {
                    *self = DnsServerBootstrap::IbmCloud(Default::default())
                }
                DnsServerBootstrapType::Infoblox => {
                    *self = DnsServerBootstrap::Infoblox(Default::default())
                }
                DnsServerBootstrapType::Infomaniak => {
                    *self = DnsServerBootstrap::Infomaniak(Default::default())
                }
                DnsServerBootstrapType::Inwx => {
                    *self = DnsServerBootstrap::Inwx(Default::default())
                }
                DnsServerBootstrapType::Ionos => {
                    *self = DnsServerBootstrap::Ionos(Default::default())
                }
                DnsServerBootstrapType::Ipv64 => {
                    *self = DnsServerBootstrap::Ipv64(Default::default())
                }
                DnsServerBootstrapType::Joker => {
                    *self = DnsServerBootstrap::Joker(Default::default())
                }
                DnsServerBootstrapType::Lightsail => {
                    *self = DnsServerBootstrap::Lightsail(Default::default())
                }
                DnsServerBootstrapType::Linode => {
                    *self = DnsServerBootstrap::Linode(Default::default())
                }
                DnsServerBootstrapType::LuaDns => {
                    *self = DnsServerBootstrap::LuaDns(Default::default())
                }
                DnsServerBootstrapType::MythicBeasts => {
                    *self = DnsServerBootstrap::MythicBeasts(Default::default())
                }
                DnsServerBootstrapType::Namecheap => {
                    *self = DnsServerBootstrap::Namecheap(Default::default())
                }
                DnsServerBootstrapType::NameDotCom => {
                    *self = DnsServerBootstrap::NameDotCom(Default::default())
                }
                DnsServerBootstrapType::NameSilo => {
                    *self = DnsServerBootstrap::NameSilo(Default::default())
                }
                DnsServerBootstrapType::Netcup => {
                    *self = DnsServerBootstrap::Netcup(Default::default())
                }
                DnsServerBootstrapType::Netlify => {
                    *self = DnsServerBootstrap::Netlify(Default::default())
                }
                DnsServerBootstrapType::Nifcloud => {
                    *self = DnsServerBootstrap::Nifcloud(Default::default())
                }
                DnsServerBootstrapType::Ns1 => *self = DnsServerBootstrap::Ns1(Default::default()),
                DnsServerBootstrapType::OracleCloud => {
                    *self = DnsServerBootstrap::OracleCloud(Default::default())
                }
                DnsServerBootstrapType::Plesk => {
                    *self = DnsServerBootstrap::Plesk(Default::default())
                }
                DnsServerBootstrapType::Safedns => {
                    *self = DnsServerBootstrap::Safedns(Default::default())
                }
                DnsServerBootstrapType::Scaleway => {
                    *self = DnsServerBootstrap::Scaleway(Default::default())
                }
                DnsServerBootstrapType::TencentCloud => {
                    *self = DnsServerBootstrap::TencentCloud(Default::default())
                }
                DnsServerBootstrapType::Transip => {
                    *self = DnsServerBootstrap::Transip(Default::default())
                }
                DnsServerBootstrapType::UltraDns => {
                    *self = DnsServerBootstrap::UltraDns(Default::default())
                }
                DnsServerBootstrapType::Vercel => {
                    *self = DnsServerBootstrap::Vercel(Default::default())
                }
                DnsServerBootstrapType::Volcengine => {
                    *self = DnsServerBootstrap::Volcengine(Default::default())
                }
                DnsServerBootstrapType::Vultr => {
                    *self = DnsServerBootstrap::Vultr(Default::default())
                }
                DnsServerBootstrapType::WebSupport => {
                    *self = DnsServerBootstrap::WebSupport(Default::default())
                }
                DnsServerBootstrapType::YandexCloud => {
                    *self = DnsServerBootstrap::YandexCloud(Default::default())
                }
            }
        }
        match self {
            DnsServerBootstrap::Manual => pointer.assert_eof(),
            DnsServerBootstrap::Tsig(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Deprecated1 => pointer.assert_eof(),
            DnsServerBootstrap::Cloudflare(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::DigitalOcean(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::DeSEC(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Ovh(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Bunny(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Porkbun(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Dnsimple(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Spaceship(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Route53(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::GoogleCloudDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Alidns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::ArvanCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Autodns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::AzureDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::BaiduCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::BluecatV2(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::ClouDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Constellix(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Cpanel(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Ddnss(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::DnsMadeEasy(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Domeneshop(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Dreamhost(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::DuckDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Dynu(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::EasyDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::EdgeDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Exoscale(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::FreeMyIp(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::GandiV5(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Gcore(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Glesys(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Godaddy(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Hetzner(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::HostingDe(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Hostinger(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::HuaweiCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Hurricane(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::IbmCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Infoblox(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Infomaniak(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Inwx(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Ionos(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Ipv64(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Joker(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Lightsail(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Linode(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::LuaDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::MythicBeasts(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Namecheap(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::NameDotCom(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::NameSilo(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Netcup(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Netlify(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Nifcloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Ns1(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::OracleCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Plesk(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Safedns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Scaleway(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::TencentCloud(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Transip(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::UltraDns(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Vercel(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Volcengine(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::Vultr(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::WebSupport(inner) => inner.patch(pointer, value),
            DnsServerBootstrap::YandexCloud(inner) => inner.patch(pointer, value),
        }
    }
}

impl DnsServerBootstrap {
    pub fn object_type(&self) -> DnsServerBootstrapType {
        match self {
            DnsServerBootstrap::Manual => DnsServerBootstrapType::Manual,
            DnsServerBootstrap::Tsig(_) => DnsServerBootstrapType::Tsig,
            DnsServerBootstrap::Deprecated1 => DnsServerBootstrapType::Deprecated1,
            DnsServerBootstrap::Cloudflare(_) => DnsServerBootstrapType::Cloudflare,
            DnsServerBootstrap::DigitalOcean(_) => DnsServerBootstrapType::DigitalOcean,
            DnsServerBootstrap::DeSEC(_) => DnsServerBootstrapType::DeSEC,
            DnsServerBootstrap::Ovh(_) => DnsServerBootstrapType::Ovh,
            DnsServerBootstrap::Bunny(_) => DnsServerBootstrapType::Bunny,
            DnsServerBootstrap::Porkbun(_) => DnsServerBootstrapType::Porkbun,
            DnsServerBootstrap::Dnsimple(_) => DnsServerBootstrapType::Dnsimple,
            DnsServerBootstrap::Spaceship(_) => DnsServerBootstrapType::Spaceship,
            DnsServerBootstrap::Route53(_) => DnsServerBootstrapType::Route53,
            DnsServerBootstrap::GoogleCloudDns(_) => DnsServerBootstrapType::GoogleCloudDns,
            DnsServerBootstrap::Alidns(_) => DnsServerBootstrapType::Alidns,
            DnsServerBootstrap::ArvanCloud(_) => DnsServerBootstrapType::ArvanCloud,
            DnsServerBootstrap::Autodns(_) => DnsServerBootstrapType::Autodns,
            DnsServerBootstrap::AzureDns(_) => DnsServerBootstrapType::AzureDns,
            DnsServerBootstrap::BaiduCloud(_) => DnsServerBootstrapType::BaiduCloud,
            DnsServerBootstrap::BluecatV2(_) => DnsServerBootstrapType::BluecatV2,
            DnsServerBootstrap::ClouDns(_) => DnsServerBootstrapType::ClouDns,
            DnsServerBootstrap::Constellix(_) => DnsServerBootstrapType::Constellix,
            DnsServerBootstrap::Cpanel(_) => DnsServerBootstrapType::Cpanel,
            DnsServerBootstrap::Ddnss(_) => DnsServerBootstrapType::Ddnss,
            DnsServerBootstrap::DnsMadeEasy(_) => DnsServerBootstrapType::DnsMadeEasy,
            DnsServerBootstrap::Domeneshop(_) => DnsServerBootstrapType::Domeneshop,
            DnsServerBootstrap::Dreamhost(_) => DnsServerBootstrapType::Dreamhost,
            DnsServerBootstrap::DuckDns(_) => DnsServerBootstrapType::DuckDns,
            DnsServerBootstrap::Dynu(_) => DnsServerBootstrapType::Dynu,
            DnsServerBootstrap::EasyDns(_) => DnsServerBootstrapType::EasyDns,
            DnsServerBootstrap::EdgeDns(_) => DnsServerBootstrapType::EdgeDns,
            DnsServerBootstrap::Exoscale(_) => DnsServerBootstrapType::Exoscale,
            DnsServerBootstrap::FreeMyIp(_) => DnsServerBootstrapType::FreeMyIp,
            DnsServerBootstrap::GandiV5(_) => DnsServerBootstrapType::GandiV5,
            DnsServerBootstrap::Gcore(_) => DnsServerBootstrapType::Gcore,
            DnsServerBootstrap::Glesys(_) => DnsServerBootstrapType::Glesys,
            DnsServerBootstrap::Godaddy(_) => DnsServerBootstrapType::Godaddy,
            DnsServerBootstrap::Hetzner(_) => DnsServerBootstrapType::Hetzner,
            DnsServerBootstrap::HostingDe(_) => DnsServerBootstrapType::HostingDe,
            DnsServerBootstrap::Hostinger(_) => DnsServerBootstrapType::Hostinger,
            DnsServerBootstrap::HuaweiCloud(_) => DnsServerBootstrapType::HuaweiCloud,
            DnsServerBootstrap::Hurricane(_) => DnsServerBootstrapType::Hurricane,
            DnsServerBootstrap::IbmCloud(_) => DnsServerBootstrapType::IbmCloud,
            DnsServerBootstrap::Infoblox(_) => DnsServerBootstrapType::Infoblox,
            DnsServerBootstrap::Infomaniak(_) => DnsServerBootstrapType::Infomaniak,
            DnsServerBootstrap::Inwx(_) => DnsServerBootstrapType::Inwx,
            DnsServerBootstrap::Ionos(_) => DnsServerBootstrapType::Ionos,
            DnsServerBootstrap::Ipv64(_) => DnsServerBootstrapType::Ipv64,
            DnsServerBootstrap::Joker(_) => DnsServerBootstrapType::Joker,
            DnsServerBootstrap::Lightsail(_) => DnsServerBootstrapType::Lightsail,
            DnsServerBootstrap::Linode(_) => DnsServerBootstrapType::Linode,
            DnsServerBootstrap::LuaDns(_) => DnsServerBootstrapType::LuaDns,
            DnsServerBootstrap::MythicBeasts(_) => DnsServerBootstrapType::MythicBeasts,
            DnsServerBootstrap::Namecheap(_) => DnsServerBootstrapType::Namecheap,
            DnsServerBootstrap::NameDotCom(_) => DnsServerBootstrapType::NameDotCom,
            DnsServerBootstrap::NameSilo(_) => DnsServerBootstrapType::NameSilo,
            DnsServerBootstrap::Netcup(_) => DnsServerBootstrapType::Netcup,
            DnsServerBootstrap::Netlify(_) => DnsServerBootstrapType::Netlify,
            DnsServerBootstrap::Nifcloud(_) => DnsServerBootstrapType::Nifcloud,
            DnsServerBootstrap::Ns1(_) => DnsServerBootstrapType::Ns1,
            DnsServerBootstrap::OracleCloud(_) => DnsServerBootstrapType::OracleCloud,
            DnsServerBootstrap::Plesk(_) => DnsServerBootstrapType::Plesk,
            DnsServerBootstrap::Safedns(_) => DnsServerBootstrapType::Safedns,
            DnsServerBootstrap::Scaleway(_) => DnsServerBootstrapType::Scaleway,
            DnsServerBootstrap::TencentCloud(_) => DnsServerBootstrapType::TencentCloud,
            DnsServerBootstrap::Transip(_) => DnsServerBootstrapType::Transip,
            DnsServerBootstrap::UltraDns(_) => DnsServerBootstrapType::UltraDns,
            DnsServerBootstrap::Vercel(_) => DnsServerBootstrapType::Vercel,
            DnsServerBootstrap::Volcengine(_) => DnsServerBootstrapType::Volcengine,
            DnsServerBootstrap::Vultr(_) => DnsServerBootstrapType::Vultr,
            DnsServerBootstrap::WebSupport(_) => DnsServerBootstrapType::WebSupport,
            DnsServerBootstrap::YandexCloud(_) => DnsServerBootstrapType::YandexCloud,
        }
    }
}

impl DnsServerClouDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.auth_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthId));
            }
        }
        if let Some(value) = &self.sub_auth_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::SubAuthId));
            }
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerClouDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_id.pickle(out);
        self.sub_auth_id.pickle(out);
        self.password.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_id = Pickle::unpickle(stream)?;
        this.sub_auth_id = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerClouDns {
    fn default() -> Self {
        Self {
            auth_id: Default::default(),
            sub_auth_id: Default::default(),
            password: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerClouDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::AuthId, self.auth_id.into_value());
        map.insert_unchecked(Property::SubAuthId, self.sub_auth_id.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerClouDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthId) => self
                .auth_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SubAuthId) => self
                .sub_auth_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerCloud {
    fn default() -> Self {
        Self {
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerCloudflare {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerCloudflare {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        if stream.version() < 1 {
            let _: Option<String> = Pickle::unpickle(stream)?;
        }
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerCloudflare {
    fn default() -> Self {
        Self {
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerCloudflare {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerCloudflare {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(property @ Property::Email) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerConstellix {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerConstellix {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerConstellix {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerConstellix {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerConstellix {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerCpanel {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.base_url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BaseUrl));
        }
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.token;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerCpanel {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.base_url.pickle(out);
        self.username.pickle(out);
        self.token.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.base_url = Pickle::unpickle(stream)?;
        this.username = Pickle::unpickle(stream)?;
        this.token = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerCpanel {
    fn default() -> Self {
        Self {
            base_url: Default::default(),
            username: Default::default(),
            token: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerCpanel {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::BaseUrl, self.base_url.into_value());
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Token, self.token.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerCpanel {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BaseUrl) => self
                .base_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Token) => self.token.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerDnsMadeEasy {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerDnsMadeEasy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerDnsMadeEasy {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerDnsMadeEasy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerDnsMadeEasy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerDnsimple {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth_token;
        value.validate(errors);
        let value = &self.account_identifier;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccountIdentifier));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerDnsimple {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_token.pickle(out);
        self.account_identifier.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_token = Pickle::unpickle(stream)?;
        this.account_identifier = Pickle::unpickle(stream)?;
        if stream.version() < 1 {
            let _: SecretKey = Pickle::unpickle(stream)?;
        }
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerDnsimple {
    fn default() -> Self {
        Self {
            auth_token: Default::default(),
            account_identifier: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerDnsimple {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AuthToken, self.auth_token.into_value());
        map.insert_unchecked(
            Property::AccountIdentifier,
            self.account_identifier.into_value(),
        );
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerDnsimple {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthToken) => self.auth_token.patch(pointer, value),
            Some(Property::AccountIdentifier) => self
                .account_identifier
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(property @ Property::Secret) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerDomeneshop {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth_token;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AuthToken));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerDomeneshop {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_token.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_token = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerDomeneshop {
    fn default() -> Self {
        Self {
            auth_token: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerDomeneshop {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AuthToken, self.auth_token.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerDomeneshop {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthToken) => self
                .auth_token
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerEasyDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.token;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Token));
        }
        let value = &self.key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerEasyDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.token.pickle(out);
        self.key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.token = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerEasyDns {
    fn default() -> Self {
        Self {
            token: Default::default(),
            key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerEasyDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Token, self.token.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerEasyDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Token) => self
                .token
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerEdgeDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.client_token;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ClientToken));
        }
        let value = &self.client_secret;
        value.validate(errors);
        let value = &self.access_token;
        value.validate(errors);
        if let Some(value) = &self.account_switch_key {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AccountSwitchKey));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerEdgeDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.host.pickle(out);
        self.client_token.pickle(out);
        self.client_secret.pickle(out);
        self.access_token.pickle(out);
        self.account_switch_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.host = Pickle::unpickle(stream)?;
        this.client_token = Pickle::unpickle(stream)?;
        this.client_secret = Pickle::unpickle(stream)?;
        this.access_token = Pickle::unpickle(stream)?;
        this.account_switch_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerEdgeDns {
    fn default() -> Self {
        Self {
            host: Default::default(),
            client_token: Default::default(),
            client_secret: Default::default(),
            access_token: Default::default(),
            account_switch_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerEdgeDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::ClientToken, self.client_token.into_value());
        map.insert_unchecked(Property::ClientSecret, self.client_secret.into_value());
        map.insert_unchecked(Property::AccessToken, self.access_token.into_value());
        map.insert_unchecked(
            Property::AccountSwitchKey,
            self.account_switch_key.into_value(),
        );
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerEdgeDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClientToken) => self
                .client_token
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClientSecret) => self.client_secret.patch(pointer, value),
            Some(Property::AccessToken) => self.access_token.patch(pointer, value),
            Some(Property::AccountSwitchKey) => self
                .account_switch_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerExoscale {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerExoscale {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerExoscale {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerExoscale {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerExoscale {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerGlesys {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_user;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiUser));
        }
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerGlesys {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_user.pickle(out);
        self.api_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_user = Pickle::unpickle(stream)?;
        this.api_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerGlesys {
    fn default() -> Self {
        Self {
            api_user: Default::default(),
            api_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerGlesys {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiUser, self.api_user.into_value());
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerGlesys {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiUser) => self
                .api_user
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerGodaddy {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerGodaddy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerGodaddy {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerGodaddy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerGodaddy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerGoogleCloudDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.service_account_json;
        value.validate(errors);
        let value = &self.project_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ProjectId));
        }
        if let Some(value) = &self.managed_zone {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ManagedZone));
            }
        }
        if let Some(value) = &self.impersonate_service_account {
            if value.is_empty() {
                errors.push(ValidationError::required(
                    Property::ImpersonateServiceAccount,
                ));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerGoogleCloudDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.service_account_json.pickle(out);
        self.project_id.pickle(out);
        self.managed_zone.pickle(out);
        self.private_zone.pickle(out);
        self.impersonate_service_account.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.service_account_json = Pickle::unpickle(stream)?;
        this.project_id = Pickle::unpickle(stream)?;
        this.managed_zone = Pickle::unpickle(stream)?;
        this.private_zone = Pickle::unpickle(stream)?;
        this.impersonate_service_account = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerGoogleCloudDns {
    fn default() -> Self {
        Self {
            service_account_json: Default::default(),
            project_id: Default::default(),
            managed_zone: Default::default(),
            private_zone: false,
            impersonate_service_account: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerGoogleCloudDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(
            Property::ServiceAccountJson,
            self.service_account_json.into_value(),
        );
        map.insert_unchecked(Property::ProjectId, self.project_id.into_value());
        map.insert_unchecked(Property::ManagedZone, self.managed_zone.into_value());
        map.insert_unchecked(Property::PrivateZone, self.private_zone.into_value());
        map.insert_unchecked(
            Property::ImpersonateServiceAccount,
            self.impersonate_service_account.into_value(),
        );
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerGoogleCloudDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ServiceAccountJson) => self.service_account_json.patch(pointer, value),
            Some(Property::ProjectId) => self
                .project_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ManagedZone) => self
                .managed_zone
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PrivateZone) => self.private_zone.patch(pointer, value),
            Some(Property::ImpersonateServiceAccount) => self
                .impersonate_service_account
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerHuaweiCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        let value = &self.region;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Region));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerHuaweiCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.region.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerHuaweiCloud {
    fn default() -> Self {
        Self {
            access_key: Default::default(),
            secret_key: Default::default(),
            region: "ap-southeast-1".to_string(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerHuaweiCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerHuaweiCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerHurricane {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.credentials;
        for value in value.values() {
            value.validate(errors);
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Credentials, 1));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerHurricane {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.credentials.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.credentials = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerHurricane {
    fn default() -> Self {
        Self {
            credentials: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerHurricane {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Credentials, self.credentials.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerHurricane {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Credentials) => self.credentials.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerIbmCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerIbmCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.api_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.api_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerIbmCloud {
    fn default() -> Self {
        Self {
            username: Default::default(),
            api_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerIbmCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerIbmCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerInfoblox {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        if let Some(value) = &self.port {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Port));
            }
        }
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        if let Some(value) = &self.wapi_version {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::WapiVersion));
            }
        }
        if let Some(value) = &self.dns_view {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DnsView));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerInfoblox {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.host.pickle(out);
        self.port.pickle(out);
        self.username.pickle(out);
        self.password.pickle(out);
        self.wapi_version.pickle(out);
        self.dns_view.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.wapi_version = Pickle::unpickle(stream)?;
        this.dns_view = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerInfoblox {
    fn default() -> Self {
        Self {
            host: Default::default(),
            port: Default::default(),
            username: Default::default(),
            password: Default::default(),
            wapi_version: Default::default(),
            dns_view: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerInfoblox {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::WapiVersion, self.wapi_version.into_value());
        map.insert_unchecked(Property::DnsView, self.dns_view.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerInfoblox {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self
                .port
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::WapiVersion) => self
                .wapi_version
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DnsView) => self
                .dns_view
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerInwx {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.shared_secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerInwx {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.password.pickle(out);
        self.shared_secret.pickle(out);
        self.sandbox.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.shared_secret = Pickle::unpickle(stream)?;
        this.sandbox = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerInwx {
    fn default() -> Self {
        Self {
            username: Default::default(),
            password: Default::default(),
            shared_secret: Default::default(),
            sandbox: false,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerInwx {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::SharedSecret, self.shared_secret.into_value());
        map.insert_unchecked(Property::Sandbox, self.sandbox.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerInwx {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::SharedSecret) => self.shared_secret.patch(pointer, value),
            Some(Property::Sandbox) => self.sandbox.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerJoker {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerJoker {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerJoker {
    fn default() -> Self {
        Self {
            auth: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerJoker {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Auth, self.auth.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerJoker {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Auth) => self.auth.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerLightsail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKeyId));
        }
        let value = &self.secret_access_key;
        value.validate(errors);
        let value = &self.session_token;
        value.validate(errors);
        if let Some(value) = &self.region {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Region));
            }
        }
        if let Some(value) = &self.domain {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Domain));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerLightsail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key_id.pickle(out);
        self.secret_access_key.pickle(out);
        self.session_token.pickle(out);
        self.region.pickle(out);
        self.domain.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key_id = Pickle::unpickle(stream)?;
        this.secret_access_key = Pickle::unpickle(stream)?;
        this.session_token = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.domain = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerLightsail {
    fn default() -> Self {
        Self {
            access_key_id: Default::default(),
            secret_access_key: Default::default(),
            session_token: Default::default(),
            region: Default::default(),
            domain: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerLightsail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::AccessKeyId, self.access_key_id.into_value());
        map.insert_unchecked(
            Property::SecretAccessKey,
            self.secret_access_key.into_value(),
        );
        map.insert_unchecked(Property::SessionToken, self.session_token.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::Domain, self.domain.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerLightsail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKeyId) => self
                .access_key_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretAccessKey) => self.secret_access_key.patch(pointer, value),
            Some(Property::SessionToken) => self.session_token.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Domain) => self
                .domain
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerLuaDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.auth_token;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerLuaDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.auth_token.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.auth_token = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerLuaDns {
    fn default() -> Self {
        Self {
            username: Default::default(),
            auth_token: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerLuaDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::AuthToken, self.auth_token.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerLuaDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthToken) => self.auth_token.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerMythicBeasts {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerMythicBeasts {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.password.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerMythicBeasts {
    fn default() -> Self {
        Self {
            username: Default::default(),
            password: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerMythicBeasts {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerMythicBeasts {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerNameDotCom {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.auth_token;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerNameDotCom {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.auth_token.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.auth_token = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerNameDotCom {
    fn default() -> Self {
        Self {
            username: Default::default(),
            auth_token: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerNameDotCom {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::AuthToken, self.auth_token.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerNameDotCom {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthToken) => self.auth_token.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerNamecheap {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_user;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiUser));
        }
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.client_ip;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ClientIp));
        }
        if let Some(value) = &self.username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Username));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerNamecheap {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_user.pickle(out);
        self.api_key.pickle(out);
        self.client_ip.pickle(out);
        self.username.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_user = Pickle::unpickle(stream)?;
        this.api_key = Pickle::unpickle(stream)?;
        this.client_ip = Pickle::unpickle(stream)?;
        this.username = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerNamecheap {
    fn default() -> Self {
        Self {
            api_user: Default::default(),
            api_key: Default::default(),
            client_ip: Default::default(),
            username: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerNamecheap {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::ApiUser, self.api_user.into_value());
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::ClientIp, self.client_ip.into_value());
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerNamecheap {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiUser) => self
                .api_user
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::ClientIp) => self
                .client_ip
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerNetcup {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.customer_number;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::CustomerNumber));
        }
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.password;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerNetcup {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.customer_number.pickle(out);
        self.api_key.pickle(out);
        self.password.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.customer_number = Pickle::unpickle(stream)?;
        this.api_key = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerNetcup {
    fn default() -> Self {
        Self {
            customer_number: Default::default(),
            api_key: Default::default(),
            password: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerNetcup {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::CustomerNumber, self.customer_number.into_value());
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerNetcup {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CustomerNumber) => self
                .customer_number
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerNifcloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerNifcloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerNifcloud {
    fn default() -> Self {
        Self {
            access_key: Default::default(),
            secret_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerNifcloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerNifcloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerOracleCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tenancy_ocid;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::TenancyOcid));
        }
        let value = &self.user_ocid;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::UserOcid));
        }
        let value = &self.fingerprint;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Fingerprint));
        }
        let value = &self.private_key_pem;
        value.validate(errors);
        let value = &self.private_key_password;
        value.validate(errors);
        let value = &self.region;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Region));
        }
        let value = &self.compartment_ocid;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::CompartmentOcid));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerOracleCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tenancy_ocid.pickle(out);
        self.user_ocid.pickle(out);
        self.fingerprint.pickle(out);
        self.private_key_pem.pickle(out);
        self.private_key_password.pickle(out);
        self.region.pickle(out);
        self.compartment_ocid.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tenancy_ocid = Pickle::unpickle(stream)?;
        this.user_ocid = Pickle::unpickle(stream)?;
        this.fingerprint = Pickle::unpickle(stream)?;
        this.private_key_pem = Pickle::unpickle(stream)?;
        this.private_key_password = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.compartment_ocid = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerOracleCloud {
    fn default() -> Self {
        Self {
            tenancy_ocid: Default::default(),
            user_ocid: Default::default(),
            fingerprint: Default::default(),
            private_key_pem: Default::default(),
            private_key_password: Default::default(),
            region: Default::default(),
            compartment_ocid: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerOracleCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(Property::TenancyOcid, self.tenancy_ocid.into_value());
        map.insert_unchecked(Property::UserOcid, self.user_ocid.into_value());
        map.insert_unchecked(Property::Fingerprint, self.fingerprint.into_value());
        map.insert_unchecked(Property::PrivateKeyPem, self.private_key_pem.into_value());
        map.insert_unchecked(
            Property::PrivateKeyPassword,
            self.private_key_password.into_value(),
        );
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(
            Property::CompartmentOcid,
            self.compartment_ocid.into_value(),
        );
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerOracleCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TenancyOcid) => self
                .tenancy_ocid
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::UserOcid) => self
                .user_ocid
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Fingerprint) => self
                .fingerprint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PrivateKeyPem) => self.private_key_pem.patch(pointer, value),
            Some(Property::PrivateKeyPassword) => self.private_key_password.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::CompartmentOcid) => self
                .compartment_ocid
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerOvh {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.application_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApplicationKey));
        }
        let value = &self.application_secret;
        value.validate(errors);
        let value = &self.consumer_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerOvh {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.application_key.pickle(out);
        self.application_secret.pickle(out);
        self.consumer_key.pickle(out);
        self.ovh_endpoint.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.application_key = Pickle::unpickle(stream)?;
        this.application_secret = Pickle::unpickle(stream)?;
        this.consumer_key = Pickle::unpickle(stream)?;
        this.ovh_endpoint = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerOvh {
    fn default() -> Self {
        Self {
            application_key: Default::default(),
            application_secret: Default::default(),
            consumer_key: Default::default(),
            ovh_endpoint: OvhEndpoint::OvhEu,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerOvh {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::ApplicationKey, self.application_key.into_value());
        map.insert_unchecked(
            Property::ApplicationSecret,
            self.application_secret.into_value(),
        );
        map.insert_unchecked(Property::ConsumerKey, self.consumer_key.into_value());
        map.insert_unchecked(Property::OvhEndpoint, self.ovh_endpoint.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerOvh {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApplicationKey) => self
                .application_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApplicationSecret) => self.application_secret.patch(pointer, value),
            Some(Property::ConsumerKey) => self.consumer_key.patch(pointer, value),
            Some(Property::OvhEndpoint) => self.ovh_endpoint.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerPlesk {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.base_url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BaseUrl));
        }
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerPlesk {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.base_url.pickle(out);
        self.api_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.base_url = Pickle::unpickle(stream)?;
        this.api_key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerPlesk {
    fn default() -> Self {
        Self {
            base_url: Default::default(),
            api_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerPlesk {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::BaseUrl, self.base_url.into_value());
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerPlesk {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BaseUrl) => self
                .base_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerPorkbun {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret_api_key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerPorkbun {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret_api_key.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret_api_key = Pickle::unpickle(stream)?;
        if stream.version() < 1 {
            let _: SecretKey = Pickle::unpickle(stream)?;
        }
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerPorkbun {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret_api_key: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerPorkbun {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::SecretApiKey, self.secret_api_key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerPorkbun {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretApiKey) => self.secret_api_key.patch(pointer, value),
            Some(property @ Property::Secret) => Ok(MaybeUnpatched::Unpatched { property, value }),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerRoute53 {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKeyId));
        }
        let value = &self.secret_access_key;
        value.validate(errors);
        let value = &self.session_token;
        value.validate(errors);
        let value = &self.region;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Region));
        }
        if let Some(value) = &self.hosted_zone_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HostedZoneId));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerRoute53 {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key_id.pickle(out);
        self.secret_access_key.pickle(out);
        self.session_token.pickle(out);
        self.region.pickle(out);
        self.hosted_zone_id.pickle(out);
        self.private_zone_only.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key_id = Pickle::unpickle(stream)?;
        this.secret_access_key = Pickle::unpickle(stream)?;
        this.session_token = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.hosted_zone_id = Pickle::unpickle(stream)?;
        this.private_zone_only = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerRoute53 {
    fn default() -> Self {
        Self {
            access_key_id: Default::default(),
            secret_access_key: Default::default(),
            session_token: Default::default(),
            region: "us-east-1".to_string(),
            hosted_zone_id: Default::default(),
            private_zone_only: false,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerRoute53 {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::AccessKeyId, self.access_key_id.into_value());
        map.insert_unchecked(
            Property::SecretAccessKey,
            self.secret_access_key.into_value(),
        );
        map.insert_unchecked(Property::SessionToken, self.session_token.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::HostedZoneId, self.hosted_zone_id.into_value());
        map.insert_unchecked(
            Property::PrivateZoneOnly,
            self.private_zone_only.into_value(),
        );
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerRoute53 {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKeyId) => self
                .access_key_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretAccessKey) => self.secret_access_key.patch(pointer, value),
            Some(Property::SessionToken) => self.session_token.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::HostedZoneId) => self
                .hosted_zone_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PrivateZoneOnly) => self.private_zone_only.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerSpaceship {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerSpaceship {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerSpaceship {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerSpaceship {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerSpaceship {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerTencentCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.secret_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::SecretId));
        }
        let value = &self.secret_key;
        value.validate(errors);
        if let Some(value) = &self.region {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Region));
            }
        }
        let value = &self.session_token;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerTencentCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret_id.pickle(out);
        self.secret_key.pickle(out);
        self.region.pickle(out);
        self.session_token.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.secret_id = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.session_token = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerTencentCloud {
    fn default() -> Self {
        Self {
            secret_id: Default::default(),
            secret_key: Default::default(),
            region: Default::default(),
            session_token: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerTencentCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::SecretId, self.secret_id.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::SessionToken, self.session_token.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerTencentCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::SecretId) => self
                .secret_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SessionToken) => self.session_token.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerTransip {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.private_key_pem;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerTransip {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.private_key_pem.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.private_key_pem = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerTransip {
    fn default() -> Self {
        Self {
            username: Default::default(),
            private_key_pem: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerTransip {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::PrivateKeyPem, self.private_key_pem.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerTransip {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PrivateKeyPem) => self.private_key_pem.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerTsig {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.host;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Host, value));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.key_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::KeyName));
        }
        let value = &self.key;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerTsig {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.host.pickle(out);
        self.port.pickle(out);
        self.key_name.pickle(out);
        self.key.pickle(out);
        self.protocol.pickle(out);
        self.tsig_algorithm.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.key_name = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.protocol = Pickle::unpickle(stream)?;
        this.tsig_algorithm = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerTsig {
    fn default() -> Self {
        Self {
            host: Default::default(),
            port: 53u64,
            key_name: Default::default(),
            key: Default::default(),
            protocol: IpProtocol::Udp,
            tsig_algorithm: TsigAlgorithm::HmacSha512,
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerTsig {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::KeyName, self.key_name.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Protocol, self.protocol.into_value());
        map.insert_unchecked(Property::TsigAlgorithm, self.tsig_algorithm.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerTsig {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::KeyName) => self
                .key_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Protocol) => self.protocol.patch(pointer, value),
            Some(Property::TsigAlgorithm) => self.tsig_algorithm.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerUltraDns {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        if let Some(value) = &self.endpoint {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Endpoint));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerUltraDns {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.password.pickle(out);
        self.endpoint.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        this.endpoint = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerUltraDns {
    fn default() -> Self {
        Self {
            username: Default::default(),
            password: Default::default(),
            endpoint: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerUltraDns {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        map.insert_unchecked(Property::Endpoint, self.endpoint.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerUltraDns {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Endpoint) => self
                .endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerVercel {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth_token;
        value.validate(errors);
        if let Some(value) = &self.team_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::TeamId));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerVercel {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_token.pickle(out);
        self.team_id.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_token = Pickle::unpickle(stream)?;
        this.team_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerVercel {
    fn default() -> Self {
        Self {
            auth_token: Default::default(),
            team_id: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerVercel {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AuthToken, self.auth_token.into_value());
        map.insert_unchecked(Property::TeamId, self.team_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerVercel {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthToken) => self.auth_token.patch(pointer, value),
            Some(Property::TeamId) => self
                .team_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerVolcengine {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.access_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccessKey));
        }
        let value = &self.secret_key;
        value.validate(errors);
        if let Some(value) = &self.region {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Region));
            }
        }
        if let Some(value) = &self.host {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Host));
            }
        }
        if let Some(value) = &self.scheme {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Scheme));
            }
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerVolcengine {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.region.pickle(out);
        self.host.pickle(out);
        self.scheme.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.region = Pickle::unpickle(stream)?;
        this.host = Pickle::unpickle(stream)?;
        this.scheme = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerVolcengine {
    fn default() -> Self {
        Self {
            access_key: Default::default(),
            secret_key: Default::default(),
            region: Default::default(),
            host: Default::default(),
            scheme: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerVolcengine {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Scheme, self.scheme.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerVolcengine {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::Region) => self
                .region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Scheme) => self
                .scheme
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerWebSupport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ApiKey));
        }
        let value = &self.secret;
        value.validate(errors);
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerWebSupport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.secret.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerWebSupport {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            secret: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerWebSupport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerWebSupport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self
                .api_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl DnsServerYandexCloud {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.folder_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FolderId));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for DnsServerYandexCloud {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.folder_id.pickle(out);
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.timeout.pickle(out);
        self.ttl.pickle(out);
        self.polling_interval.pickle(out);
        self.propagation_timeout.pickle(out);
        self.propagation_delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.folder_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.ttl = Pickle::unpickle(stream)?;
        this.polling_interval = Pickle::unpickle(stream)?;
        this.propagation_timeout = Pickle::unpickle(stream)?;
        this.propagation_delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DnsServerYandexCloud {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            folder_id: Default::default(),
            description: Default::default(),
            member_tenant_id: Default::default(),
            timeout: Duration::from_millis(30000),
            ttl: Duration::from_millis(300000),
            polling_interval: Duration::from_millis(15000),
            propagation_timeout: Duration::from_millis(60000),
            propagation_delay: Default::default(),
        }
    }
}

impl IntoValue for DnsServerYandexCloud {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::FolderId, self.folder_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Ttl, self.ttl.into_value());
        map.insert_unchecked(
            Property::PollingInterval,
            self.polling_interval.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationTimeout,
            self.propagation_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PropagationDelay,
            self.propagation_delay.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DnsServerYandexCloud {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::FolderId) => self
                .folder_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Ttl) => self.ttl.patch(pointer, value),
            Some(Property::PollingInterval) => self.polling_interval.patch(pointer, value),
            Some(Property::PropagationTimeout) => self.propagation_timeout.patch(pointer, value),
            Some(Property::PropagationDelay) => self.propagation_delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Domain {
    const FLAGS: u64 = OBJ_FILTER_TENANT | OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Domain;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.aliases;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Aliases));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        if let Some(value) = &self.logo {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Logo));
            }
        }
        let value = &self.certificate_management;
        value.validate(errors);
        let value = &self.dkim_management;
        value.validate(errors);
        let value = &self.dns_management;
        value.validate(errors);
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        if let Some(value) = &self.directory_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DirectoryId));
            }
        }
        if let Some(value) = &self.catch_all_address {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::CatchAllAddress));
            }
        }
        let value = &self.sub_addressing;
        value.validate(errors);
        if let Some(value) = &self.report_address_uri {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReportAddressUri));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
        i.text(Property::Text, &self.name);
        for value in self.aliases.iter() {
            i.text(Property::Text, value);
        }
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        self.certificate_management.index(i);
        self.dns_management.index(i);
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
        i.foreign_key(ObjectType::Directory, self.directory_id, None);
    }
}

impl Pickle for Domain {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.aliases.pickle(out);
        self.is_enabled.pickle(out);
        self.created_at.pickle(out);
        self.description.pickle(out);
        self.logo.pickle(out);
        self.certificate_management.pickle(out);
        self.dkim_management.pickle(out);
        self.dns_management.pickle(out);
        self.member_tenant_id.pickle(out);
        self.directory_id.pickle(out);
        self.catch_all_address.pickle(out);
        self.sub_addressing.pickle(out);
        self.allow_relaying.pickle(out);
        self.report_address_uri.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.aliases = Pickle::unpickle(stream)?;
        this.is_enabled = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.logo = Pickle::unpickle(stream)?;
        this.certificate_management = Pickle::unpickle(stream)?;
        this.dkim_management = Pickle::unpickle(stream)?;
        this.dns_management = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.directory_id = Pickle::unpickle(stream)?;
        this.catch_all_address = Pickle::unpickle(stream)?;
        this.sub_addressing = Pickle::unpickle(stream)?;
        this.allow_relaying = Pickle::unpickle(stream)?;
        this.report_address_uri = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Domain {
    fn default() -> Self {
        Self {
            name: Default::default(),
            aliases: Default::default(),
            is_enabled: true,
            created_at: Default::default(),
            description: Default::default(),
            logo: Default::default(),
            certificate_management: Default::default(),
            dkim_management: Default::default(),
            dns_management: Default::default(),
            member_tenant_id: Default::default(),
            directory_id: Default::default(),
            catch_all_address: Default::default(),
            sub_addressing: Default::default(),
            allow_relaying: false,
            report_address_uri: Some("mailto:postmaster".to_string()),
        }
    }
}

impl IntoValue for Domain {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(17);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Aliases, self.aliases.into_value());
        map.insert_unchecked(Property::IsEnabled, self.is_enabled.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Logo, self.logo.into_value());
        map.insert_unchecked(
            Property::CertificateManagement,
            self.certificate_management.into_value(),
        );
        map.insert_unchecked(Property::DkimManagement, self.dkim_management.into_value());
        map.insert_unchecked(Property::DnsManagement, self.dns_management.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::DirectoryId, self.directory_id.into_value());
        map.insert_unchecked(
            Property::CatchAllAddress,
            self.catch_all_address.into_value(),
        );
        map.insert_unchecked(Property::SubAddressing, self.sub_addressing.into_value());
        map.insert_unchecked(Property::AllowRelaying, self.allow_relaying.into_value());
        map.insert_unchecked(
            Property::ReportAddressUri,
            self.report_address_uri.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Domain {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self
                .name
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::Aliases) => self
                .aliases
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::IsEnabled) => self.is_enabled.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Logo) => self.logo.patch(pointer, value),
            Some(Property::CertificateManagement) => {
                self.certificate_management.patch(pointer, value)
            }
            Some(Property::DkimManagement) => self.dkim_management.patch(pointer, value),
            Some(Property::DnsManagement) => self.dns_management.patch(pointer, value),
            Some(Property::DnsZoneFile) => pointer.assert_server_set(),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::DirectoryId) => self.directory_id.patch(pointer, value),
            Some(Property::CatchAllAddress) => self
                .catch_all_address
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::SubAddressing) => self.sub_addressing.patch(pointer, value),
            Some(Property::AllowRelaying) => self.allow_relaying.patch(pointer, value),
            Some(Property::ReportAddressUri) => self
                .report_address_uri
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for DsnReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::DsnReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from_address;
        value.validate(errors);
        let value = &self.from_name;
        value.validate(errors);
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl DsnReportSettings {
    pub fn ctx_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_address,
            default: Some(Expression {
                else_: "'MAILER-DAEMON@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FromAddress,
            allowed_variables: MTA_QUEUE_SENDER_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_name,
            default: Some(Expression {
                else_: "'Mail Delivery Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::FromName,
            allowed_variables: MTA_QUEUE_SENDER_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_QUEUE_SENDER_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_from_address(),
            self.ctx_from_name(),
            self.ctx_dkim_sign_domain(),
        ]
    }
}

impl Pickle for DsnReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from_address.pickle(out);
        self.from_name.pickle(out);
        self.dkim_sign_domain.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from_address = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for DsnReportSettings {
    fn default() -> Self {
        Self {
            from_address: Expression {
                else_: "'MAILER-DAEMON@' + system('domain')".to_string(),
                ..Default::default()
            },
            from_name: Expression {
                else_: "'Mail Delivery Subsystem'".to_string(),
                ..Default::default()
            },
            dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for DsnReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::FromAddress, self.from_address.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for DsnReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::FromAddress) => self.from_address.patch(pointer, value),
            Some(Property::FromName) => self.from_name.patch(pointer, value),
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ElasticSearchStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.num_replicas;
        if *value > 2048 {
            errors.push(ValidationError::max_value(Property::NumReplicas, 2048));
        }
        let value = &self.num_shards;
        if *value > 1048576 {
            errors.push(ValidationError::max_value(Property::NumShards, 1048576));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::NumShards, 1));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for ElasticSearchStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.url.pickle(out);
        self.num_replicas.pickle(out);
        self.num_shards.pickle(out);
        self.include_source.pickle(out);
        self.timeout.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.url = Pickle::unpickle(stream)?;
        this.num_replicas = Pickle::unpickle(stream)?;
        this.num_shards = Pickle::unpickle(stream)?;
        this.include_source = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ElasticSearchStore {
    fn default() -> Self {
        Self {
            url: Default::default(),
            num_replicas: 0u64,
            num_shards: 3u64,
            include_source: false,
            timeout: Duration::from_millis(30000),
            allow_invalid_certs: false,
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for ElasticSearchStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::NumReplicas, self.num_replicas.into_value());
        map.insert_unchecked(Property::NumShards, self.num_shards.into_value());
        map.insert_unchecked(Property::IncludeSource, self.include_source.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ElasticSearchStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::NumReplicas) => self.num_replicas.patch(pointer, value),
            Some(Property::NumShards) => self.num_shards.patch(pointer, value),
            Some(Property::IncludeSource) => self.include_source.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Email {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Email;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_attachment_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxAttachmentSize, 1));
        }
        let value = &self.max_message_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMessageSize, 1));
        }
        let value = &self.max_mailbox_depth;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMailboxDepth, 1));
        }
        let value = &self.max_mailbox_name_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(
                Property::MaxMailboxNameLength,
                1,
            ));
        }
        let value = &self.default_folders;
        for value in value.values() {
            value.validate(errors);
        }
        if let Some(value) = &self.max_messages {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxMessages, 1));
            }
        }
        if let Some(value) = &self.max_submissions {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxSubmissions, 1));
            }
        }
        if let Some(value) = &self.max_identities {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxIdentities, 1));
            }
        }
        if let Some(value) = &self.max_mailboxes {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxMailboxes, 1));
            }
        }
        if let Some(value) = &self.max_masked_addresses {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxMaskedAddresses, 1));
            }
        }
        if let Some(value) = &self.max_public_keys {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxPublicKeys, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Email {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_attachment_size.pickle(out);
        self.max_message_size.pickle(out);
        self.max_mailbox_depth.pickle(out);
        self.max_mailbox_name_length.pickle(out);
        self.encrypt_on_append.pickle(out);
        self.encrypt_at_rest.pickle(out);
        self.compression_algorithm.pickle(out);
        self.default_folders.pickle(out);
        self.max_messages.pickle(out);
        self.max_submissions.pickle(out);
        self.max_identities.pickle(out);
        self.max_mailboxes.pickle(out);
        self.max_masked_addresses.pickle(out);
        self.max_public_keys.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_attachment_size = Pickle::unpickle(stream)?;
        this.max_message_size = Pickle::unpickle(stream)?;
        this.max_mailbox_depth = Pickle::unpickle(stream)?;
        this.max_mailbox_name_length = Pickle::unpickle(stream)?;
        this.encrypt_on_append = Pickle::unpickle(stream)?;
        this.encrypt_at_rest = Pickle::unpickle(stream)?;
        this.compression_algorithm = Pickle::unpickle(stream)?;
        this.default_folders = Pickle::unpickle(stream)?;
        this.max_messages = Pickle::unpickle(stream)?;
        this.max_submissions = Pickle::unpickle(stream)?;
        this.max_identities = Pickle::unpickle(stream)?;
        this.max_mailboxes = Pickle::unpickle(stream)?;
        this.max_masked_addresses = Pickle::unpickle(stream)?;
        this.max_public_keys = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Email {
    fn default() -> Self {
        Self {
            max_attachment_size: 50000000u64,
            max_message_size: 75000000u64,
            max_mailbox_depth: 10u64,
            max_mailbox_name_length: 255u64,
            encrypt_on_append: false,
            encrypt_at_rest: true,
            compression_algorithm: CompressionAlgo::Lz4,
            default_folders: Default::default(),
            max_messages: Default::default(),
            max_submissions: Some(500u64),
            max_identities: Some(20u64),
            max_mailboxes: Some(250u64),
            max_masked_addresses: Some(5u64),
            max_public_keys: Some(5u64),
        }
    }
}

impl IntoValue for Email {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(
            Property::MaxAttachmentSize,
            self.max_attachment_size.into_value(),
        );
        map.insert_unchecked(Property::MaxMessageSize, self.max_message_size.into_value());
        map.insert_unchecked(
            Property::MaxMailboxDepth,
            self.max_mailbox_depth.into_value(),
        );
        map.insert_unchecked(
            Property::MaxMailboxNameLength,
            self.max_mailbox_name_length.into_value(),
        );
        map.insert_unchecked(
            Property::EncryptOnAppend,
            self.encrypt_on_append.into_value(),
        );
        map.insert_unchecked(Property::EncryptAtRest, self.encrypt_at_rest.into_value());
        map.insert_unchecked(
            Property::CompressionAlgorithm,
            self.compression_algorithm.into_value(),
        );
        map.insert_unchecked(Property::DefaultFolders, self.default_folders.into_value());
        map.insert_unchecked(Property::MaxMessages, self.max_messages.into_value());
        map.insert_unchecked(Property::MaxSubmissions, self.max_submissions.into_value());
        map.insert_unchecked(Property::MaxIdentities, self.max_identities.into_value());
        map.insert_unchecked(Property::MaxMailboxes, self.max_mailboxes.into_value());
        map.insert_unchecked(
            Property::MaxMaskedAddresses,
            self.max_masked_addresses.into_value(),
        );
        map.insert_unchecked(Property::MaxPublicKeys, self.max_public_keys.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Email {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxAttachmentSize) => self.max_attachment_size.patch(pointer, value),
            Some(Property::MaxMessageSize) => self.max_message_size.patch(pointer, value),
            Some(Property::MaxMailboxDepth) => self.max_mailbox_depth.patch(pointer, value),
            Some(Property::MaxMailboxNameLength) => {
                self.max_mailbox_name_length.patch(pointer, value)
            }
            Some(Property::EncryptOnAppend) => self.encrypt_on_append.patch(pointer, value),
            Some(Property::EncryptAtRest) => self.encrypt_at_rest.patch(pointer, value),
            Some(Property::CompressionAlgorithm) => {
                self.compression_algorithm.patch(pointer, value)
            }
            Some(Property::DefaultFolders) => self.default_folders.patch(pointer, value),
            Some(Property::MaxMessages) => self.max_messages.patch(pointer, value),
            Some(Property::MaxSubmissions) => self.max_submissions.patch(pointer, value),
            Some(Property::MaxIdentities) => self.max_identities.patch(pointer, value),
            Some(Property::MaxMailboxes) => self.max_mailboxes.patch(pointer, value),
            Some(Property::MaxMaskedAddresses) => self.max_masked_addresses.patch(pointer, value),
            Some(Property::MaxPublicKeys) => self.max_public_keys.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl EmailAlias {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Email, &self.name, &self.domain_id);
        i.text(Property::Text, &self.name);
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
    }
}

impl Pickle for EmailAlias {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enabled.pickle(out);
        self.name.pickle(out);
        self.domain_id.pickle(out);
        self.description.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enabled = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for EmailAlias {
    fn default() -> Self {
        Self {
            enabled: true,
            name: Default::default(),
            domain_id: Default::default(),
            description: Default::default(),
        }
    }
}

impl IntoValue for EmailAlias {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Enabled, self.enabled.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for EmailAlias {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enabled) => self.enabled.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer.with_validators(&[StringValidator::EmailLocalPart]),
                value,
            ),
            Some(Property::DomainId) => self.domain_id.patch(pointer, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl EmailFolder {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.aliases;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Aliases));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for EmailFolder {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.create.pickle(out);
        self.subscribe.pickle(out);
        self.aliases.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.create = Pickle::unpickle(stream)?;
        this.subscribe = Pickle::unpickle(stream)?;
        this.aliases = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for EmailFolder {
    fn default() -> Self {
        Self {
            name: Default::default(),
            create: true,
            subscribe: true,
            aliases: Default::default(),
        }
    }
}

impl IntoValue for EmailFolder {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Create, self.create.into_value());
        map.insert_unchecked(Property::Subscribe, self.subscribe.into_value());
        map.insert_unchecked(Property::Aliases, self.aliases.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for EmailFolder {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self
                .name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Create) => self.create.patch(pointer, value),
            Some(Property::Subscribe) => self.subscribe.patch(pointer, value),
            Some(Property::Aliases) => self
                .aliases
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl EncryptionAtRest {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            EncryptionAtRest::Disabled => true,
            EncryptionAtRest::Aes128(inner) => inner.validate(errors),
            EncryptionAtRest::Aes256(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            EncryptionAtRest::Disabled => {}
            EncryptionAtRest::Aes128(object) => {
                object.index(i);
            }
            EncryptionAtRest::Aes256(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for EncryptionAtRest {
    fn default() -> Self {
        EncryptionAtRest::Disabled
    }
}

impl Pickle for EncryptionAtRest {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            EncryptionAtRest::Disabled => {
                0u16.pickle(out);
            }
            EncryptionAtRest::Aes128(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            EncryptionAtRest::Aes256(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(EncryptionAtRest::Disabled),
            1 => Pickle::unpickle(stream).map(EncryptionAtRest::Aes128),
            2 => Pickle::unpickle(stream).map(EncryptionAtRest::Aes256),
            _ => None,
        }
    }
}

impl IntoValue for EncryptionAtRest {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            EncryptionAtRest::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            EncryptionAtRest::Aes128(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Aes128".into()));
                obj
            }
            EncryptionAtRest::Aes256(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Aes256".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for EncryptionAtRest {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                EncryptionAtRestType::Disabled => *self = EncryptionAtRest::Disabled,
                EncryptionAtRestType::Aes128 => {
                    *self = EncryptionAtRest::Aes128(Default::default())
                }
                EncryptionAtRestType::Aes256 => {
                    *self = EncryptionAtRest::Aes256(Default::default())
                }
            }
        }
        match self {
            EncryptionAtRest::Disabled => pointer.assert_eof(),
            EncryptionAtRest::Aes128(inner) => inner.patch(pointer, value),
            EncryptionAtRest::Aes256(inner) => inner.patch(pointer, value),
        }
    }
}

impl EncryptionAtRest {
    pub fn object_type(&self) -> EncryptionAtRestType {
        match self {
            EncryptionAtRest::Disabled => EncryptionAtRestType::Disabled,
            EncryptionAtRest::Aes128(_) => EncryptionAtRestType::Aes128,
            EncryptionAtRest::Aes256(_) => EncryptionAtRestType::Aes256,
        }
    }
}

impl EncryptionSettings {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.public_key;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::PublicKey));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::PublicKey, self.public_key.into(), None);
    }
}

impl Pickle for EncryptionSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.public_key.pickle(out);
        self.encrypt_on_append.pickle(out);
        self.allow_spam_training.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.public_key = Pickle::unpickle(stream)?;
        this.encrypt_on_append = Pickle::unpickle(stream)?;
        this.allow_spam_training = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for EncryptionSettings {
    fn default() -> Self {
        Self {
            public_key: Default::default(),
            encrypt_on_append: false,
            allow_spam_training: false,
        }
    }
}

impl IntoValue for EncryptionSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::PublicKey, self.public_key.into_value());
        map.insert_unchecked(
            Property::EncryptOnAppend,
            self.encrypt_on_append.into_value(),
        );
        map.insert_unchecked(
            Property::AllowSpamTraining,
            self.allow_spam_training.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for EncryptionSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::PublicKey) => self.public_key.patch(pointer, value),
            Some(Property::EncryptOnAppend) => self.encrypt_on_append.patch(pointer, value),
            Some(Property::AllowSpamTraining) => self.allow_spam_training.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Enterprise {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Enterprise;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        value.validate(errors);
        let value = &self.license_key;
        value.validate(errors);
        if let Some(value) = &self.logo_url {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::LogoUrl));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Enterprise {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
        self.license_key.pickle(out);
        self.logo_url.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        this.license_key = Pickle::unpickle(stream)?;
        this.logo_url = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Enterprise {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
            license_key: Default::default(),
            logo_url: Default::default(),
        }
    }
}

impl IntoValue for Enterprise {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        map.insert_unchecked(Property::LicenseKey, self.license_key.into_value());
        map.insert_unchecked(Property::LogoUrl, self.logo_url.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Enterprise {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::LicenseKey) => self.license_key.patch(pointer, value),
            Some(Property::LogoUrl) => self
                .logo_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for EventTracingLevel {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::EventTracingLevel;

    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Event, &self.event);
    }
}

impl Pickle for EventTracingLevel {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.event.pickle(out);
        self.level.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.event = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for EventTracingLevel {
    fn default() -> Self {
        Self {
            event: Default::default(),
            level: TracingLevelOpt::Info,
        }
    }
}

impl IntoValue for EventTracingLevel {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Event, self.event.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for EventTracingLevel {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Event) => self.event.patch(pointer.assert_read_only()?, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Expression {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.match_;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.else_;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Else));
        }
        errors.len() == neb
    }
}

impl Pickle for Expression {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.match_.pickle(out);
        self.else_.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.match_ = Pickle::unpickle(stream)?;
        this.else_ = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Expression {
    fn default() -> Self {
        Self {
            match_: Default::default(),
            else_: Default::default(),
        }
    }
}

impl IntoValue for Expression {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Match, self.match_.into_value());
        map.insert_unchecked(Property::Else, self.else_.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Expression {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Match) => self.match_.patch(pointer, value),
            Some(Property::Else) => self.else_.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ExpressionMatch {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.if_;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::If));
        }
        let value = &self.then;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Then));
        }
        errors.len() == neb
    }
}

impl Pickle for ExpressionMatch {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.if_.pickle(out);
        self.then.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.if_ = Pickle::unpickle(stream)?;
        this.then = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ExpressionMatch {
    fn default() -> Self {
        Self {
            if_: Default::default(),
            then: Default::default(),
        }
    }
}

impl IntoValue for ExpressionMatch {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::If, self.if_.into_value());
        map.insert_unchecked(Property::Then, self.then.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ExpressionMatch {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::If) => self.if_.patch(pointer, value),
            Some(Property::Then) => self.then.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for FileStorage {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::FileStorage;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.max_files {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxFiles, 1));
            }
        }
        if let Some(value) = &self.max_folders {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxFolders, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for FileStorage {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_size.pickle(out);
        self.max_files.pickle(out);
        self.max_folders.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_size = Pickle::unpickle(stream)?;
        this.max_files = Pickle::unpickle(stream)?;
        this.max_folders = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for FileStorage {
    fn default() -> Self {
        Self {
            max_size: 26214400,
            max_files: Default::default(),
            max_folders: Default::default(),
        }
    }
}

impl IntoValue for FileStorage {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::MaxSize, self.max_size.into_value());
        map.insert_unchecked(Property::MaxFiles, self.max_files.into_value());
        map.insert_unchecked(Property::MaxFolders, self.max_folders.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for FileStorage {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxSize) => self.max_size.patch(pointer, value),
            Some(Property::MaxFiles) => self.max_files.patch(pointer, value),
            Some(Property::MaxFolders) => self.max_folders.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl FileSystemStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Path));
        }
        let value = &self.depth;
        if *value > 5 {
            errors.push(ValidationError::max_value(Property::Depth, 5));
        }
        errors.len() == neb
    }
}

impl Pickle for FileSystemStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.path.pickle(out);
        self.depth.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.path = Pickle::unpickle(stream)?;
        this.depth = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for FileSystemStore {
    fn default() -> Self {
        Self {
            path: Default::default(),
            depth: 2u64,
        }
    }
}

impl IntoValue for FileSystemStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Path, self.path.into_value());
        map.insert_unchecked(Property::Depth, self.depth.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for FileSystemStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Path) => self
                .path
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Depth) => self.depth.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl FoundationDbStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.cluster_file {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ClusterFile));
            }
        }
        if let Some(value) = &self.datacenter_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DatacenterId));
            }
        }
        if let Some(value) = &self.machine_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MachineId));
            }
        }
        if let Some(value) = &self.transaction_retry_limit {
            if *value > 1000 {
                errors.push(ValidationError::max_value(
                    Property::TransactionRetryLimit,
                    1000,
                ));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::TransactionRetryLimit,
                    1,
                ));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for FoundationDbStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.cluster_file.pickle(out);
        self.datacenter_id.pickle(out);
        self.machine_id.pickle(out);
        self.transaction_retry_delay.pickle(out);
        self.transaction_retry_limit.pickle(out);
        self.transaction_timeout.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.cluster_file = Pickle::unpickle(stream)?;
        this.datacenter_id = Pickle::unpickle(stream)?;
        this.machine_id = Pickle::unpickle(stream)?;
        this.transaction_retry_delay = Pickle::unpickle(stream)?;
        this.transaction_retry_limit = Pickle::unpickle(stream)?;
        this.transaction_timeout = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for FoundationDbStore {
    fn default() -> Self {
        Self {
            cluster_file: Default::default(),
            datacenter_id: Default::default(),
            machine_id: Default::default(),
            transaction_retry_delay: Default::default(),
            transaction_retry_limit: Default::default(),
            transaction_timeout: Default::default(),
        }
    }
}

impl IntoValue for FoundationDbStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::ClusterFile, self.cluster_file.into_value());
        map.insert_unchecked(Property::DatacenterId, self.datacenter_id.into_value());
        map.insert_unchecked(Property::MachineId, self.machine_id.into_value());
        map.insert_unchecked(
            Property::TransactionRetryDelay,
            self.transaction_retry_delay.into_value(),
        );
        map.insert_unchecked(
            Property::TransactionRetryLimit,
            self.transaction_retry_limit.into_value(),
        );
        map.insert_unchecked(
            Property::TransactionTimeout,
            self.transaction_timeout.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for FoundationDbStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ClusterFile) => self
                .cluster_file
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DatacenterId) => self
                .datacenter_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MachineId) => self
                .machine_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::TransactionRetryDelay) => {
                self.transaction_retry_delay.patch(pointer, value)
            }
            Some(Property::TransactionRetryLimit) => {
                self.transaction_retry_limit.patch(pointer, value)
            }
            Some(Property::TransactionTimeout) => self.transaction_timeout.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl FtrlParameters {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.alpha;
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::Alpha, 0));
        }
        let value = &self.beta;
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::Beta, 0));
        }
        let value = &self.l1_ratio;
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::L1Ratio, 0));
        }
        let value = &self.l2_ratio;
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::L2Ratio, 0));
        }
        errors.len() == neb
    }
}

impl Pickle for FtrlParameters {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.alpha.pickle(out);
        self.beta.pickle(out);
        self.num_features.pickle(out);
        self.l1_ratio.pickle(out);
        self.l2_ratio.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.alpha = Pickle::unpickle(stream)?;
        this.beta = Pickle::unpickle(stream)?;
        this.num_features = Pickle::unpickle(stream)?;
        this.l1_ratio = Pickle::unpickle(stream)?;
        this.l2_ratio = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for FtrlParameters {
    fn default() -> Self {
        Self {
            alpha: Float::new(2.0f64),
            beta: Float::new(1.0f64),
            num_features: ModelSize::V20,
            l1_ratio: Float::new(0.001f64),
            l2_ratio: Float::new(0.0001f64),
        }
    }
}

impl IntoValue for FtrlParameters {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Alpha, self.alpha.into_value());
        map.insert_unchecked(Property::Beta, self.beta.into_value());
        map.insert_unchecked(Property::NumFeatures, self.num_features.into_value());
        map.insert_unchecked(Property::L1Ratio, self.l1_ratio.into_value());
        map.insert_unchecked(Property::L2Ratio, self.l2_ratio.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for FtrlParameters {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Alpha) => self.alpha.patch(pointer, value),
            Some(Property::Beta) => self.beta.patch(pointer, value),
            Some(Property::NumFeatures) => self.num_features.patch(pointer, value),
            Some(Property::L1Ratio) => self.l1_ratio.patch(pointer, value),
            Some(Property::L2Ratio) => self.l2_ratio.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl GroupAccount {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.roles;
        value.validate(errors);
        let value = &self.permissions;
        value.validate(errors);
        let value = &self.aliases;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Email, &self.name, &self.domain_id);
        i.text(Property::Text, &self.name);
        i.search(Property::Name, &self.name);
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
        i.search(Property::DomainId, &self.domain_id);
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
        self.roles.index(i);
        for item in self.aliases.values() {
            item.index(i);
        }
    }
}

impl Pickle for GroupAccount {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.domain_id.pickle(out);
        self.description.pickle(out);
        self.created_at.pickle(out);
        self.member_tenant_id.pickle(out);
        self.roles.pickle(out);
        self.quotas.pickle(out);
        self.permissions.pickle(out);
        self.aliases.pickle(out);
        self.locale.pickle(out);
        self.time_zone.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.roles = Pickle::unpickle(stream)?;
        this.quotas = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.aliases = Pickle::unpickle(stream)?;
        this.locale = Pickle::unpickle(stream)?;
        this.time_zone = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for GroupAccount {
    fn default() -> Self {
        Self {
            name: Default::default(),
            domain_id: Default::default(),
            description: Default::default(),
            created_at: Default::default(),
            member_tenant_id: Default::default(),
            roles: Default::default(),
            quotas: Default::default(),
            permissions: Default::default(),
            aliases: Default::default(),
            locale: Locale::EnUS,
            time_zone: Default::default(),
        }
    }
}

impl IntoValue for GroupAccount {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Roles, self.roles.into_value());
        map.insert_unchecked(Property::Quotas, self.quotas.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::Aliases, self.aliases.into_value());
        map.insert_unchecked(Property::Locale, self.locale.into_value());
        map.insert_unchecked(Property::TimeZone, self.time_zone.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for GroupAccount {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(
                pointer.with_validators(&[StringValidator::EmailLocalPart]),
                value,
            ),
            Some(Property::DomainId) => self.domain_id.patch(pointer, value),
            Some(Property::EmailAddress) => pointer.assert_server_set(),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Roles) => self.roles.patch(pointer, value),
            Some(Property::Quotas) => self.quotas.patch(pointer, value),
            Some(Property::UsedDiskQuota) => pointer.assert_server_set(),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::Aliases) => self.aliases.patch(pointer, value),
            Some(Property::Locale) => self.locale.patch(pointer, value),
            Some(Property::TimeZone) => self.time_zone.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Http {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Http;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.rate_limit_authenticated {
            value.validate(errors);
        }
        if let Some(value) = &self.rate_limit_anonymous {
            value.validate(errors);
        }
        let value = &self.allowed_endpoints;
        value.validate(errors);
        let value = &self.response_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseHeaders));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Http {
    pub fn ctx_allowed_endpoints(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.allowed_endpoints,
            default: Some(Expression {
                else_: "200".to_string(),
                ..Default::default()
            }),
            property: Property::AllowedEndpoints,
            allowed_variables: HTTP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_allowed_endpoints()]
    }
}

impl Pickle for Http {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.rate_limit_authenticated.pickle(out);
        self.rate_limit_anonymous.pickle(out);
        self.allowed_endpoints.pickle(out);
        self.enable_hsts.pickle(out);
        self.use_permissive_cors.pickle(out);
        self.response_headers.pickle(out);
        self.use_x_forwarded.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.rate_limit_authenticated = Pickle::unpickle(stream)?;
        this.rate_limit_anonymous = Pickle::unpickle(stream)?;
        this.allowed_endpoints = Pickle::unpickle(stream)?;
        this.enable_hsts = Pickle::unpickle(stream)?;
        this.use_permissive_cors = Pickle::unpickle(stream)?;
        this.response_headers = Pickle::unpickle(stream)?;
        this.use_x_forwarded = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Http {
    fn default() -> Self {
        Self {
            rate_limit_authenticated: Some(Rate {
                count: 1000u64,
                period: Duration::from_millis(60000),
            }),
            rate_limit_anonymous: Some(Rate {
                count: 100u64,
                period: Duration::from_millis(60000),
            }),
            allowed_endpoints: Expression {
                else_: "200".to_string(),
                ..Default::default()
            },
            enable_hsts: false,
            use_permissive_cors: false,
            response_headers: Default::default(),
            use_x_forwarded: false,
        }
    }
}

impl IntoValue for Http {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(
            Property::RateLimitAuthenticated,
            self.rate_limit_authenticated.into_value(),
        );
        map.insert_unchecked(
            Property::RateLimitAnonymous,
            self.rate_limit_anonymous.into_value(),
        );
        map.insert_unchecked(
            Property::AllowedEndpoints,
            self.allowed_endpoints.into_value(),
        );
        map.insert_unchecked(Property::EnableHsts, self.enable_hsts.into_value());
        map.insert_unchecked(
            Property::UsePermissiveCors,
            self.use_permissive_cors.into_value(),
        );
        map.insert_unchecked(
            Property::ResponseHeaders,
            self.response_headers.into_value(),
        );
        map.insert_unchecked(Property::UseXForwarded, self.use_x_forwarded.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Http {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::RateLimitAuthenticated) => {
                self.rate_limit_authenticated.patch(pointer, value)
            }
            Some(Property::RateLimitAnonymous) => self.rate_limit_anonymous.patch(pointer, value),
            Some(Property::AllowedEndpoints) => self.allowed_endpoints.patch(pointer, value),
            Some(Property::EnableHsts) => self.enable_hsts.patch(pointer, value),
            Some(Property::UsePermissiveCors) => self.use_permissive_cors.patch(pointer, value),
            Some(Property::ResponseHeaders) => self
                .response_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::UseXForwarded) => self.use_x_forwarded.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl HttpAuth {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            HttpAuth::Unauthenticated => true,
            HttpAuth::Basic(inner) => inner.validate(errors),
            HttpAuth::Bearer(inner) => inner.validate(errors),
        }
    }
}

impl Default for HttpAuth {
    fn default() -> Self {
        HttpAuth::Unauthenticated
    }
}

impl Pickle for HttpAuth {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            HttpAuth::Unauthenticated => {
                0u16.pickle(out);
            }
            HttpAuth::Basic(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            HttpAuth::Bearer(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(HttpAuth::Unauthenticated),
            1 => Pickle::unpickle(stream).map(HttpAuth::Basic),
            2 => Pickle::unpickle(stream).map(HttpAuth::Bearer),
            _ => None,
        }
    }
}

impl IntoValue for HttpAuth {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            HttpAuth::Unauthenticated => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Unauthenticated".into()));
                JmapValue::Object(obj)
            }
            HttpAuth::Basic(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Basic".into()));
                obj
            }
            HttpAuth::Bearer(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Bearer".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for HttpAuth {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                HttpAuthType::Unauthenticated => *self = HttpAuth::Unauthenticated,
                HttpAuthType::Basic => *self = HttpAuth::Basic(Default::default()),
                HttpAuthType::Bearer => *self = HttpAuth::Bearer(Default::default()),
            }
        }
        match self {
            HttpAuth::Unauthenticated => pointer.assert_eof(),
            HttpAuth::Basic(inner) => inner.patch(pointer, value),
            HttpAuth::Bearer(inner) => inner.patch(pointer, value),
        }
    }
}

impl HttpAuth {
    pub fn object_type(&self) -> HttpAuthType {
        match self {
            HttpAuth::Unauthenticated => HttpAuthType::Unauthenticated,
            HttpAuth::Basic(_) => HttpAuthType::Basic,
            HttpAuth::Bearer(_) => HttpAuthType::Bearer,
        }
    }
}

impl HttpAuthBasic {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.secret;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for HttpAuthBasic {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HttpAuthBasic {
    fn default() -> Self {
        Self {
            username: Default::default(),
            secret: Default::default(),
        }
    }
}

impl IntoValue for HttpAuthBasic {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HttpAuthBasic {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl HttpAuthBearer {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.bearer_token;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for HttpAuthBearer {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.bearer_token.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.bearer_token = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HttpAuthBearer {
    fn default() -> Self {
        Self {
            bearer_token: Default::default(),
        }
    }
}

impl IntoValue for HttpAuthBearer {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::BearerToken, self.bearer_token.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HttpAuthBearer {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BearerToken) => self.bearer_token.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for HttpForm {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::HttpForm;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.deliver_to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::DeliverTo));
            }
        }
        let value = &self.default_from_address;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultFromAddress));
        }
        if let Some(value) = &self.field_email {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FieldEmail));
            }
        }
        if let Some(value) = &self.field_honey_pot {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FieldHoneyPot));
            }
        }
        let value = &self.default_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultName));
        }
        if let Some(value) = &self.field_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FieldName));
            }
        }
        if let Some(value) = &self.rate_limit {
            value.validate(errors);
        }
        let value = &self.default_subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultSubject));
        }
        if let Some(value) = &self.field_subject {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FieldSubject));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for HttpForm {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.deliver_to.pickle(out);
        self.default_from_address.pickle(out);
        self.field_email.pickle(out);
        self.enable.pickle(out);
        self.field_honey_pot.pickle(out);
        self.max_size.pickle(out);
        self.default_name.pickle(out);
        self.field_name.pickle(out);
        self.rate_limit.pickle(out);
        self.default_subject.pickle(out);
        self.field_subject.pickle(out);
        self.validate_domain.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.deliver_to = Pickle::unpickle(stream)?;
        this.default_from_address = Pickle::unpickle(stream)?;
        this.field_email = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.field_honey_pot = Pickle::unpickle(stream)?;
        this.max_size = Pickle::unpickle(stream)?;
        this.default_name = Pickle::unpickle(stream)?;
        this.field_name = Pickle::unpickle(stream)?;
        this.rate_limit = Pickle::unpickle(stream)?;
        this.default_subject = Pickle::unpickle(stream)?;
        this.field_subject = Pickle::unpickle(stream)?;
        this.validate_domain = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HttpForm {
    fn default() -> Self {
        Self {
            deliver_to: Default::default(),
            default_from_address: "postmaster@localhost".to_string(),
            field_email: Default::default(),
            enable: false,
            field_honey_pot: Default::default(),
            max_size: 102400,
            default_name: "Anonymous".to_string(),
            field_name: Default::default(),
            rate_limit: Some(Rate {
                count: 5u64,
                period: Duration::from_millis(3600000),
            }),
            default_subject: "Contact form submission".to_string(),
            field_subject: Default::default(),
            validate_domain: true,
        }
    }
}

impl IntoValue for HttpForm {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::DeliverTo, self.deliver_to.into_value());
        map.insert_unchecked(
            Property::DefaultFromAddress,
            self.default_from_address.into_value(),
        );
        map.insert_unchecked(Property::FieldEmail, self.field_email.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::FieldHoneyPot, self.field_honey_pot.into_value());
        map.insert_unchecked(Property::MaxSize, self.max_size.into_value());
        map.insert_unchecked(Property::DefaultName, self.default_name.into_value());
        map.insert_unchecked(Property::FieldName, self.field_name.into_value());
        map.insert_unchecked(Property::RateLimit, self.rate_limit.into_value());
        map.insert_unchecked(Property::DefaultSubject, self.default_subject.into_value());
        map.insert_unchecked(Property::FieldSubject, self.field_subject.into_value());
        map.insert_unchecked(Property::ValidateDomain, self.validate_domain.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HttpForm {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DeliverTo) => self
                .deliver_to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::DefaultFromAddress) => self
                .default_from_address
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::FieldEmail) => self
                .field_email
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::FieldHoneyPot) => self
                .field_honey_pot
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MaxSize) => self.max_size.patch(pointer, value),
            Some(Property::DefaultName) => self
                .default_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::FieldName) => self
                .field_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::RateLimit) => self.rate_limit.patch(pointer, value),
            Some(Property::DefaultSubject) => self
                .default_subject
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::FieldSubject) => self
                .field_subject
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ValidateDomain) => self.validate_domain.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for HttpLookup {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::HttpLookup;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.namespace;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Namespace));
        }
        let value = &self.format;
        value.validate(errors);
        let value = &self.max_entries;
        if *value > 1048576 {
            errors.push(ValidationError::max_value(Property::MaxEntries, 1048576));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxEntries, 1));
        }
        let value = &self.max_entry_size;
        if *value > 1048576 {
            errors.push(ValidationError::max_value(Property::MaxEntrySize, 1048576));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxEntrySize, 1));
        }
        let value = &self.max_size;
        if *value > 1073741824 {
            errors.push(ValidationError::max_value(Property::MaxSize, 1073741824));
        }
        if *value < 10 {
            errors.push(ValidationError::min_value(Property::MaxSize, 10));
        }
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global(Property::Namespace, &self.namespace);
    }
}

impl Pickle for HttpLookup {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.namespace.pickle(out);
        self.enable.pickle(out);
        self.format.pickle(out);
        self.is_gzipped.pickle(out);
        self.max_entries.pickle(out);
        self.max_entry_size.pickle(out);
        self.max_size.pickle(out);
        self.refresh.pickle(out);
        self.retry.pickle(out);
        self.timeout.pickle(out);
        self.url.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.namespace = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.format = Pickle::unpickle(stream)?;
        this.is_gzipped = Pickle::unpickle(stream)?;
        this.max_entries = Pickle::unpickle(stream)?;
        this.max_entry_size = Pickle::unpickle(stream)?;
        this.max_size = Pickle::unpickle(stream)?;
        this.refresh = Pickle::unpickle(stream)?;
        this.retry = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HttpLookup {
    fn default() -> Self {
        Self {
            namespace: Default::default(),
            enable: true,
            format: Default::default(),
            is_gzipped: false,
            max_entries: 100000u64,
            max_entry_size: 512u64,
            max_size: 104857600,
            refresh: Duration::from_millis(43200000),
            retry: Duration::from_millis(3600000),
            timeout: Duration::from_millis(30000),
            url: Default::default(),
        }
    }
}

impl IntoValue for HttpLookup {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::Namespace, self.namespace.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Format, self.format.into_value());
        map.insert_unchecked(Property::IsGzipped, self.is_gzipped.into_value());
        map.insert_unchecked(Property::MaxEntries, self.max_entries.into_value());
        map.insert_unchecked(Property::MaxEntrySize, self.max_entry_size.into_value());
        map.insert_unchecked(Property::MaxSize, self.max_size.into_value());
        map.insert_unchecked(Property::Refresh, self.refresh.into_value());
        map.insert_unchecked(Property::Retry, self.retry.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HttpLookup {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Namespace) => self.namespace.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Trim]),
                value,
            ),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Format) => self.format.patch(pointer, value),
            Some(Property::IsGzipped) => self.is_gzipped.patch(pointer, value),
            Some(Property::MaxEntries) => self.max_entries.patch(pointer, value),
            Some(Property::MaxEntrySize) => self.max_entry_size.patch(pointer, value),
            Some(Property::MaxSize) => self.max_size.patch(pointer, value),
            Some(Property::Refresh) => self.refresh.patch(pointer, value),
            Some(Property::Retry) => self.retry.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl HttpLookupCsv {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.separator;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Separator));
        }
        errors.len() == neb
    }
}

impl Pickle for HttpLookupCsv {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.index_key.pickle(out);
        self.index_value.pickle(out);
        self.separator.pickle(out);
        self.skip_first.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.index_key = Pickle::unpickle(stream)?;
        this.index_value = Pickle::unpickle(stream)?;
        this.separator = Pickle::unpickle(stream)?;
        this.skip_first = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HttpLookupCsv {
    fn default() -> Self {
        Self {
            index_key: 0u64,
            index_value: Default::default(),
            separator: ",".to_string(),
            skip_first: false,
        }
    }
}

impl IntoValue for HttpLookupCsv {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::IndexKey, self.index_key.into_value());
        map.insert_unchecked(Property::IndexValue, self.index_value.into_value());
        map.insert_unchecked(Property::Separator, self.separator.into_value());
        map.insert_unchecked(Property::SkipFirst, self.skip_first.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HttpLookupCsv {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IndexKey) => self.index_key.patch(pointer, value),
            Some(Property::IndexValue) => self.index_value.patch(pointer, value),
            Some(Property::Separator) => self
                .separator
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SkipFirst) => self.skip_first.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl HttpLookupFormat {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            HttpLookupFormat::Csv(inner) => inner.validate(errors),
            HttpLookupFormat::List => true,
        }
    }
}

impl Default for HttpLookupFormat {
    fn default() -> Self {
        HttpLookupFormat::Csv(Default::default())
    }
}

impl Pickle for HttpLookupFormat {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            HttpLookupFormat::Csv(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            HttpLookupFormat::List => {
                1u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(HttpLookupFormat::Csv),
            1 => Some(HttpLookupFormat::List),
            _ => None,
        }
    }
}

impl IntoValue for HttpLookupFormat {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            HttpLookupFormat::Csv(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Csv".into()));
                obj
            }
            HttpLookupFormat::List => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("List".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for HttpLookupFormat {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                HttpLookupFormatType::Csv => *self = HttpLookupFormat::Csv(Default::default()),
                HttpLookupFormatType::List => *self = HttpLookupFormat::List,
            }
        }
        match self {
            HttpLookupFormat::Csv(inner) => inner.patch(pointer, value),
            HttpLookupFormat::List => pointer.assert_eof(),
        }
    }
}

impl HttpLookupFormat {
    pub fn object_type(&self) -> HttpLookupFormatType {
        match self {
            HttpLookupFormat::Csv(_) => HttpLookupFormatType::Csv,
            HttpLookupFormat::List => HttpLookupFormatType::List,
        }
    }
}

impl HurricaneCredential {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.zone;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Zone));
        }
        let value = &self.secret;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for HurricaneCredential {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.zone.pickle(out);
        self.secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.zone = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for HurricaneCredential {
    fn default() -> Self {
        Self {
            zone: Default::default(),
            secret: Default::default(),
        }
    }
}

impl IntoValue for HurricaneCredential {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Secret, self.secret.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for HurricaneCredential {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Zone) => self.zone.patch(
                pointer.with_validators(&[StringValidator::Domain, StringValidator::Trim]),
                value,
            ),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Imap {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Imap;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_auth_failures;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxAuthFailures, 1));
        }
        if let Some(value) = &self.max_concurrent {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxConcurrent, 1));
            }
        }
        if let Some(value) = &self.max_request_rate {
            value.validate(errors);
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Imap {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_plain_text_auth.pickle(out);
        self.max_auth_failures.pickle(out);
        self.max_concurrent.pickle(out);
        self.max_request_rate.pickle(out);
        self.max_request_size.pickle(out);
        self.timeout_anonymous.pickle(out);
        self.timeout_authenticated.pickle(out);
        self.timeout_idle.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_plain_text_auth = Pickle::unpickle(stream)?;
        this.max_auth_failures = Pickle::unpickle(stream)?;
        this.max_concurrent = Pickle::unpickle(stream)?;
        this.max_request_rate = Pickle::unpickle(stream)?;
        this.max_request_size = Pickle::unpickle(stream)?;
        this.timeout_anonymous = Pickle::unpickle(stream)?;
        this.timeout_authenticated = Pickle::unpickle(stream)?;
        this.timeout_idle = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Imap {
    fn default() -> Self {
        Self {
            allow_plain_text_auth: false,
            max_auth_failures: 3u64,
            max_concurrent: Some(16u64),
            max_request_rate: Some(Rate {
                count: 2000u64,
                period: Duration::from_millis(60000),
            }),
            max_request_size: 52428800,
            timeout_anonymous: Duration::from_millis(60000),
            timeout_authenticated: Duration::from_millis(1800000),
            timeout_idle: Duration::from_millis(1800000),
        }
    }
}

impl IntoValue for Imap {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(
            Property::AllowPlainTextAuth,
            self.allow_plain_text_auth.into_value(),
        );
        map.insert_unchecked(
            Property::MaxAuthFailures,
            self.max_auth_failures.into_value(),
        );
        map.insert_unchecked(Property::MaxConcurrent, self.max_concurrent.into_value());
        map.insert_unchecked(Property::MaxRequestRate, self.max_request_rate.into_value());
        map.insert_unchecked(Property::MaxRequestSize, self.max_request_size.into_value());
        map.insert_unchecked(
            Property::TimeoutAnonymous,
            self.timeout_anonymous.into_value(),
        );
        map.insert_unchecked(
            Property::TimeoutAuthenticated,
            self.timeout_authenticated.into_value(),
        );
        map.insert_unchecked(Property::TimeoutIdle, self.timeout_idle.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Imap {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowPlainTextAuth) => self.allow_plain_text_auth.patch(pointer, value),
            Some(Property::MaxAuthFailures) => self.max_auth_failures.patch(pointer, value),
            Some(Property::MaxConcurrent) => self.max_concurrent.patch(pointer, value),
            Some(Property::MaxRequestRate) => self.max_request_rate.patch(pointer, value),
            Some(Property::MaxRequestSize) => self.max_request_size.patch(pointer, value),
            Some(Property::TimeoutAnonymous) => self.timeout_anonymous.patch(pointer, value),
            Some(Property::TimeoutAuthenticated) => {
                self.timeout_authenticated.patch(pointer, value)
            }
            Some(Property::TimeoutIdle) => self.timeout_idle.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for InMemoryStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::InMemoryStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            InMemoryStore::Default => true,
            InMemoryStore::Sharded(inner) => inner.validate(errors),
            InMemoryStore::Redis(inner) => inner.validate(errors),
            InMemoryStore::RedisCluster(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for InMemoryStore {
    fn default() -> Self {
        InMemoryStore::Default
    }
}

impl Pickle for InMemoryStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            InMemoryStore::Default => {
                0u16.pickle(out);
            }
            InMemoryStore::Sharded(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            InMemoryStore::Redis(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            InMemoryStore::RedisCluster(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(InMemoryStore::Default),
            1 => Pickle::unpickle(stream).map(InMemoryStore::Sharded),
            2 => Pickle::unpickle(stream).map(InMemoryStore::Redis),
            3 => Pickle::unpickle(stream).map(InMemoryStore::RedisCluster),
            _ => None,
        }
    }
}

impl IntoValue for InMemoryStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            InMemoryStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            InMemoryStore::Sharded(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sharded".into()));
                obj
            }
            InMemoryStore::Redis(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Redis".into()));
                obj
            }
            InMemoryStore::RedisCluster(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for InMemoryStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                InMemoryStoreType::Default => *self = InMemoryStore::Default,
                InMemoryStoreType::Sharded => *self = InMemoryStore::Sharded(Default::default()),
                InMemoryStoreType::Redis => *self = InMemoryStore::Redis(Default::default()),
                InMemoryStoreType::RedisCluster => {
                    *self = InMemoryStore::RedisCluster(Default::default())
                }
            }
        }
        match self {
            InMemoryStore::Default => pointer.assert_eof(),
            InMemoryStore::Sharded(inner) => inner.patch(pointer, value),
            InMemoryStore::Redis(inner) => inner.patch(pointer, value),
            InMemoryStore::RedisCluster(inner) => inner.patch(pointer, value),
        }
    }
}

impl InMemoryStore {
    pub fn object_type(&self) -> InMemoryStoreType {
        match self {
            InMemoryStore::Default => InMemoryStoreType::Default,
            InMemoryStore::Sharded(_) => InMemoryStoreType::Sharded,
            InMemoryStore::Redis(_) => InMemoryStoreType::Redis,
            InMemoryStore::RedisCluster(_) => InMemoryStoreType::RedisCluster,
        }
    }
}

impl InMemoryStoreBase {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            InMemoryStoreBase::Redis(inner) => inner.validate(errors),
            InMemoryStoreBase::RedisCluster(inner) => inner.validate(errors),
        }
    }
}

impl Default for InMemoryStoreBase {
    fn default() -> Self {
        InMemoryStoreBase::Redis(Default::default())
    }
}

impl Pickle for InMemoryStoreBase {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            InMemoryStoreBase::Redis(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            InMemoryStoreBase::RedisCluster(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(InMemoryStoreBase::Redis),
            1 => Pickle::unpickle(stream).map(InMemoryStoreBase::RedisCluster),
            _ => None,
        }
    }
}

impl IntoValue for InMemoryStoreBase {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            InMemoryStoreBase::Redis(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Redis".into()));
                obj
            }
            InMemoryStoreBase::RedisCluster(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for InMemoryStoreBase {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                InMemoryStoreBaseType::Redis => {
                    *self = InMemoryStoreBase::Redis(Default::default())
                }
                InMemoryStoreBaseType::RedisCluster => {
                    *self = InMemoryStoreBase::RedisCluster(Default::default())
                }
            }
        }
        match self {
            InMemoryStoreBase::Redis(inner) => inner.patch(pointer, value),
            InMemoryStoreBase::RedisCluster(inner) => inner.patch(pointer, value),
        }
    }
}

impl InMemoryStoreBase {
    pub fn object_type(&self) -> InMemoryStoreBaseType {
        match self {
            InMemoryStoreBase::Redis(_) => InMemoryStoreBaseType::Redis,
            InMemoryStoreBase::RedisCluster(_) => InMemoryStoreBaseType::RedisCluster,
        }
    }
}

impl ObjectImpl for Jmap {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Jmap;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.parse_limit_event;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ParseLimitEvent, 1));
        }
        let value = &self.parse_limit_contact;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ParseLimitContact, 1));
        }
        let value = &self.parse_limit_email;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ParseLimitEmail, 1));
        }
        let value = &self.changes_max_results;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ChangesMaxResults, 1));
        }
        let value = &self.get_max_results;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::GetMaxResults, 1));
        }
        let value = &self.query_max_results;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::QueryMaxResults, 1));
        }
        let value = &self.max_method_calls;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMethodCalls, 1));
        }
        if let Some(value) = &self.max_concurrent_requests {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::MaxConcurrentRequests,
                    1,
                ));
            }
        }
        let value = &self.max_request_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxRequestSize, 1));
        }
        let value = &self.set_max_objects;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::SetMaxObjects, 1));
        }
        let value = &self.snippet_max_results;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::SnippetMaxResults, 1));
        }
        if let Some(value) = &self.max_concurrent_uploads {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::MaxConcurrentUploads,
                    1,
                ));
            }
        }
        let value = &self.max_upload_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxUploadSize, 1));
        }
        let value = &self.max_upload_count;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxUploadCount, 1));
        }
        let value = &self.upload_quota;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::UploadQuota, 1));
        }
        let value = &self.push_max_attempts;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PushMaxAttempts, 1));
        }
        let value = &self.push_shards_total;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PushShardsTotal, 1));
        }
        if let Some(value) = &self.max_subscriptions {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxSubscriptions, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Jmap {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.parse_limit_event.pickle(out);
        self.parse_limit_contact.pickle(out);
        self.parse_limit_email.pickle(out);
        self.changes_max_results.pickle(out);
        self.get_max_results.pickle(out);
        self.query_max_results.pickle(out);
        self.max_method_calls.pickle(out);
        self.max_concurrent_requests.pickle(out);
        self.max_request_size.pickle(out);
        self.set_max_objects.pickle(out);
        self.snippet_max_results.pickle(out);
        self.max_concurrent_uploads.pickle(out);
        self.max_upload_size.pickle(out);
        self.max_upload_count.pickle(out);
        self.upload_quota.pickle(out);
        self.upload_ttl.pickle(out);
        self.event_source_throttle.pickle(out);
        self.push_attempt_wait.pickle(out);
        self.push_max_attempts.pickle(out);
        self.push_retry_wait.pickle(out);
        self.push_throttle.pickle(out);
        self.push_request_timeout.pickle(out);
        self.push_verify_timeout.pickle(out);
        self.push_shards_total.pickle(out);
        self.websocket_heartbeat.pickle(out);
        self.websocket_throttle.pickle(out);
        self.websocket_timeout.pickle(out);
        self.max_subscriptions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.parse_limit_event = Pickle::unpickle(stream)?;
        this.parse_limit_contact = Pickle::unpickle(stream)?;
        this.parse_limit_email = Pickle::unpickle(stream)?;
        this.changes_max_results = Pickle::unpickle(stream)?;
        this.get_max_results = Pickle::unpickle(stream)?;
        this.query_max_results = Pickle::unpickle(stream)?;
        this.max_method_calls = Pickle::unpickle(stream)?;
        this.max_concurrent_requests = Pickle::unpickle(stream)?;
        this.max_request_size = Pickle::unpickle(stream)?;
        this.set_max_objects = Pickle::unpickle(stream)?;
        this.snippet_max_results = Pickle::unpickle(stream)?;
        this.max_concurrent_uploads = Pickle::unpickle(stream)?;
        this.max_upload_size = Pickle::unpickle(stream)?;
        this.max_upload_count = Pickle::unpickle(stream)?;
        this.upload_quota = Pickle::unpickle(stream)?;
        this.upload_ttl = Pickle::unpickle(stream)?;
        this.event_source_throttle = Pickle::unpickle(stream)?;
        this.push_attempt_wait = Pickle::unpickle(stream)?;
        this.push_max_attempts = Pickle::unpickle(stream)?;
        this.push_retry_wait = Pickle::unpickle(stream)?;
        this.push_throttle = Pickle::unpickle(stream)?;
        this.push_request_timeout = Pickle::unpickle(stream)?;
        this.push_verify_timeout = Pickle::unpickle(stream)?;
        this.push_shards_total = Pickle::unpickle(stream)?;
        this.websocket_heartbeat = Pickle::unpickle(stream)?;
        this.websocket_throttle = Pickle::unpickle(stream)?;
        this.websocket_timeout = Pickle::unpickle(stream)?;
        this.max_subscriptions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Jmap {
    fn default() -> Self {
        Self {
            parse_limit_event: 10u64,
            parse_limit_contact: 10u64,
            parse_limit_email: 10u64,
            changes_max_results: 5000u64,
            get_max_results: 500u64,
            query_max_results: 5000u64,
            max_method_calls: 16u64,
            max_concurrent_requests: Some(4u64),
            max_request_size: 10000000u64,
            set_max_objects: 500u64,
            snippet_max_results: 100u64,
            max_concurrent_uploads: Some(4u64),
            max_upload_size: 50000000u64,
            max_upload_count: 1000u64,
            upload_quota: 50000000u64,
            upload_ttl: Duration::from_millis(3600000),
            event_source_throttle: Duration::from_millis(1000),
            push_attempt_wait: Duration::from_millis(60000),
            push_max_attempts: 3u64,
            push_retry_wait: Duration::from_millis(1000),
            push_throttle: Duration::from_millis(1000),
            push_request_timeout: Duration::from_millis(10000),
            push_verify_timeout: Duration::from_millis(60000),
            push_shards_total: 1u64,
            websocket_heartbeat: Duration::from_millis(60000),
            websocket_throttle: Duration::from_millis(1000),
            websocket_timeout: Duration::from_millis(600000),
            max_subscriptions: Some(15u64),
        }
    }
}

impl IntoValue for Jmap {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(30);
        map.insert_unchecked(
            Property::ParseLimitEvent,
            self.parse_limit_event.into_value(),
        );
        map.insert_unchecked(
            Property::ParseLimitContact,
            self.parse_limit_contact.into_value(),
        );
        map.insert_unchecked(
            Property::ParseLimitEmail,
            self.parse_limit_email.into_value(),
        );
        map.insert_unchecked(
            Property::ChangesMaxResults,
            self.changes_max_results.into_value(),
        );
        map.insert_unchecked(Property::GetMaxResults, self.get_max_results.into_value());
        map.insert_unchecked(
            Property::QueryMaxResults,
            self.query_max_results.into_value(),
        );
        map.insert_unchecked(Property::MaxMethodCalls, self.max_method_calls.into_value());
        map.insert_unchecked(
            Property::MaxConcurrentRequests,
            self.max_concurrent_requests.into_value(),
        );
        map.insert_unchecked(Property::MaxRequestSize, self.max_request_size.into_value());
        map.insert_unchecked(Property::SetMaxObjects, self.set_max_objects.into_value());
        map.insert_unchecked(
            Property::SnippetMaxResults,
            self.snippet_max_results.into_value(),
        );
        map.insert_unchecked(
            Property::MaxConcurrentUploads,
            self.max_concurrent_uploads.into_value(),
        );
        map.insert_unchecked(Property::MaxUploadSize, self.max_upload_size.into_value());
        map.insert_unchecked(Property::MaxUploadCount, self.max_upload_count.into_value());
        map.insert_unchecked(Property::UploadQuota, self.upload_quota.into_value());
        map.insert_unchecked(Property::UploadTtl, self.upload_ttl.into_value());
        map.insert_unchecked(
            Property::EventSourceThrottle,
            self.event_source_throttle.into_value(),
        );
        map.insert_unchecked(
            Property::PushAttemptWait,
            self.push_attempt_wait.into_value(),
        );
        map.insert_unchecked(
            Property::PushMaxAttempts,
            self.push_max_attempts.into_value(),
        );
        map.insert_unchecked(Property::PushRetryWait, self.push_retry_wait.into_value());
        map.insert_unchecked(Property::PushThrottle, self.push_throttle.into_value());
        map.insert_unchecked(
            Property::PushRequestTimeout,
            self.push_request_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PushVerifyTimeout,
            self.push_verify_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::PushShardsTotal,
            self.push_shards_total.into_value(),
        );
        map.insert_unchecked(
            Property::WebsocketHeartbeat,
            self.websocket_heartbeat.into_value(),
        );
        map.insert_unchecked(
            Property::WebsocketThrottle,
            self.websocket_throttle.into_value(),
        );
        map.insert_unchecked(
            Property::WebsocketTimeout,
            self.websocket_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::MaxSubscriptions,
            self.max_subscriptions.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Jmap {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ParseLimitEvent) => self.parse_limit_event.patch(pointer, value),
            Some(Property::ParseLimitContact) => self.parse_limit_contact.patch(pointer, value),
            Some(Property::ParseLimitEmail) => self.parse_limit_email.patch(pointer, value),
            Some(Property::ChangesMaxResults) => self.changes_max_results.patch(pointer, value),
            Some(Property::GetMaxResults) => self.get_max_results.patch(pointer, value),
            Some(Property::QueryMaxResults) => self.query_max_results.patch(pointer, value),
            Some(Property::MaxMethodCalls) => self.max_method_calls.patch(pointer, value),
            Some(Property::MaxConcurrentRequests) => {
                self.max_concurrent_requests.patch(pointer, value)
            }
            Some(Property::MaxRequestSize) => self.max_request_size.patch(pointer, value),
            Some(Property::SetMaxObjects) => self.set_max_objects.patch(pointer, value),
            Some(Property::SnippetMaxResults) => self.snippet_max_results.patch(pointer, value),
            Some(Property::MaxConcurrentUploads) => {
                self.max_concurrent_uploads.patch(pointer, value)
            }
            Some(Property::MaxUploadSize) => self.max_upload_size.patch(pointer, value),
            Some(Property::MaxUploadCount) => self.max_upload_count.patch(pointer, value),
            Some(Property::UploadQuota) => self.upload_quota.patch(pointer, value),
            Some(Property::UploadTtl) => self.upload_ttl.patch(pointer, value),
            Some(Property::EventSourceThrottle) => self.event_source_throttle.patch(pointer, value),
            Some(Property::PushAttemptWait) => self.push_attempt_wait.patch(pointer, value),
            Some(Property::PushMaxAttempts) => self.push_max_attempts.patch(pointer, value),
            Some(Property::PushRetryWait) => self.push_retry_wait.patch(pointer, value),
            Some(Property::PushThrottle) => self.push_throttle.patch(pointer, value),
            Some(Property::PushRequestTimeout) => self.push_request_timeout.patch(pointer, value),
            Some(Property::PushVerifyTimeout) => self.push_verify_timeout.patch(pointer, value),
            Some(Property::PushShardsTotal) => self.push_shards_total.patch(pointer, value),
            Some(Property::WebsocketHeartbeat) => self.websocket_heartbeat.patch(pointer, value),
            Some(Property::WebsocketThrottle) => self.websocket_throttle.patch(pointer, value),
            Some(Property::WebsocketTimeout) => self.websocket_timeout.patch(pointer, value),
            Some(Property::MaxSubscriptions) => self.max_subscriptions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl JokerAuth {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            JokerAuth::ApiKey(inner) => inner.validate(errors),
            JokerAuth::UsernamePassword(inner) => inner.validate(errors),
        }
    }
}

impl Default for JokerAuth {
    fn default() -> Self {
        JokerAuth::ApiKey(Default::default())
    }
}

impl Pickle for JokerAuth {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            JokerAuth::ApiKey(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            JokerAuth::UsernamePassword(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(JokerAuth::ApiKey),
            1 => Pickle::unpickle(stream).map(JokerAuth::UsernamePassword),
            _ => None,
        }
    }
}

impl IntoValue for JokerAuth {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            JokerAuth::ApiKey(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ApiKey".into()));
                obj
            }
            JokerAuth::UsernamePassword(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UsernamePassword".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for JokerAuth {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                JokerAuthType::ApiKey => *self = JokerAuth::ApiKey(Default::default()),
                JokerAuthType::UsernamePassword => {
                    *self = JokerAuth::UsernamePassword(Default::default())
                }
            }
        }
        match self {
            JokerAuth::ApiKey(inner) => inner.patch(pointer, value),
            JokerAuth::UsernamePassword(inner) => inner.patch(pointer, value),
        }
    }
}

impl JokerAuth {
    pub fn object_type(&self) -> JokerAuthType {
        match self {
            JokerAuth::ApiKey(_) => JokerAuthType::ApiKey,
            JokerAuth::UsernamePassword(_) => JokerAuthType::UsernamePassword,
        }
    }
}

impl JokerAuthApiKey {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.api_key;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for JokerAuthApiKey {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.api_key.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.api_key = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for JokerAuthApiKey {
    fn default() -> Self {
        Self {
            api_key: Default::default(),
        }
    }
}

impl IntoValue for JokerAuthApiKey {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::ApiKey, self.api_key.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for JokerAuthApiKey {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ApiKey) => self.api_key.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl JokerAuthUsernamePassword {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Username));
        }
        let value = &self.password;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for JokerAuthUsernamePassword {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.username.pickle(out);
        self.password.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.username = Pickle::unpickle(stream)?;
        this.password = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for JokerAuthUsernamePassword {
    fn default() -> Self {
        Self {
            username: Default::default(),
            password: Default::default(),
        }
    }
}

impl IntoValue for JokerAuthUsernamePassword {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Username, self.username.into_value());
        map.insert_unchecked(Property::Password, self.password.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for JokerAuthUsernamePassword {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Username) => self
                .username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Password) => self.password.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl KafkaCoordinator {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.brokers;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Brokers));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Brokers, 1));
        }
        let value = &self.group_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::GroupId));
        }
        errors.len() == neb
    }
}

impl Pickle for KafkaCoordinator {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.brokers.pickle(out);
        self.group_id.pickle(out);
        self.timeout_message.pickle(out);
        self.timeout_session.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.brokers = Pickle::unpickle(stream)?;
        this.group_id = Pickle::unpickle(stream)?;
        this.timeout_message = Pickle::unpickle(stream)?;
        this.timeout_session = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for KafkaCoordinator {
    fn default() -> Self {
        Self {
            brokers: Default::default(),
            group_id: Default::default(),
            timeout_message: Duration::from_millis(5000),
            timeout_session: Duration::from_millis(5000),
        }
    }
}

impl IntoValue for KafkaCoordinator {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Brokers, self.brokers.into_value());
        map.insert_unchecked(Property::GroupId, self.group_id.into_value());
        map.insert_unchecked(Property::TimeoutMessage, self.timeout_message.into_value());
        map.insert_unchecked(Property::TimeoutSession, self.timeout_session.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for KafkaCoordinator {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Brokers) => self.brokers.patch(pointer, value),
            Some(Property::GroupId) => self
                .group_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::TimeoutMessage) => self.timeout_message.patch(pointer, value),
            Some(Property::TimeoutSession) => self.timeout_session.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl LdapDirectory {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.base_dn;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BaseDn));
        }
        if let Some(value) = &self.bind_dn {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::BindDn));
            }
        }
        let value = &self.bind_secret;
        value.validate(errors);
        let value = &self.filter_login;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FilterLogin));
        }
        let value = &self.filter_mailbox;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FilterMailbox));
        }
        if let Some(value) = &self.filter_member_of {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FilterMemberOf));
            }
        }
        let value = &self.attr_class;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrClass));
            }
        }
        let value = &self.attr_description;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrDescription));
            }
        }
        let value = &self.attr_email;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrEmail));
            }
        }
        let value = &self.attr_email_alias;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrEmailAlias));
            }
        }
        let value = &self.attr_member_of;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrMemberOf));
            }
        }
        let value = &self.attr_secret;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrSecret));
            }
        }
        let value = &self.attr_secret_changed;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AttrSecretChanged));
            }
        }
        let value = &self.group_class;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::GroupClass));
        }
        let value = &self.pool_max_connections;
        if *value > 8192 {
            errors.push(ValidationError::max_value(
                Property::PoolMaxConnections,
                8192,
            ));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for LdapDirectory {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.url.pickle(out);
        self.timeout.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.use_tls.pickle(out);
        self.base_dn.pickle(out);
        self.bind_dn.pickle(out);
        self.bind_secret.pickle(out);
        self.bind_authentication.pickle(out);
        self.filter_login.pickle(out);
        self.filter_mailbox.pickle(out);
        self.filter_member_of.pickle(out);
        self.attr_class.pickle(out);
        self.attr_description.pickle(out);
        self.attr_email.pickle(out);
        self.attr_email_alias.pickle(out);
        self.attr_member_of.pickle(out);
        self.attr_secret.pickle(out);
        self.attr_secret_changed.pickle(out);
        self.group_class.pickle(out);
        self.pool_max_connections.pickle(out);
        self.pool_timeout_create.pickle(out);
        self.pool_timeout_recycle.pickle(out);
        self.pool_timeout_wait.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.base_dn = Pickle::unpickle(stream)?;
        this.bind_dn = Pickle::unpickle(stream)?;
        this.bind_secret = Pickle::unpickle(stream)?;
        this.bind_authentication = Pickle::unpickle(stream)?;
        this.filter_login = Pickle::unpickle(stream)?;
        this.filter_mailbox = Pickle::unpickle(stream)?;
        this.filter_member_of = Pickle::unpickle(stream)?;
        this.attr_class = Pickle::unpickle(stream)?;
        this.attr_description = Pickle::unpickle(stream)?;
        this.attr_email = Pickle::unpickle(stream)?;
        this.attr_email_alias = Pickle::unpickle(stream)?;
        this.attr_member_of = Pickle::unpickle(stream)?;
        this.attr_secret = Pickle::unpickle(stream)?;
        this.attr_secret_changed = Pickle::unpickle(stream)?;
        this.group_class = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        this.pool_timeout_create = Pickle::unpickle(stream)?;
        this.pool_timeout_recycle = Pickle::unpickle(stream)?;
        this.pool_timeout_wait = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for LdapDirectory {
    fn default() -> Self {
        Self {
            description: Default::default(),
            url: "ldap://localhost:389".to_string(),
            timeout: Duration::from_millis(30000),
            allow_invalid_certs: false,
            use_tls: false,
            base_dn: Default::default(),
            bind_dn: Default::default(),
            bind_secret: Default::default(),
            bind_authentication: true,
            filter_login: "(&(objectClass=inetOrgPerson)(mail=?))".to_string(),
            filter_mailbox: "(|(&(objectClass=inetOrgPerson)(|(mail=?)(mailAlias=?)))(&(objectClass=groupOfNames)(|(mail=?)(mailAlias=?))))".to_string(),
            filter_member_of: Some("(&(objectClass=groupOfNames)(member=?))".to_string()),
            attr_class: Map::new(vec!["objectClass".to_string()]),
            attr_description: Map::new(vec!["description".to_string()]),
            attr_email: Map::new(vec!["mail".to_string()]),
            attr_email_alias: Map::new(vec!["mailAlias".to_string()]),
            attr_member_of: Map::new(vec!["memberOf".to_string()]),
            attr_secret: Map::new(vec!["userPassword".to_string()]),
            attr_secret_changed: Map::new(vec!["pwdChangeTime".to_string()]),
            group_class: "groupOfNames".to_string(),
            pool_max_connections: 10u64,
            pool_timeout_create: Duration::from_millis(30000),
            pool_timeout_recycle: Duration::from_millis(30000),
            pool_timeout_wait: Duration::from_millis(30000),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for LdapDirectory {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(27);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(Property::BaseDn, self.base_dn.into_value());
        map.insert_unchecked(Property::BindDn, self.bind_dn.into_value());
        map.insert_unchecked(Property::BindSecret, self.bind_secret.into_value());
        map.insert_unchecked(
            Property::BindAuthentication,
            self.bind_authentication.into_value(),
        );
        map.insert_unchecked(Property::FilterLogin, self.filter_login.into_value());
        map.insert_unchecked(Property::FilterMailbox, self.filter_mailbox.into_value());
        map.insert_unchecked(Property::FilterMemberOf, self.filter_member_of.into_value());
        map.insert_unchecked(Property::AttrClass, self.attr_class.into_value());
        map.insert_unchecked(
            Property::AttrDescription,
            self.attr_description.into_value(),
        );
        map.insert_unchecked(Property::AttrEmail, self.attr_email.into_value());
        map.insert_unchecked(Property::AttrEmailAlias, self.attr_email_alias.into_value());
        map.insert_unchecked(Property::AttrMemberOf, self.attr_member_of.into_value());
        map.insert_unchecked(Property::AttrSecret, self.attr_secret.into_value());
        map.insert_unchecked(
            Property::AttrSecretChanged,
            self.attr_secret_changed.into_value(),
        );
        map.insert_unchecked(Property::GroupClass, self.group_class.into_value());
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutCreate,
            self.pool_timeout_create.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutRecycle,
            self.pool_timeout_recycle.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutWait,
            self.pool_timeout_wait.into_value(),
        );
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for LdapDirectory {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::BaseDn) => self
                .base_dn
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::BindDn) => self
                .bind_dn
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::BindSecret) => self.bind_secret.patch(pointer, value),
            Some(Property::BindAuthentication) => self.bind_authentication.patch(pointer, value),
            Some(Property::FilterLogin) => self
                .filter_login
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::FilterMailbox) => self
                .filter_mailbox
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::FilterMemberOf) => self
                .filter_member_of
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrClass) => self
                .attr_class
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrDescription) => self
                .attr_description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrEmail) => self
                .attr_email
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrEmailAlias) => self
                .attr_email_alias
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrMemberOf) => self
                .attr_member_of
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrSecret) => self
                .attr_secret
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AttrSecretChanged) => self
                .attr_secret_changed
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::GroupClass) => self
                .group_class
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::PoolTimeoutCreate) => self.pool_timeout_create.patch(pointer, value),
            Some(Property::PoolTimeoutRecycle) => self.pool_timeout_recycle.patch(pointer, value),
            Some(Property::PoolTimeoutWait) => self.pool_timeout_wait.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Log {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Log;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.timestamp;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Timestamp, value));
        }
        let value = &self.details;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Details));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Log {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.timestamp.pickle(out);
        self.level.pickle(out);
        self.event.pickle(out);
        self.details.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.timestamp = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.event = Pickle::unpickle(stream)?;
        this.details = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Log {
    fn default() -> Self {
        Self {
            timestamp: Default::default(),
            level: Default::default(),
            event: Default::default(),
            details: Default::default(),
        }
    }
}

impl IntoValue for Log {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Timestamp, self.timestamp.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Event, self.event.into_value());
        map.insert_unchecked(Property::Details, self.details.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Log {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Timestamp) => self.timestamp.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Event) => self.event.patch(pointer, value),
            Some(Property::Details) => self.details.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl LookupStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            LookupStore::PostgreSql(inner) => inner.validate(errors),
            LookupStore::MySql(inner) => inner.validate(errors),
            LookupStore::Sqlite(inner) => inner.validate(errors),
            LookupStore::Sharded(inner) => inner.validate(errors),
            LookupStore::Redis(inner) => inner.validate(errors),
            LookupStore::RedisCluster(inner) => inner.validate(errors),
        }
    }
}

impl Default for LookupStore {
    fn default() -> Self {
        LookupStore::PostgreSql(Default::default())
    }
}

impl Pickle for LookupStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            LookupStore::PostgreSql(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            LookupStore::MySql(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            LookupStore::Sqlite(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            LookupStore::Sharded(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            LookupStore::Redis(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            LookupStore::RedisCluster(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(LookupStore::PostgreSql),
            1 => Pickle::unpickle(stream).map(LookupStore::MySql),
            2 => Pickle::unpickle(stream).map(LookupStore::Sqlite),
            3 => Pickle::unpickle(stream).map(LookupStore::Sharded),
            4 => Pickle::unpickle(stream).map(LookupStore::Redis),
            5 => Pickle::unpickle(stream).map(LookupStore::RedisCluster),
            _ => None,
        }
    }
}

impl IntoValue for LookupStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            LookupStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            LookupStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
            LookupStore::Sqlite(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sqlite".into()));
                obj
            }
            LookupStore::Sharded(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sharded".into()));
                obj
            }
            LookupStore::Redis(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Redis".into()));
                obj
            }
            LookupStore::RedisCluster(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RedisCluster".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for LookupStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                LookupStoreType::PostgreSql => *self = LookupStore::PostgreSql(Default::default()),
                LookupStoreType::MySql => *self = LookupStore::MySql(Default::default()),
                LookupStoreType::Sqlite => *self = LookupStore::Sqlite(Default::default()),
                LookupStoreType::Sharded => *self = LookupStore::Sharded(Default::default()),
                LookupStoreType::Redis => *self = LookupStore::Redis(Default::default()),
                LookupStoreType::RedisCluster => {
                    *self = LookupStore::RedisCluster(Default::default())
                }
            }
        }
        match self {
            LookupStore::PostgreSql(inner) => inner.patch(pointer, value),
            LookupStore::MySql(inner) => inner.patch(pointer, value),
            LookupStore::Sqlite(inner) => inner.patch(pointer, value),
            LookupStore::Sharded(inner) => inner.patch(pointer, value),
            LookupStore::Redis(inner) => inner.patch(pointer, value),
            LookupStore::RedisCluster(inner) => inner.patch(pointer, value),
        }
    }
}

impl LookupStore {
    pub fn object_type(&self) -> LookupStoreType {
        match self {
            LookupStore::PostgreSql(_) => LookupStoreType::PostgreSql,
            LookupStore::MySql(_) => LookupStoreType::MySql,
            LookupStore::Sqlite(_) => LookupStoreType::Sqlite,
            LookupStore::Sharded(_) => LookupStoreType::Sharded,
            LookupStore::Redis(_) => LookupStoreType::Redis,
            LookupStore::RedisCluster(_) => LookupStoreType::RedisCluster,
        }
    }
}

impl MailExchanger {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Hostname));
            }
        }
        let value = &self.priority;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Priority, 1));
        }
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Priority, 65535));
        }
        errors.len() == neb
    }
}

impl Pickle for MailExchanger {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.hostname.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.hostname = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MailExchanger {
    fn default() -> Self {
        Self {
            hostname: Default::default(),
            priority: 10u64,
        }
    }
}

impl IntoValue for MailExchanger {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Hostname, self.hostname.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MailExchanger {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Hostname) => self
                .hostname
                .patch(pointer.with_validators(&[StringValidator::Hostname]), value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MailingList {
    const FLAGS: u64 = OBJ_FILTER_TENANT | OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MailingList;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.aliases;
        for value in value.values() {
            value.validate(errors);
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.recipients;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Recipients));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Email, &self.name, &self.domain_id);
        i.text(Property::Text, &self.name);
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        for item in self.aliases.values() {
            item.index(i);
        }
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
        for value in self.recipients.iter() {
            i.text(Property::Text, value);
        }
    }
}

impl Pickle for MailingList {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.domain_id.pickle(out);
        self.description.pickle(out);
        self.aliases.pickle(out);
        self.member_tenant_id.pickle(out);
        self.recipients.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.aliases = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.recipients = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MailingList {
    fn default() -> Self {
        Self {
            name: Default::default(),
            domain_id: Default::default(),
            description: Default::default(),
            aliases: Default::default(),
            member_tenant_id: Default::default(),
            recipients: Default::default(),
        }
    }
}

impl IntoValue for MailingList {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Aliases, self.aliases.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Recipients, self.recipients.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MailingList {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(
                pointer.with_validators(&[StringValidator::EmailLocalPart]),
                value,
            ),
            Some(Property::DomainId) => self.domain_id.patch(pointer, value),
            Some(Property::EmailAddress) => pointer.assert_server_set(),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Aliases) => self.aliases.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Recipients) => self
                .recipients
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MaskedEmail {
    const FLAGS: u64 = OBJ_FILTER_ACCOUNT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MaskedEmail;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.email;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Email));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        if let Some(value) = &self.for_domain {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ForDomain));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.created_by {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::CreatedBy));
            }
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        if let Some(value) = &self.url {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Url));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for MaskedEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enabled.pickle(out);
        self.account_id.pickle(out);
        self.email.pickle(out);
        self.description.pickle(out);
        self.for_domain.pickle(out);
        self.created_at.pickle(out);
        self.created_by.pickle(out);
        self.expires_at.pickle(out);
        self.url.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enabled = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.email = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.for_domain = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.created_by = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MaskedEmail {
    fn default() -> Self {
        Self {
            enabled: true,
            account_id: Default::default(),
            email: Default::default(),
            description: Default::default(),
            for_domain: Default::default(),
            created_at: Default::default(),
            created_by: Default::default(),
            expires_at: Default::default(),
            url: Default::default(),
        }
    }
}

impl IntoValue for MaskedEmail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Enabled, self.enabled.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::Email, self.email.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::ForDomain, self.for_domain.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::CreatedBy, self.created_by.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MaskedEmail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enabled) => self.enabled.patch(pointer, value),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::Email) => pointer.assert_server_set(),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::ForDomain) => self.for_domain.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::CreatedBy) => self.created_by.patch(pointer, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer.assert_read_only()?, value),
            Some(Property::Url) => self.url.patch(pointer, value),
            Some(property @ Property::EmailPrefix) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(property @ Property::EmailDomain) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MeilisearchStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.max_retries;
        if *value > 1024 {
            errors.push(ValidationError::max_value(Property::MaxRetries, 1024));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxRetries, 1));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for MeilisearchStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.url.pickle(out);
        self.poll_interval.pickle(out);
        self.max_retries.pickle(out);
        self.fail_on_timeout.pickle(out);
        self.timeout.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.url = Pickle::unpickle(stream)?;
        this.poll_interval = Pickle::unpickle(stream)?;
        this.max_retries = Pickle::unpickle(stream)?;
        this.fail_on_timeout = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MeilisearchStore {
    fn default() -> Self {
        Self {
            url: Default::default(),
            poll_interval: Duration::from_millis(500),
            max_retries: 120u64,
            fail_on_timeout: true,
            timeout: Duration::from_millis(30000),
            allow_invalid_certs: false,
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for MeilisearchStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::PollInterval, self.poll_interval.into_value());
        map.insert_unchecked(Property::MaxRetries, self.max_retries.into_value());
        map.insert_unchecked(Property::FailOnTimeout, self.fail_on_timeout.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MeilisearchStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PollInterval) => self.poll_interval.patch(pointer, value),
            Some(Property::MaxRetries) => self.max_retries.patch(pointer, value),
            Some(Property::FailOnTimeout) => self.fail_on_timeout.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MemoryLookupKey {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MemoryLookupKey;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.namespace;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Namespace));
        }
        let value = &self.key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Key));
        }
        if value.len() > 255 {
            errors.push(ValidationError::max_length(Property::Key, 255));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Namespace, &self.namespace, &self.key);
        i.search(Property::Namespace, &self.namespace);
    }
}

impl Pickle for MemoryLookupKey {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.namespace.pickle(out);
        self.key.pickle(out);
        self.is_glob_pattern.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.namespace = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.is_glob_pattern = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MemoryLookupKey {
    fn default() -> Self {
        Self {
            namespace: Default::default(),
            key: Default::default(),
            is_glob_pattern: false,
        }
    }
}

impl IntoValue for MemoryLookupKey {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Namespace, self.namespace.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::IsGlobPattern, self.is_glob_pattern.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MemoryLookupKey {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Namespace) => self.namespace.patch(pointer, value),
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::IsGlobPattern) => self.is_glob_pattern.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MemoryLookupKeyValue {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MemoryLookupKeyValue;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.namespace;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Namespace));
        }
        let value = &self.key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Key));
        }
        if value.len() > 255 {
            errors.push(ValidationError::max_length(Property::Key, 255));
        }
        let value = &self.value;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Value));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Namespace, &self.namespace, &self.key);
        i.search(Property::Namespace, &self.namespace);
    }
}

impl Pickle for MemoryLookupKeyValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.namespace.pickle(out);
        self.key.pickle(out);
        self.value.pickle(out);
        self.is_glob_pattern.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.namespace = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.value = Pickle::unpickle(stream)?;
        this.is_glob_pattern = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MemoryLookupKeyValue {
    fn default() -> Self {
        Self {
            namespace: Default::default(),
            key: Default::default(),
            value: Default::default(),
            is_glob_pattern: false,
        }
    }
}

impl IntoValue for MemoryLookupKeyValue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Namespace, self.namespace.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Value, self.value.into_value());
        map.insert_unchecked(Property::IsGlobPattern, self.is_glob_pattern.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MemoryLookupKeyValue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Namespace) => self.namespace.patch(pointer, value),
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::IsGlobPattern) => self.is_glob_pattern.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Metric {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Metric;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Metric::Counter(inner) => inner.validate(errors),
            Metric::Gauge(inner) => inner.validate(errors),
            Metric::Histogram(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for Metric {
    fn default() -> Self {
        Metric::Counter(Default::default())
    }
}

impl Pickle for Metric {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Metric::Counter(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Metric::Gauge(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Metric::Histogram(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Metric::Counter),
            1 => Pickle::unpickle(stream).map(Metric::Gauge),
            2 => Pickle::unpickle(stream).map(Metric::Histogram),
            _ => None,
        }
    }
}

impl IntoValue for Metric {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Metric::Counter(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Counter".into()));
                obj
            }
            Metric::Gauge(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Gauge".into()));
                obj
            }
            Metric::Histogram(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Histogram".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Metric {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MetricType::Counter => *self = Metric::Counter(Default::default()),
                MetricType::Gauge => *self = Metric::Gauge(Default::default()),
                MetricType::Histogram => *self = Metric::Histogram(Default::default()),
            }
        }
        match self {
            Metric::Counter(inner) => inner.patch(pointer, value),
            Metric::Gauge(inner) => inner.patch(pointer, value),
            Metric::Histogram(inner) => inner.patch(pointer, value),
        }
    }
}

impl Metric {
    pub fn object_type(&self) -> MetricType {
        match self {
            Metric::Counter(_) => MetricType::Counter,
            Metric::Gauge(_) => MetricType::Gauge,
            Metric::Histogram(_) => MetricType::Histogram,
        }
    }
}

impl MetricCount {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for MetricCount {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.count.pickle(out);
        self.metric.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.count = Pickle::unpickle(stream)?;
        this.metric = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MetricCount {
    fn default() -> Self {
        Self {
            count: 0u64,
            metric: Default::default(),
        }
    }
}

impl IntoValue for MetricCount {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Count, self.count.into_value());
        map.insert_unchecked(Property::Metric, self.metric.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MetricCount {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Count) => self.count.patch(pointer, value),
            Some(Property::Metric) => self.metric.patch(pointer, value),
            Some(property @ Property::Timestamp) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MetricSum {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for MetricSum {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.count.pickle(out);
        self.sum.pickle(out);
        self.metric.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.count = Pickle::unpickle(stream)?;
        this.sum = Pickle::unpickle(stream)?;
        this.metric = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MetricSum {
    fn default() -> Self {
        Self {
            count: 0u64,
            sum: 0u64,
            metric: Default::default(),
        }
    }
}

impl IntoValue for MetricSum {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Count, self.count.into_value());
        map.insert_unchecked(Property::Sum, self.sum.into_value());
        map.insert_unchecked(Property::Metric, self.metric.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MetricSum {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Count) => self.count.patch(pointer, value),
            Some(Property::Sum) => self.sum.patch(pointer, value),
            Some(Property::Metric) => self.metric.patch(pointer, value),
            Some(property @ Property::Timestamp) => {
                Ok(MaybeUnpatched::Unpatched { property, value })
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Metrics {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Metrics;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.open_telemetry;
        value.validate(errors);
        let value = &self.prometheus;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Metrics {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.open_telemetry.pickle(out);
        self.prometheus.pickle(out);
        self.metrics.pickle(out);
        self.metrics_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.open_telemetry = Pickle::unpickle(stream)?;
        this.prometheus = Pickle::unpickle(stream)?;
        this.metrics = Pickle::unpickle(stream)?;
        this.metrics_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Metrics {
    fn default() -> Self {
        Self {
            open_telemetry: Default::default(),
            prometheus: Default::default(),
            metrics: Default::default(),
            metrics_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for Metrics {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::OpenTelemetry, self.open_telemetry.into_value());
        map.insert_unchecked(Property::Prometheus, self.prometheus.into_value());
        map.insert_unchecked(Property::Metrics, self.metrics.into_value());
        map.insert_unchecked(Property::MetricsPolicy, self.metrics_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Metrics {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::OpenTelemetry) => self.open_telemetry.patch(pointer, value),
            Some(Property::Prometheus) => self.prometheus.patch(pointer, value),
            Some(Property::Metrics) => self.metrics.patch(pointer, value),
            Some(Property::MetricsPolicy) => self.metrics_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MetricsOtel {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MetricsOtel::Disabled => true,
            MetricsOtel::Http(inner) => inner.validate(errors),
            MetricsOtel::Grpc(inner) => inner.validate(errors),
        }
    }
}

impl Default for MetricsOtel {
    fn default() -> Self {
        MetricsOtel::Disabled
    }
}

impl Pickle for MetricsOtel {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MetricsOtel::Disabled => {
                0u16.pickle(out);
            }
            MetricsOtel::Http(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            MetricsOtel::Grpc(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(MetricsOtel::Disabled),
            1 => Pickle::unpickle(stream).map(MetricsOtel::Http),
            2 => Pickle::unpickle(stream).map(MetricsOtel::Grpc),
            _ => None,
        }
    }
}

impl IntoValue for MetricsOtel {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MetricsOtel::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            MetricsOtel::Http(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Http".into()));
                obj
            }
            MetricsOtel::Grpc(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Grpc".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MetricsOtel {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MetricsOtelType::Disabled => *self = MetricsOtel::Disabled,
                MetricsOtelType::Http => *self = MetricsOtel::Http(Default::default()),
                MetricsOtelType::Grpc => *self = MetricsOtel::Grpc(Default::default()),
            }
        }
        match self {
            MetricsOtel::Disabled => pointer.assert_eof(),
            MetricsOtel::Http(inner) => inner.patch(pointer, value),
            MetricsOtel::Grpc(inner) => inner.patch(pointer, value),
        }
    }
}

impl MetricsOtel {
    pub fn object_type(&self) -> MetricsOtelType {
        match self {
            MetricsOtel::Disabled => MetricsOtelType::Disabled,
            MetricsOtel::Http(_) => MetricsOtelType::Http,
            MetricsOtel::Grpc(_) => MetricsOtelType::Grpc,
        }
    }
}

impl MetricsOtelGrpc {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.endpoint {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Endpoint));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for MetricsOtelGrpc {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.endpoint.pickle(out);
        self.interval.pickle(out);
        self.timeout.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.endpoint = Pickle::unpickle(stream)?;
        this.interval = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MetricsOtelGrpc {
    fn default() -> Self {
        Self {
            endpoint: Default::default(),
            interval: Duration::from_millis(60000),
            timeout: Duration::from_millis(10000),
        }
    }
}

impl IntoValue for MetricsOtelGrpc {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Endpoint, self.endpoint.into_value());
        map.insert_unchecked(Property::Interval, self.interval.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MetricsOtelGrpc {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Endpoint) => self
                .endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Interval) => self.interval.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MetricsOtelHttp {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.endpoint;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Endpoint));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for MetricsOtelHttp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.endpoint.pickle(out);
        self.interval.pickle(out);
        self.timeout.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.endpoint = Pickle::unpickle(stream)?;
        this.interval = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MetricsOtelHttp {
    fn default() -> Self {
        Self {
            endpoint: Default::default(),
            interval: Duration::from_millis(60000),
            timeout: Duration::from_millis(10000),
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for MetricsOtelHttp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Endpoint, self.endpoint.into_value());
        map.insert_unchecked(Property::Interval, self.interval.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MetricsOtelHttp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Endpoint) => self
                .endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Interval) => self.interval.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MetricsPrometheus {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MetricsPrometheus::Disabled => true,
            MetricsPrometheus::Enabled(inner) => inner.validate(errors),
        }
    }
}

impl Default for MetricsPrometheus {
    fn default() -> Self {
        MetricsPrometheus::Disabled
    }
}

impl Pickle for MetricsPrometheus {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MetricsPrometheus::Disabled => {
                0u16.pickle(out);
            }
            MetricsPrometheus::Enabled(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(MetricsPrometheus::Disabled),
            1 => Pickle::unpickle(stream).map(MetricsPrometheus::Enabled),
            _ => None,
        }
    }
}

impl IntoValue for MetricsPrometheus {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MetricsPrometheus::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            MetricsPrometheus::Enabled(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Enabled".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MetricsPrometheus {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MetricsPrometheusType::Disabled => *self = MetricsPrometheus::Disabled,
                MetricsPrometheusType::Enabled => {
                    *self = MetricsPrometheus::Enabled(Default::default())
                }
            }
        }
        match self {
            MetricsPrometheus::Disabled => pointer.assert_eof(),
            MetricsPrometheus::Enabled(inner) => inner.patch(pointer, value),
        }
    }
}

impl MetricsPrometheus {
    pub fn object_type(&self) -> MetricsPrometheusType {
        match self {
            MetricsPrometheus::Disabled => MetricsPrometheusType::Disabled,
            MetricsPrometheus::Enabled(_) => MetricsPrometheusType::Enabled,
        }
    }
}

impl MetricsPrometheusProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for MetricsPrometheusProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_secret.pickle(out);
        self.auth_username.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_secret = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MetricsPrometheusProperties {
    fn default() -> Self {
        Self {
            auth_secret: Default::default(),
            auth_username: Default::default(),
        }
    }
}

impl IntoValue for MetricsPrometheusProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MetricsPrometheusProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MetricsStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MetricsStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MetricsStore::Disabled => true,
            MetricsStore::Default => true,
            MetricsStore::FoundationDb(inner) => inner.validate(errors),
            MetricsStore::PostgreSql(inner) => inner.validate(errors),
            MetricsStore::MySql(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for MetricsStore {
    fn default() -> Self {
        MetricsStore::Disabled
    }
}

impl Pickle for MetricsStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MetricsStore::Disabled => {
                0u16.pickle(out);
            }
            MetricsStore::Default => {
                1u16.pickle(out);
            }
            MetricsStore::FoundationDb(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            MetricsStore::PostgreSql(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            MetricsStore::MySql(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(MetricsStore::Disabled),
            1 => Some(MetricsStore::Default),
            2 => Pickle::unpickle(stream).map(MetricsStore::FoundationDb),
            3 => Pickle::unpickle(stream).map(MetricsStore::PostgreSql),
            4 => Pickle::unpickle(stream).map(MetricsStore::MySql),
            _ => None,
        }
    }
}

impl IntoValue for MetricsStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MetricsStore::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            MetricsStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            MetricsStore::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            MetricsStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            MetricsStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MetricsStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MetricsStoreType::Disabled => *self = MetricsStore::Disabled,
                MetricsStoreType::Default => *self = MetricsStore::Default,
                MetricsStoreType::FoundationDb => {
                    *self = MetricsStore::FoundationDb(Default::default())
                }
                MetricsStoreType::PostgreSql => {
                    *self = MetricsStore::PostgreSql(Default::default())
                }
                MetricsStoreType::MySql => *self = MetricsStore::MySql(Default::default()),
            }
        }
        match self {
            MetricsStore::Disabled => pointer.assert_eof(),
            MetricsStore::Default => pointer.assert_eof(),
            MetricsStore::FoundationDb(inner) => inner.patch(pointer, value),
            MetricsStore::PostgreSql(inner) => inner.patch(pointer, value),
            MetricsStore::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl MetricsStore {
    pub fn object_type(&self) -> MetricsStoreType {
        match self {
            MetricsStore::Disabled => MetricsStoreType::Disabled,
            MetricsStore::Default => MetricsStoreType::Default,
            MetricsStore::FoundationDb(_) => MetricsStoreType::FoundationDb,
            MetricsStore::PostgreSql(_) => MetricsStoreType::PostgreSql,
            MetricsStore::MySql(_) => MetricsStoreType::MySql,
        }
    }
}

impl MtaConnectionIpHost {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.ehlo_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EhloHostname));
            }
        }
        let value = &self.source_ip;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::SourceIp, value));
        }
        errors.len() == neb
    }
}

impl Pickle for MtaConnectionIpHost {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.ehlo_hostname.pickle(out);
        self.source_ip.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.ehlo_hostname = Pickle::unpickle(stream)?;
        this.source_ip = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaConnectionIpHost {
    fn default() -> Self {
        Self {
            ehlo_hostname: Default::default(),
            source_ip: Default::default(),
        }
    }
}

impl IntoValue for MtaConnectionIpHost {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::EhloHostname, self.ehlo_hostname.into_value());
        map.insert_unchecked(Property::SourceIp, self.source_ip.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaConnectionIpHost {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::EhloHostname) => self
                .ehlo_hostname
                .patch(pointer.with_validators(&[StringValidator::Hostname]), value),
            Some(Property::SourceIp) => self.source_ip.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaConnectionStrategy {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaConnectionStrategy;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        if let Some(value) = &self.ehlo_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EhloHostname));
            }
        }
        let value = &self.source_ips;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaConnectionStrategy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.ehlo_hostname.pickle(out);
        self.source_ips.pickle(out);
        self.connect_timeout.pickle(out);
        self.data_timeout.pickle(out);
        self.ehlo_timeout.pickle(out);
        self.greeting_timeout.pickle(out);
        self.mail_from_timeout.pickle(out);
        self.rcpt_to_timeout.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.ehlo_hostname = Pickle::unpickle(stream)?;
        this.source_ips = Pickle::unpickle(stream)?;
        this.connect_timeout = Pickle::unpickle(stream)?;
        this.data_timeout = Pickle::unpickle(stream)?;
        this.ehlo_timeout = Pickle::unpickle(stream)?;
        this.greeting_timeout = Pickle::unpickle(stream)?;
        this.mail_from_timeout = Pickle::unpickle(stream)?;
        this.rcpt_to_timeout = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaConnectionStrategy {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            ehlo_hostname: Default::default(),
            source_ips: Default::default(),
            connect_timeout: Duration::from_millis(300000),
            data_timeout: Duration::from_millis(600000),
            ehlo_timeout: Duration::from_millis(300000),
            greeting_timeout: Duration::from_millis(300000),
            mail_from_timeout: Duration::from_millis(300000),
            rcpt_to_timeout: Duration::from_millis(300000),
        }
    }
}

impl IntoValue for MtaConnectionStrategy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::EhloHostname, self.ehlo_hostname.into_value());
        map.insert_unchecked(Property::SourceIps, self.source_ips.into_value());
        map.insert_unchecked(Property::ConnectTimeout, self.connect_timeout.into_value());
        map.insert_unchecked(Property::DataTimeout, self.data_timeout.into_value());
        map.insert_unchecked(Property::EhloTimeout, self.ehlo_timeout.into_value());
        map.insert_unchecked(
            Property::GreetingTimeout,
            self.greeting_timeout.into_value(),
        );
        map.insert_unchecked(
            Property::MailFromTimeout,
            self.mail_from_timeout.into_value(),
        );
        map.insert_unchecked(Property::RcptToTimeout, self.rcpt_to_timeout.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaConnectionStrategy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::EhloHostname) => self
                .ehlo_hostname
                .patch(pointer.with_validators(&[StringValidator::Hostname]), value),
            Some(Property::SourceIps) => self.source_ips.patch(pointer, value),
            Some(Property::ConnectTimeout) => self.connect_timeout.patch(pointer, value),
            Some(Property::DataTimeout) => self.data_timeout.patch(pointer, value),
            Some(Property::EhloTimeout) => self.ehlo_timeout.patch(pointer, value),
            Some(Property::GreetingTimeout) => self.greeting_timeout.patch(pointer, value),
            Some(Property::MailFromTimeout) => self.mail_from_timeout.patch(pointer, value),
            Some(Property::RcptToTimeout) => self.rcpt_to_timeout.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaDeliveryExpiration {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MtaDeliveryExpiration::Ttl(inner) => inner.validate(errors),
            MtaDeliveryExpiration::Attempts(inner) => inner.validate(errors),
        }
    }
}

impl Default for MtaDeliveryExpiration {
    fn default() -> Self {
        MtaDeliveryExpiration::Ttl(Default::default())
    }
}

impl Pickle for MtaDeliveryExpiration {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MtaDeliveryExpiration::Ttl(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            MtaDeliveryExpiration::Attempts(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(MtaDeliveryExpiration::Ttl),
            1 => Pickle::unpickle(stream).map(MtaDeliveryExpiration::Attempts),
            _ => None,
        }
    }
}

impl IntoValue for MtaDeliveryExpiration {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MtaDeliveryExpiration::Ttl(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ttl".into()));
                obj
            }
            MtaDeliveryExpiration::Attempts(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Attempts".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MtaDeliveryExpiration {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MtaDeliveryExpirationType::Ttl => {
                    *self = MtaDeliveryExpiration::Ttl(Default::default())
                }
                MtaDeliveryExpirationType::Attempts => {
                    *self = MtaDeliveryExpiration::Attempts(Default::default())
                }
            }
        }
        match self {
            MtaDeliveryExpiration::Ttl(inner) => inner.patch(pointer, value),
            MtaDeliveryExpiration::Attempts(inner) => inner.patch(pointer, value),
        }
    }
}

impl MtaDeliveryExpiration {
    pub fn object_type(&self) -> MtaDeliveryExpirationType {
        match self {
            MtaDeliveryExpiration::Ttl(_) => MtaDeliveryExpirationType::Ttl,
            MtaDeliveryExpiration::Attempts(_) => MtaDeliveryExpirationType::Attempts,
        }
    }
}

impl MtaDeliveryExpirationAttempts {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_attempts;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxAttempts, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for MtaDeliveryExpirationAttempts {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_attempts.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_attempts = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaDeliveryExpirationAttempts {
    fn default() -> Self {
        Self { max_attempts: 5u64 }
    }
}

impl IntoValue for MtaDeliveryExpirationAttempts {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::MaxAttempts, self.max_attempts.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaDeliveryExpirationAttempts {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxAttempts) => self.max_attempts.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaDeliveryExpirationTtl {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for MtaDeliveryExpirationTtl {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.expire.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.expire = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaDeliveryExpirationTtl {
    fn default() -> Self {
        Self {
            expire: Duration::from_millis(259200000),
        }
    }
}

impl IntoValue for MtaDeliveryExpirationTtl {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Expire, self.expire.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaDeliveryExpirationTtl {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Expire) => self.expire.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaDeliverySchedule {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaDeliverySchedule;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.expiry;
        value.validate(errors);
        let value = &self.notify;
        value.validate(errors);
        let value = &self.queue_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::QueueId));
        }
        let value = &self.retry;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
        i.foreign_key(ObjectType::MtaVirtualQueue, self.queue_id.into(), None);
    }
}

impl Pickle for MtaDeliverySchedule {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.expiry.pickle(out);
        self.notify.pickle(out);
        self.queue_id.pickle(out);
        self.retry.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.expiry = Pickle::unpickle(stream)?;
        this.notify = Pickle::unpickle(stream)?;
        this.queue_id = Pickle::unpickle(stream)?;
        this.retry = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaDeliverySchedule {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            expiry: Default::default(),
            notify: Default::default(),
            queue_id: Default::default(),
            retry: Default::default(),
        }
    }
}

impl IntoValue for MtaDeliverySchedule {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Expiry, self.expiry.into_value());
        map.insert_unchecked(Property::Notify, self.notify.into_value());
        map.insert_unchecked(Property::QueueId, self.queue_id.into_value());
        map.insert_unchecked(Property::Retry, self.retry.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaDeliverySchedule {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Expiry) => self.expiry.patch(pointer, value),
            Some(Property::Notify) => self.notify.patch(pointer, value),
            Some(Property::QueueId) => self.queue_id.patch(pointer, value),
            Some(Property::Retry) => self.retry.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaDeliveryScheduleInterval {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for MtaDeliveryScheduleInterval {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.duration.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.duration = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaDeliveryScheduleInterval {
    fn default() -> Self {
        Self {
            duration: Duration::from_millis(3600000),
        }
    }
}

impl IntoValue for MtaDeliveryScheduleInterval {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Duration, self.duration.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaDeliveryScheduleInterval {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Duration) => self.duration.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaDeliveryScheduleIntervals {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.intervals;
        for value in value.values() {
            value.validate(errors);
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Intervals, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for MtaDeliveryScheduleIntervals {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.intervals.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.intervals = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaDeliveryScheduleIntervals {
    fn default() -> Self {
        Self {
            intervals: Default::default(),
        }
    }
}

impl IntoValue for MtaDeliveryScheduleIntervals {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Intervals, self.intervals.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaDeliveryScheduleIntervals {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Intervals) => self.intervals.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaDeliveryScheduleIntervalsOrDefault {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MtaDeliveryScheduleIntervalsOrDefault::Default => true,
            MtaDeliveryScheduleIntervalsOrDefault::Custom(inner) => inner.validate(errors),
        }
    }
}

impl Default for MtaDeliveryScheduleIntervalsOrDefault {
    fn default() -> Self {
        MtaDeliveryScheduleIntervalsOrDefault::Default
    }
}

impl Pickle for MtaDeliveryScheduleIntervalsOrDefault {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MtaDeliveryScheduleIntervalsOrDefault::Default => {
                0u16.pickle(out);
            }
            MtaDeliveryScheduleIntervalsOrDefault::Custom(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(MtaDeliveryScheduleIntervalsOrDefault::Default),
            1 => Pickle::unpickle(stream).map(MtaDeliveryScheduleIntervalsOrDefault::Custom),
            _ => None,
        }
    }
}

impl IntoValue for MtaDeliveryScheduleIntervalsOrDefault {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MtaDeliveryScheduleIntervalsOrDefault::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            MtaDeliveryScheduleIntervalsOrDefault::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MtaDeliveryScheduleIntervalsOrDefault {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MtaDeliveryScheduleIntervalsOrDefaultType::Default => {
                    *self = MtaDeliveryScheduleIntervalsOrDefault::Default
                }
                MtaDeliveryScheduleIntervalsOrDefaultType::Custom => {
                    *self = MtaDeliveryScheduleIntervalsOrDefault::Custom(Default::default())
                }
            }
        }
        match self {
            MtaDeliveryScheduleIntervalsOrDefault::Default => pointer.assert_eof(),
            MtaDeliveryScheduleIntervalsOrDefault::Custom(inner) => inner.patch(pointer, value),
        }
    }
}

impl MtaDeliveryScheduleIntervalsOrDefault {
    pub fn object_type(&self) -> MtaDeliveryScheduleIntervalsOrDefaultType {
        match self {
            MtaDeliveryScheduleIntervalsOrDefault::Default => {
                MtaDeliveryScheduleIntervalsOrDefaultType::Default
            }
            MtaDeliveryScheduleIntervalsOrDefault::Custom(_) => {
                MtaDeliveryScheduleIntervalsOrDefaultType::Custom
            }
        }
    }
}

impl ObjectImpl for MtaExtensions {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaExtensions;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.chunking;
        value.validate(errors);
        let value = &self.deliver_by;
        value.validate(errors);
        let value = &self.dsn;
        value.validate(errors);
        let value = &self.expn;
        value.validate(errors);
        let value = &self.future_release;
        value.validate(errors);
        let value = &self.mt_priority;
        value.validate(errors);
        let value = &self.no_soliciting;
        value.validate(errors);
        let value = &self.pipelining;
        value.validate(errors);
        let value = &self.require_tls;
        value.validate(errors);
        let value = &self.vrfy;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaExtensions {
    pub fn ctx_chunking(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.chunking,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Chunking,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_deliver_by(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.deliver_by,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "15d".to_string(),
                }]),
            }),
            property: Property::DeliverBy,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dsn(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dsn,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::Dsn,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_expn(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.expn,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::Expn,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_future_release(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.future_release,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "7d".to_string(),
                }]),
            }),
            property: Property::FutureRelease,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_mt_priority(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.mt_priority,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "mixer".to_string(),
                }]),
            }),
            property: Property::MtPriority,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: MTA_PRIORITY_CONSTANT,
        }
    }

    pub fn ctx_no_soliciting(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.no_soliciting,
            default: Some(Expression {
                else_: "''".to_string(),
                ..Default::default()
            }),
            property: Property::NoSoliciting,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_pipelining(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.pipelining,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Pipelining,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_require_tls(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.require_tls,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::RequireTls,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_vrfy(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.vrfy,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::Vrfy,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_chunking(),
            self.ctx_deliver_by(),
            self.ctx_dsn(),
            self.ctx_expn(),
            self.ctx_future_release(),
            self.ctx_mt_priority(),
            self.ctx_no_soliciting(),
            self.ctx_pipelining(),
            self.ctx_require_tls(),
            self.ctx_vrfy(),
        ]
    }
}

impl Pickle for MtaExtensions {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.chunking.pickle(out);
        self.deliver_by.pickle(out);
        self.dsn.pickle(out);
        self.expn.pickle(out);
        self.future_release.pickle(out);
        self.mt_priority.pickle(out);
        self.no_soliciting.pickle(out);
        self.pipelining.pickle(out);
        self.require_tls.pickle(out);
        self.vrfy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.chunking = Pickle::unpickle(stream)?;
        this.deliver_by = Pickle::unpickle(stream)?;
        this.dsn = Pickle::unpickle(stream)?;
        this.expn = Pickle::unpickle(stream)?;
        this.future_release = Pickle::unpickle(stream)?;
        this.mt_priority = Pickle::unpickle(stream)?;
        this.no_soliciting = Pickle::unpickle(stream)?;
        this.pipelining = Pickle::unpickle(stream)?;
        this.require_tls = Pickle::unpickle(stream)?;
        this.vrfy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaExtensions {
    fn default() -> Self {
        Self {
            chunking: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            deliver_by: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "15d".to_string(),
                }]),
            },
            dsn: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            },
            expn: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            },
            future_release: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "7d".to_string(),
                }]),
            },
            mt_priority: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "mixer".to_string(),
                }]),
            },
            no_soliciting: Expression {
                else_: "''".to_string(),
                ..Default::default()
            },
            pipelining: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            require_tls: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            vrfy: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "!is_empty(authenticated_as)".to_string(),
                    then: "true".to_string(),
                }]),
            },
        }
    }
}

impl IntoValue for MtaExtensions {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Chunking, self.chunking.into_value());
        map.insert_unchecked(Property::DeliverBy, self.deliver_by.into_value());
        map.insert_unchecked(Property::Dsn, self.dsn.into_value());
        map.insert_unchecked(Property::Expn, self.expn.into_value());
        map.insert_unchecked(Property::FutureRelease, self.future_release.into_value());
        map.insert_unchecked(Property::MtPriority, self.mt_priority.into_value());
        map.insert_unchecked(Property::NoSoliciting, self.no_soliciting.into_value());
        map.insert_unchecked(Property::Pipelining, self.pipelining.into_value());
        map.insert_unchecked(Property::RequireTls, self.require_tls.into_value());
        map.insert_unchecked(Property::Vrfy, self.vrfy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaExtensions {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Chunking) => self.chunking.patch(pointer, value),
            Some(Property::DeliverBy) => self.deliver_by.patch(pointer, value),
            Some(Property::Dsn) => self.dsn.patch(pointer, value),
            Some(Property::Expn) => self.expn.patch(pointer, value),
            Some(Property::FutureRelease) => self.future_release.patch(pointer, value),
            Some(Property::MtPriority) => self.mt_priority.patch(pointer, value),
            Some(Property::NoSoliciting) => self.no_soliciting.patch(pointer, value),
            Some(Property::Pipelining) => self.pipelining.patch(pointer, value),
            Some(Property::RequireTls) => self.require_tls.patch(pointer, value),
            Some(Property::Vrfy) => self.vrfy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaHook {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaHook;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.enable;
        value.validate(errors);
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaHook {
    pub fn ctx_enable(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.enable,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Enable,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_enable()]
    }
}

impl Pickle for MtaHook {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_invalid_certs.pickle(out);
        self.enable.pickle(out);
        self.max_response_size.pickle(out);
        self.temp_fail_on_error.pickle(out);
        self.stages.pickle(out);
        self.timeout.pickle(out);
        self.url.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.max_response_size = Pickle::unpickle(stream)?;
        this.temp_fail_on_error = Pickle::unpickle(stream)?;
        this.stages = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaHook {
    fn default() -> Self {
        Self {
            allow_invalid_certs: false,
            enable: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            max_response_size: 52428800u64,
            temp_fail_on_error: true,
            stages: Map::new(vec![MtaStage::Data]),
            timeout: Duration::from_millis(30000),
            url: Default::default(),
            http_auth: Default::default(),
            http_headers: Default::default(),
        }
    }
}

impl IntoValue for MtaHook {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(
            Property::MaxResponseSize,
            self.max_response_size.into_value(),
        );
        map.insert_unchecked(
            Property::TempFailOnError,
            self.temp_fail_on_error.into_value(),
        );
        map.insert_unchecked(Property::Stages, self.stages.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaHook {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::MaxResponseSize) => self.max_response_size.patch(pointer, value),
            Some(Property::TempFailOnError) => self.temp_fail_on_error.patch(pointer, value),
            Some(Property::Stages) => self.stages.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaInboundSession {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaInboundSession;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_duration;
        value.validate(errors);
        let value = &self.timeout;
        value.validate(errors);
        let value = &self.transfer_limit;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaInboundSession {
    pub fn ctx_max_duration(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_duration,
            default: Some(Expression {
                else_: "10m".to_string(),
                ..Default::default()
            }),
            property: Property::MaxDuration,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_timeout(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.timeout,
            default: Some(Expression {
                else_: "5m".to_string(),
                ..Default::default()
            }),
            property: Property::Timeout,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_transfer_limit(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.transfer_limit,
            default: Some(Expression {
                else_: "262144000".to_string(),
                ..Default::default()
            }),
            property: Property::TransferLimit,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_max_duration(),
            self.ctx_timeout(),
            self.ctx_transfer_limit(),
        ]
    }
}

impl Pickle for MtaInboundSession {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_duration.pickle(out);
        self.timeout.pickle(out);
        self.transfer_limit.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_duration = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.transfer_limit = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaInboundSession {
    fn default() -> Self {
        Self {
            max_duration: Expression {
                else_: "10m".to_string(),
                ..Default::default()
            },
            timeout: Expression {
                else_: "5m".to_string(),
                ..Default::default()
            },
            transfer_limit: Expression {
                else_: "262144000".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaInboundSession {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::MaxDuration, self.max_duration.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::TransferLimit, self.transfer_limit.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaInboundSession {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxDuration) => self.max_duration.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::TransferLimit) => self.transfer_limit.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaInboundThrottle {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaInboundThrottle;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.match_;
        value.validate(errors);
        let value = &self.rate;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaInboundThrottle {
    pub fn ctx_match_(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.match_,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Match,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_match_()]
    }
}

impl Pickle for MtaInboundThrottle {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable.pickle(out);
        self.description.pickle(out);
        self.key.pickle(out);
        self.match_.pickle(out);
        self.rate.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.match_ = Pickle::unpickle(stream)?;
        this.rate = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaInboundThrottle {
    fn default() -> Self {
        Self {
            enable: true,
            description: Default::default(),
            key: Default::default(),
            match_: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            rate: Default::default(),
        }
    }
}

impl IntoValue for MtaInboundThrottle {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Match, self.match_.into_value());
        map.insert_unchecked(Property::Rate, self.rate.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaInboundThrottle {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Description) => {
                self.description.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Match) => self.match_.patch(pointer, value),
            Some(Property::Rate) => self.rate.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaMilter {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaMilter;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.enable;
        value.validate(errors);
        let value = &self.hostname;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Hostname));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.stages;
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Stages, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaMilter {
    pub fn ctx_enable(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.enable,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Enable,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_enable()]
    }
}

impl Pickle for MtaMilter {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_invalid_certs.pickle(out);
        self.enable.pickle(out);
        self.hostname.pickle(out);
        self.max_response_size.pickle(out);
        self.temp_fail_on_error.pickle(out);
        self.protocol_version.pickle(out);
        self.port.pickle(out);
        self.stages.pickle(out);
        self.timeout_command.pickle(out);
        self.timeout_connect.pickle(out);
        self.timeout_data.pickle(out);
        self.use_tls.pickle(out);
        self.flags_action.pickle(out);
        self.flags_protocol.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.hostname = Pickle::unpickle(stream)?;
        this.max_response_size = Pickle::unpickle(stream)?;
        this.temp_fail_on_error = Pickle::unpickle(stream)?;
        this.protocol_version = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.stages = Pickle::unpickle(stream)?;
        this.timeout_command = Pickle::unpickle(stream)?;
        this.timeout_connect = Pickle::unpickle(stream)?;
        this.timeout_data = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.flags_action = Pickle::unpickle(stream)?;
        this.flags_protocol = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaMilter {
    fn default() -> Self {
        Self {
            allow_invalid_certs: false,
            enable: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            hostname: Default::default(),
            max_response_size: 52428800u64,
            temp_fail_on_error: true,
            protocol_version: MilterVersion::V6,
            port: 11332u64,
            stages: Map::new(vec![MtaStage::Data]),
            timeout_command: Duration::from_millis(30000),
            timeout_connect: Duration::from_millis(30000),
            timeout_data: Duration::from_millis(60000),
            use_tls: false,
            flags_action: Default::default(),
            flags_protocol: Default::default(),
        }
    }
}

impl IntoValue for MtaMilter {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Hostname, self.hostname.into_value());
        map.insert_unchecked(
            Property::MaxResponseSize,
            self.max_response_size.into_value(),
        );
        map.insert_unchecked(
            Property::TempFailOnError,
            self.temp_fail_on_error.into_value(),
        );
        map.insert_unchecked(
            Property::ProtocolVersion,
            self.protocol_version.into_value(),
        );
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Stages, self.stages.into_value());
        map.insert_unchecked(Property::TimeoutCommand, self.timeout_command.into_value());
        map.insert_unchecked(Property::TimeoutConnect, self.timeout_connect.into_value());
        map.insert_unchecked(Property::TimeoutData, self.timeout_data.into_value());
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(Property::FlagsAction, self.flags_action.into_value());
        map.insert_unchecked(Property::FlagsProtocol, self.flags_protocol.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaMilter {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Hostname) => self
                .hostname
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MaxResponseSize) => self.max_response_size.patch(pointer, value),
            Some(Property::TempFailOnError) => self.temp_fail_on_error.patch(pointer, value),
            Some(Property::ProtocolVersion) => self.protocol_version.patch(pointer, value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Stages) => self.stages.patch(pointer, value),
            Some(Property::TimeoutCommand) => self.timeout_command.patch(pointer, value),
            Some(Property::TimeoutConnect) => self.timeout_connect.patch(pointer, value),
            Some(Property::TimeoutData) => self.timeout_data.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::FlagsAction) => self.flags_action.patch(pointer, value),
            Some(Property::FlagsProtocol) => self.flags_protocol.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaOutboundStrategy {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaOutboundStrategy;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.connection;
        value.validate(errors);
        let value = &self.route;
        value.validate(errors);
        let value = &self.schedule;
        value.validate(errors);
        let value = &self.tls;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaOutboundStrategy {
    pub fn ctx_connection(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.connection,
            default: Some(Expression {
                else_: "'default'".to_string(),
                ..Default::default()
            }),
            property: Property::Connection,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_route(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.route,
            default: Some(Expression {
                else_: "'mx'".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "is_local_domain(rcpt_domain)".to_string(),
                    then: "'local'".to_string(),
                }]),
            }),
            property: Property::Route,
            allowed_variables: MTA_QUEUE_RCPT_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_schedule(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.schedule,
            default: Some(Expression {
                else_: "'remote'".to_string(),
                match_: List::from_iter([
                    ExpressionMatch {
                        if_: "is_local_domain(rcpt_domain)".to_string(),
                        then: "'local'".to_string(),
                    },
                    ExpressionMatch {
                        if_: "source == 'dsn'".to_string(),
                        then: "'dsn'".to_string(),
                    },
                    ExpressionMatch {
                        if_: "source == 'report'".to_string(),
                        then: "'report'".to_string(),
                    },
                ]),
            }),
            property: Property::Schedule,
            allowed_variables: MTA_QUEUE_RCPT_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_tls(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tls,
            default: Some(Expression {
                else_: "'default'".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "retry_num > 0 && last_error == 'tls'".to_string(),
                    then: "'invalid-tls'".to_string(),
                }]),
            }),
            property: Property::Tls,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_connection(),
            self.ctx_route(),
            self.ctx_schedule(),
            self.ctx_tls(),
        ]
    }
}

impl Pickle for MtaOutboundStrategy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.connection.pickle(out);
        self.route.pickle(out);
        self.schedule.pickle(out);
        self.tls.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.connection = Pickle::unpickle(stream)?;
        this.route = Pickle::unpickle(stream)?;
        this.schedule = Pickle::unpickle(stream)?;
        this.tls = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaOutboundStrategy {
    fn default() -> Self {
        Self {
            connection: Expression {
                else_: "'default'".to_string(),
                ..Default::default()
            },
            route: Expression {
                else_: "'mx'".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "is_local_domain(rcpt_domain)".to_string(),
                    then: "'local'".to_string(),
                }]),
            },
            schedule: Expression {
                else_: "'remote'".to_string(),
                match_: List::from_iter([
                    ExpressionMatch {
                        if_: "is_local_domain(rcpt_domain)".to_string(),
                        then: "'local'".to_string(),
                    },
                    ExpressionMatch {
                        if_: "source == 'dsn'".to_string(),
                        then: "'dsn'".to_string(),
                    },
                    ExpressionMatch {
                        if_: "source == 'report'".to_string(),
                        then: "'report'".to_string(),
                    },
                ]),
            },
            tls: Expression {
                else_: "'default'".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "retry_num > 0 && last_error == 'tls'".to_string(),
                    then: "'invalid-tls'".to_string(),
                }]),
            },
        }
    }
}

impl IntoValue for MtaOutboundStrategy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Connection, self.connection.into_value());
        map.insert_unchecked(Property::Route, self.route.into_value());
        map.insert_unchecked(Property::Schedule, self.schedule.into_value());
        map.insert_unchecked(Property::Tls, self.tls.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaOutboundStrategy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Connection) => self.connection.patch(pointer, value),
            Some(Property::Route) => self.route.patch(pointer, value),
            Some(Property::Schedule) => self.schedule.patch(pointer, value),
            Some(Property::Tls) => self.tls.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaOutboundThrottle {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaOutboundThrottle;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.match_;
        value.validate(errors);
        let value = &self.rate;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaOutboundThrottle {
    pub fn ctx_match_(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.match_,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Match,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_match_()]
    }
}

impl Pickle for MtaOutboundThrottle {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable.pickle(out);
        self.description.pickle(out);
        self.key.pickle(out);
        self.match_.pickle(out);
        self.rate.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.match_ = Pickle::unpickle(stream)?;
        this.rate = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaOutboundThrottle {
    fn default() -> Self {
        Self {
            enable: true,
            description: Default::default(),
            key: Default::default(),
            match_: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            rate: Default::default(),
        }
    }
}

impl IntoValue for MtaOutboundThrottle {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Match, self.match_.into_value());
        map.insert_unchecked(Property::Rate, self.rate.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaOutboundThrottle {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Match) => self.match_.patch(pointer, value),
            Some(Property::Rate) => self.rate.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaQueueQuota {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaQueueQuota;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.key;
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Key, 1));
        }
        let value = &self.match_;
        value.validate(errors);
        if let Some(value) = &self.messages {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::Messages, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaQueueQuota {
    pub fn ctx_match_(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.match_,
            default: None,
            property: Property::Match,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_match_()]
    }
}

impl Pickle for MtaQueueQuota {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable.pickle(out);
        self.description.pickle(out);
        self.key.pickle(out);
        self.match_.pickle(out);
        self.messages.pickle(out);
        self.size.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.match_ = Pickle::unpickle(stream)?;
        this.messages = Pickle::unpickle(stream)?;
        this.size = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaQueueQuota {
    fn default() -> Self {
        Self {
            enable: true,
            description: Default::default(),
            key: Default::default(),
            match_: Default::default(),
            messages: Default::default(),
            size: Default::default(),
        }
    }
}

impl IntoValue for MtaQueueQuota {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Match, self.match_.into_value());
        map.insert_unchecked(Property::Messages, self.messages.into_value());
        map.insert_unchecked(Property::Size, self.size.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaQueueQuota {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Description) => {
                self.description.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Match) => self.match_.patch(pointer, value),
            Some(Property::Messages) => self.messages.patch(pointer, value),
            Some(Property::Size) => self.size.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaRoute {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaRoute;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            MtaRoute::Mx(inner) => inner.validate(errors),
            MtaRoute::Relay(inner) => inner.validate(errors),
            MtaRoute::Local(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            MtaRoute::Mx(object) => {
                object.index(i);
            }
            MtaRoute::Relay(object) => {
                object.index(i);
            }
            MtaRoute::Local(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for MtaRoute {
    fn default() -> Self {
        MtaRoute::Mx(Default::default())
    }
}

impl Pickle for MtaRoute {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            MtaRoute::Mx(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            MtaRoute::Relay(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            MtaRoute::Local(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(MtaRoute::Mx),
            1 => Pickle::unpickle(stream).map(MtaRoute::Relay),
            2 => Pickle::unpickle(stream).map(MtaRoute::Local),
            _ => None,
        }
    }
}

impl IntoValue for MtaRoute {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            MtaRoute::Mx(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Mx".into()));
                obj
            }
            MtaRoute::Relay(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Relay".into()));
                obj
            }
            MtaRoute::Local(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Local".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for MtaRoute {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                MtaRouteType::Mx => *self = MtaRoute::Mx(Default::default()),
                MtaRouteType::Relay => *self = MtaRoute::Relay(Default::default()),
                MtaRouteType::Local => *self = MtaRoute::Local(Default::default()),
            }
        }
        match self {
            MtaRoute::Mx(inner) => inner.patch(pointer, value),
            MtaRoute::Relay(inner) => inner.patch(pointer, value),
            MtaRoute::Local(inner) => inner.patch(pointer, value),
        }
    }
}

impl MtaRoute {
    pub fn object_type(&self) -> MtaRouteType {
        match self {
            MtaRoute::Mx(_) => MtaRouteType::Mx,
            MtaRoute::Relay(_) => MtaRouteType::Relay,
            MtaRoute::Local(_) => MtaRouteType::Local,
        }
    }
}

impl MtaRouteCommon {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaRouteCommon {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaRouteCommon {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
        }
    }
}

impl IntoValue for MtaRouteCommon {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaRouteCommon {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaRouteMx {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_multihomed;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMultihomed, 1));
        }
        let value = &self.max_mx_hosts;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMxHosts, 1));
        }
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaRouteMx {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.ip_lookup_strategy.pickle(out);
        self.max_multihomed.pickle(out);
        self.max_mx_hosts.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.ip_lookup_strategy = Pickle::unpickle(stream)?;
        this.max_multihomed = Pickle::unpickle(stream)?;
        this.max_mx_hosts = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaRouteMx {
    fn default() -> Self {
        Self {
            ip_lookup_strategy: MtaIpStrategy::V4ThenV6,
            max_multihomed: 2u64,
            max_mx_hosts: 5u64,
            name: Default::default(),
            description: Default::default(),
        }
    }
}

impl IntoValue for MtaRouteMx {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(
            Property::IpLookupStrategy,
            self.ip_lookup_strategy.into_value(),
        );
        map.insert_unchecked(Property::MaxMultihomed, self.max_multihomed.into_value());
        map.insert_unchecked(Property::MaxMxHosts, self.max_mx_hosts.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaRouteMx {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IpLookupStrategy) => self.ip_lookup_strategy.patch(pointer, value),
            Some(Property::MaxMultihomed) => self.max_multihomed.patch(pointer, value),
            Some(Property::MaxMxHosts) => self.max_mx_hosts.patch(pointer, value),
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MtaRouteRelay {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.address;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Address));
        }
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaRouteRelay {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.address.pickle(out);
        self.auth_secret.pickle(out);
        self.auth_username.pickle(out);
        self.port.pickle(out);
        self.protocol.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.implicit_tls.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.address = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.protocol = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.implicit_tls = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaRouteRelay {
    fn default() -> Self {
        Self {
            address: Default::default(),
            auth_secret: Default::default(),
            auth_username: Default::default(),
            port: 25u64,
            protocol: MtaProtocol::Smtp,
            allow_invalid_certs: false,
            implicit_tls: false,
            name: Default::default(),
            description: Default::default(),
        }
    }
}

impl IntoValue for MtaRouteRelay {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Address, self.address.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Protocol, self.protocol.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::ImplicitTls, self.implicit_tls.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaRouteRelay {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Address) => self
                .address
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::AuthUsername) => self.auth_username.patch(pointer, value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Protocol) => self.protocol.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::ImplicitTls) => self.implicit_tls.patch(pointer, value),
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageAuth {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageAuth;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_failures;
        value.validate(errors);
        let value = &self.wait_on_fail;
        value.validate(errors);
        let value = &self.sasl_mechanisms;
        value.validate(errors);
        let value = &self.must_match_sender;
        value.validate(errors);
        let value = &self.require;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageAuth {
    pub fn ctx_max_failures(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_failures,
            default: Some(Expression {
                else_: "3".to_string(),
                ..Default::default()
            }),
            property: Property::MaxFailures,
            allowed_variables: MTA_EHLO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_wait_on_fail(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.wait_on_fail,
            default: Some(Expression {
                else_: "5s".to_string(),
                ..Default::default()
            }),
            property: Property::WaitOnFail,
            allowed_variables: MTA_EHLO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_sasl_mechanisms(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.sasl_mechanisms,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([
                    ExpressionMatch {
                        if_: "local_port != 25 && is_tls".to_string(),
                        then: "[plain, login, oauthbearer, xoauth2]".to_string(),
                    },
                    ExpressionMatch {
                        if_: "local_port != 25".to_string(),
                        then: "[oauthbearer, xoauth2]".to_string(),
                    },
                ]),
            }),
            property: Property::SaslMechanisms,
            allowed_variables: MTA_EHLO_VARIABLE,
            allowed_constants: MTA_AUTH_TYPE_CONSTANT,
        }
    }

    pub fn ctx_must_match_sender(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.must_match_sender,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::MustMatchSender,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_require(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.require,
            default: Some(Expression {
                else_: "local_port != 25".to_string(),
                ..Default::default()
            }),
            property: Property::Require,
            allowed_variables: MTA_EHLO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_max_failures(),
            self.ctx_wait_on_fail(),
            self.ctx_sasl_mechanisms(),
            self.ctx_must_match_sender(),
            self.ctx_require(),
        ]
    }
}

impl Pickle for MtaStageAuth {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_failures.pickle(out);
        self.wait_on_fail.pickle(out);
        self.sasl_mechanisms.pickle(out);
        self.must_match_sender.pickle(out);
        self.require.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_failures = Pickle::unpickle(stream)?;
        this.wait_on_fail = Pickle::unpickle(stream)?;
        this.sasl_mechanisms = Pickle::unpickle(stream)?;
        this.must_match_sender = Pickle::unpickle(stream)?;
        this.require = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageAuth {
    fn default() -> Self {
        Self {
            max_failures: Expression {
                else_: "3".to_string(),
                ..Default::default()
            },
            wait_on_fail: Expression {
                else_: "5s".to_string(),
                ..Default::default()
            },
            sasl_mechanisms: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([
                    ExpressionMatch {
                        if_: "local_port != 25 && is_tls".to_string(),
                        then: "[plain, login, oauthbearer, xoauth2]".to_string(),
                    },
                    ExpressionMatch {
                        if_: "local_port != 25".to_string(),
                        then: "[oauthbearer, xoauth2]".to_string(),
                    },
                ]),
            },
            must_match_sender: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            require: Expression {
                else_: "local_port != 25".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageAuth {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::MaxFailures, self.max_failures.into_value());
        map.insert_unchecked(Property::WaitOnFail, self.wait_on_fail.into_value());
        map.insert_unchecked(Property::SaslMechanisms, self.sasl_mechanisms.into_value());
        map.insert_unchecked(
            Property::MustMatchSender,
            self.must_match_sender.into_value(),
        );
        map.insert_unchecked(Property::Require, self.require.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageAuth {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxFailures) => self.max_failures.patch(pointer, value),
            Some(Property::WaitOnFail) => self.wait_on_fail.patch(pointer, value),
            Some(Property::SaslMechanisms) => self.sasl_mechanisms.patch(pointer, value),
            Some(Property::MustMatchSender) => self.must_match_sender.patch(pointer, value),
            Some(Property::Require) => self.require.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageConnect {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageConnect;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.smtp_greeting;
        value.validate(errors);
        let value = &self.hostname;
        value.validate(errors);
        let value = &self.script;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageConnect {
    pub fn ctx_smtp_greeting(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.smtp_greeting,
            default: Some(Expression {
                else_: "system('hostname') + ' Stalwart ESMTP at your service'".to_string(),
                ..Default::default()
            }),
            property: Property::SmtpGreeting,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_hostname(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.hostname,
            default: Some(Expression {
                else_: "system('hostname')".to_string(),
                ..Default::default()
            }),
            property: Property::Hostname,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_script(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.script,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Script,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_smtp_greeting(),
            self.ctx_hostname(),
            self.ctx_script(),
        ]
    }
}

impl Pickle for MtaStageConnect {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.smtp_greeting.pickle(out);
        self.hostname.pickle(out);
        self.script.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.smtp_greeting = Pickle::unpickle(stream)?;
        this.hostname = Pickle::unpickle(stream)?;
        this.script = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageConnect {
    fn default() -> Self {
        Self {
            smtp_greeting: Expression {
                else_: "system('hostname') + ' Stalwart ESMTP at your service'".to_string(),
                ..Default::default()
            },
            hostname: Expression {
                else_: "system('hostname')".to_string(),
                ..Default::default()
            },
            script: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageConnect {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::SmtpGreeting, self.smtp_greeting.into_value());
        map.insert_unchecked(Property::Hostname, self.hostname.into_value());
        map.insert_unchecked(Property::Script, self.script.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageConnect {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::SmtpGreeting) => self.smtp_greeting.patch(pointer, value),
            Some(Property::Hostname) => self.hostname.patch(pointer, value),
            Some(Property::Script) => self.script.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageData {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageData;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.add_auth_results_header;
        value.validate(errors);
        let value = &self.add_date_header;
        value.validate(errors);
        let value = &self.add_message_id_header;
        value.validate(errors);
        let value = &self.add_received_header;
        value.validate(errors);
        let value = &self.add_received_spf_header;
        value.validate(errors);
        let value = &self.add_return_path_header;
        value.validate(errors);
        let value = &self.max_messages;
        value.validate(errors);
        let value = &self.max_received_headers;
        value.validate(errors);
        let value = &self.max_message_size;
        value.validate(errors);
        let value = &self.script;
        value.validate(errors);
        let value = &self.enable_spam_filter;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageData {
    pub fn ctx_add_auth_results_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_auth_results_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddAuthResultsHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_add_date_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_date_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddDateHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_add_message_id_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_message_id_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddMessageIdHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_add_received_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_received_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddReceivedHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_add_received_spf_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_received_spf_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddReceivedSpfHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_add_return_path_header(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.add_return_path_header,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::AddReturnPathHeader,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_max_messages(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_messages,
            default: Some(Expression {
                else_: "10".to_string(),
                ..Default::default()
            }),
            property: Property::MaxMessages,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_max_received_headers(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_received_headers,
            default: Some(Expression {
                else_: "50".to_string(),
                ..Default::default()
            }),
            property: Property::MaxReceivedHeaders,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_max_message_size(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_message_size,
            default: Some(Expression {
                else_: "104857600".to_string(),
                ..Default::default()
            }),
            property: Property::MaxMessageSize,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_script(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.script,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Script,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_enable_spam_filter(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.enable_spam_filter,
            default: Some(Expression {
                else_: "is_empty(authenticated_as)".to_string(),
                ..Default::default()
            }),
            property: Property::EnableSpamFilter,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_add_auth_results_header(),
            self.ctx_add_date_header(),
            self.ctx_add_message_id_header(),
            self.ctx_add_received_header(),
            self.ctx_add_received_spf_header(),
            self.ctx_add_return_path_header(),
            self.ctx_max_messages(),
            self.ctx_max_received_headers(),
            self.ctx_max_message_size(),
            self.ctx_script(),
            self.ctx_enable_spam_filter(),
        ]
    }
}

impl Pickle for MtaStageData {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.add_auth_results_header.pickle(out);
        self.add_date_header.pickle(out);
        self.add_delivered_to_header.pickle(out);
        self.add_message_id_header.pickle(out);
        self.add_received_header.pickle(out);
        self.add_received_spf_header.pickle(out);
        self.add_return_path_header.pickle(out);
        self.max_messages.pickle(out);
        self.max_received_headers.pickle(out);
        self.max_message_size.pickle(out);
        self.script.pickle(out);
        self.enable_spam_filter.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.add_auth_results_header = Pickle::unpickle(stream)?;
        this.add_date_header = Pickle::unpickle(stream)?;
        this.add_delivered_to_header = Pickle::unpickle(stream)?;
        this.add_message_id_header = Pickle::unpickle(stream)?;
        this.add_received_header = Pickle::unpickle(stream)?;
        this.add_received_spf_header = Pickle::unpickle(stream)?;
        this.add_return_path_header = Pickle::unpickle(stream)?;
        this.max_messages = Pickle::unpickle(stream)?;
        this.max_received_headers = Pickle::unpickle(stream)?;
        this.max_message_size = Pickle::unpickle(stream)?;
        this.script = Pickle::unpickle(stream)?;
        this.enable_spam_filter = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageData {
    fn default() -> Self {
        Self {
            add_auth_results_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            add_date_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            add_delivered_to_header: true,
            add_message_id_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            add_received_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            add_received_spf_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            add_return_path_header: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            max_messages: Expression {
                else_: "10".to_string(),
                ..Default::default()
            },
            max_received_headers: Expression {
                else_: "50".to_string(),
                ..Default::default()
            },
            max_message_size: Expression {
                else_: "104857600".to_string(),
                ..Default::default()
            },
            script: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
            enable_spam_filter: Expression {
                else_: "is_empty(authenticated_as)".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageData {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(
            Property::AddAuthResultsHeader,
            self.add_auth_results_header.into_value(),
        );
        map.insert_unchecked(Property::AddDateHeader, self.add_date_header.into_value());
        map.insert_unchecked(
            Property::AddDeliveredToHeader,
            self.add_delivered_to_header.into_value(),
        );
        map.insert_unchecked(
            Property::AddMessageIdHeader,
            self.add_message_id_header.into_value(),
        );
        map.insert_unchecked(
            Property::AddReceivedHeader,
            self.add_received_header.into_value(),
        );
        map.insert_unchecked(
            Property::AddReceivedSpfHeader,
            self.add_received_spf_header.into_value(),
        );
        map.insert_unchecked(
            Property::AddReturnPathHeader,
            self.add_return_path_header.into_value(),
        );
        map.insert_unchecked(Property::MaxMessages, self.max_messages.into_value());
        map.insert_unchecked(
            Property::MaxReceivedHeaders,
            self.max_received_headers.into_value(),
        );
        map.insert_unchecked(Property::MaxMessageSize, self.max_message_size.into_value());
        map.insert_unchecked(Property::Script, self.script.into_value());
        map.insert_unchecked(
            Property::EnableSpamFilter,
            self.enable_spam_filter.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageData {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AddAuthResultsHeader) => {
                self.add_auth_results_header.patch(pointer, value)
            }
            Some(Property::AddDateHeader) => self.add_date_header.patch(pointer, value),
            Some(Property::AddDeliveredToHeader) => {
                self.add_delivered_to_header.patch(pointer, value)
            }
            Some(Property::AddMessageIdHeader) => self.add_message_id_header.patch(pointer, value),
            Some(Property::AddReceivedHeader) => self.add_received_header.patch(pointer, value),
            Some(Property::AddReceivedSpfHeader) => {
                self.add_received_spf_header.patch(pointer, value)
            }
            Some(Property::AddReturnPathHeader) => {
                self.add_return_path_header.patch(pointer, value)
            }
            Some(Property::MaxMessages) => self.max_messages.patch(pointer, value),
            Some(Property::MaxReceivedHeaders) => self.max_received_headers.patch(pointer, value),
            Some(Property::MaxMessageSize) => self.max_message_size.patch(pointer, value),
            Some(Property::Script) => self.script.patch(pointer, value),
            Some(Property::EnableSpamFilter) => self.enable_spam_filter.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageEhlo {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageEhlo;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.reject_non_fqdn;
        value.validate(errors);
        let value = &self.require;
        value.validate(errors);
        let value = &self.script;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageEhlo {
    pub fn ctx_reject_non_fqdn(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.reject_non_fqdn,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            }),
            property: Property::RejectNonFqdn,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_require(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.require,
            default: Some(Expression {
                else_: "true".to_string(),
                ..Default::default()
            }),
            property: Property::Require,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_script(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.script,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Script,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_reject_non_fqdn(),
            self.ctx_require(),
            self.ctx_script(),
        ]
    }
}

impl Pickle for MtaStageEhlo {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.reject_non_fqdn.pickle(out);
        self.require.pickle(out);
        self.script.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.reject_non_fqdn = Pickle::unpickle(stream)?;
        this.require = Pickle::unpickle(stream)?;
        this.script = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageEhlo {
    fn default() -> Self {
        Self {
            reject_non_fqdn: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "true".to_string(),
                }]),
            },
            require: Expression {
                else_: "true".to_string(),
                ..Default::default()
            },
            script: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageEhlo {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::RejectNonFqdn, self.reject_non_fqdn.into_value());
        map.insert_unchecked(Property::Require, self.require.into_value());
        map.insert_unchecked(Property::Script, self.script.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageEhlo {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::RejectNonFqdn) => self.reject_non_fqdn.patch(pointer, value),
            Some(Property::Require) => self.require.patch(pointer, value),
            Some(Property::Script) => self.script.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageMail {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageMail;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.is_sender_allowed;
        value.validate(errors);
        let value = &self.rewrite;
        value.validate(errors);
        let value = &self.script;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageMail {
    pub fn ctx_is_sender_allowed(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.is_sender_allowed,
            default: Some(Expression {
                else_: "!is_empty(authenticated_as) || !key_exists('spam-block', sender_domain)"
                    .to_string(),
                match_: List::from_iter([]),
            }),
            property: Property::IsSenderAllowed,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_rewrite(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.rewrite,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Rewrite,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_script(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.script,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Script,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_is_sender_allowed(),
            self.ctx_rewrite(),
            self.ctx_script(),
        ]
    }
}

impl Pickle for MtaStageMail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.is_sender_allowed.pickle(out);
        self.rewrite.pickle(out);
        self.script.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.is_sender_allowed = Pickle::unpickle(stream)?;
        this.rewrite = Pickle::unpickle(stream)?;
        this.script = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageMail {
    fn default() -> Self {
        Self {
            is_sender_allowed: Expression {
                else_: "!is_empty(authenticated_as) || !key_exists('spam-block', sender_domain)"
                    .to_string(),
                match_: List::from_iter([]),
            },
            rewrite: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
            script: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageMail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(
            Property::IsSenderAllowed,
            self.is_sender_allowed.into_value(),
        );
        map.insert_unchecked(Property::Rewrite, self.rewrite.into_value());
        map.insert_unchecked(Property::Script, self.script.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageMail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IsSenderAllowed) => self.is_sender_allowed.patch(pointer, value),
            Some(Property::Rewrite) => self.rewrite.patch(pointer, value),
            Some(Property::Script) => self.script.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaStageRcpt {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaStageRcpt;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_failures;
        value.validate(errors);
        let value = &self.wait_on_fail;
        value.validate(errors);
        let value = &self.max_recipients;
        value.validate(errors);
        let value = &self.allow_relaying;
        value.validate(errors);
        let value = &self.rewrite;
        value.validate(errors);
        let value = &self.script;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl MtaStageRcpt {
    pub fn ctx_max_failures(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_failures,
            default: Some(Expression {
                else_: "5".to_string(),
                ..Default::default()
            }),
            property: Property::MaxFailures,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_wait_on_fail(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.wait_on_fail,
            default: Some(Expression {
                else_: "5s".to_string(),
                ..Default::default()
            }),
            property: Property::WaitOnFail,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_max_recipients(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_recipients,
            default: Some(Expression {
                else_: "100".to_string(),
                ..Default::default()
            }),
            property: Property::MaxRecipients,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_allow_relaying(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.allow_relaying,
            default: Some(Expression {
                else_: "!is_empty(authenticated_as)".to_string(),
                ..Default::default()
            }),
            property: Property::AllowRelaying,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_rewrite(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.rewrite,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Rewrite,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_script(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.script,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::Script,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_max_failures(),
            self.ctx_wait_on_fail(),
            self.ctx_max_recipients(),
            self.ctx_allow_relaying(),
            self.ctx_rewrite(),
            self.ctx_script(),
        ]
    }
}

impl Pickle for MtaStageRcpt {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_failures.pickle(out);
        self.wait_on_fail.pickle(out);
        self.max_recipients.pickle(out);
        self.allow_relaying.pickle(out);
        self.rewrite.pickle(out);
        self.script.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_failures = Pickle::unpickle(stream)?;
        this.wait_on_fail = Pickle::unpickle(stream)?;
        this.max_recipients = Pickle::unpickle(stream)?;
        this.allow_relaying = Pickle::unpickle(stream)?;
        this.rewrite = Pickle::unpickle(stream)?;
        this.script = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaStageRcpt {
    fn default() -> Self {
        Self {
            max_failures: Expression {
                else_: "5".to_string(),
                ..Default::default()
            },
            wait_on_fail: Expression {
                else_: "5s".to_string(),
                ..Default::default()
            },
            max_recipients: Expression {
                else_: "100".to_string(),
                ..Default::default()
            },
            allow_relaying: Expression {
                else_: "!is_empty(authenticated_as)".to_string(),
                ..Default::default()
            },
            rewrite: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
            script: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for MtaStageRcpt {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::MaxFailures, self.max_failures.into_value());
        map.insert_unchecked(Property::WaitOnFail, self.wait_on_fail.into_value());
        map.insert_unchecked(Property::MaxRecipients, self.max_recipients.into_value());
        map.insert_unchecked(Property::AllowRelaying, self.allow_relaying.into_value());
        map.insert_unchecked(Property::Rewrite, self.rewrite.into_value());
        map.insert_unchecked(Property::Script, self.script.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaStageRcpt {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxFailures) => self.max_failures.patch(pointer, value),
            Some(Property::WaitOnFail) => self.wait_on_fail.patch(pointer, value),
            Some(Property::MaxRecipients) => self.max_recipients.patch(pointer, value),
            Some(Property::AllowRelaying) => self.allow_relaying.patch(pointer, value),
            Some(Property::Rewrite) => self.rewrite.patch(pointer, value),
            Some(Property::Script) => self.script.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaSts {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaSts;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.mx_hosts;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MxHosts));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for MtaSts {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_age.pickle(out);
        self.mode.pickle(out);
        self.mx_hosts.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_age = Pickle::unpickle(stream)?;
        this.mode = Pickle::unpickle(stream)?;
        this.mx_hosts = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaSts {
    fn default() -> Self {
        Self {
            max_age: Duration::from_millis(604800000),
            mode: PolicyEnforcement::Testing,
            mx_hosts: Default::default(),
        }
    }
}

impl IntoValue for MtaSts {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::MaxAge, self.max_age.into_value());
        map.insert_unchecked(Property::Mode, self.mode.into_value());
        map.insert_unchecked(Property::MxHosts, self.mx_hosts.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaSts {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxAge) => self.max_age.patch(pointer, value),
            Some(Property::Mode) => self.mode.patch(pointer, value),
            Some(Property::MxHosts) => self
                .mx_hosts
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaTlsStrategy {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaTlsStrategy;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaTlsStrategy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.dane.pickle(out);
        self.description.pickle(out);
        self.mta_sts.pickle(out);
        self.start_tls.pickle(out);
        self.mta_sts_timeout.pickle(out);
        self.tls_timeout.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.dane = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.mta_sts = Pickle::unpickle(stream)?;
        this.start_tls = Pickle::unpickle(stream)?;
        this.mta_sts_timeout = Pickle::unpickle(stream)?;
        this.tls_timeout = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaTlsStrategy {
    fn default() -> Self {
        Self {
            name: Default::default(),
            allow_invalid_certs: false,
            dane: MtaRequiredOrOptional::Optional,
            description: Default::default(),
            mta_sts: MtaRequiredOrOptional::Optional,
            start_tls: MtaRequiredOrOptional::Optional,
            mta_sts_timeout: Duration::from_millis(300000),
            tls_timeout: Duration::from_millis(180000),
        }
    }
}

impl IntoValue for MtaTlsStrategy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::Dane, self.dane.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MtaSts, self.mta_sts.into_value());
        map.insert_unchecked(Property::StartTls, self.start_tls.into_value());
        map.insert_unchecked(Property::MtaStsTimeout, self.mta_sts_timeout.into_value());
        map.insert_unchecked(Property::TlsTimeout, self.tls_timeout.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaTlsStrategy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::Dane) => self.dane.patch(pointer, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::MtaSts) => self.mta_sts.patch(pointer, value),
            Some(Property::StartTls) => self.start_tls.patch(pointer, value),
            Some(Property::MtaStsTimeout) => self.mta_sts_timeout.patch(pointer, value),
            Some(Property::TlsTimeout) => self.tls_timeout.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for MtaVirtualQueue {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::MtaVirtualQueue;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if value.len() > 8 {
            errors.push(ValidationError::max_length(Property::Name, 8));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.threads_per_node;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ThreadsPerNode, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for MtaVirtualQueue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.threads_per_node.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.threads_per_node = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MtaVirtualQueue {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            threads_per_node: 25u64,
        }
    }
}

impl IntoValue for MtaVirtualQueue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::ThreadsPerNode, self.threads_per_node.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MtaVirtualQueue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Trim]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::ThreadsPerNode) => self.threads_per_node.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MySqlSettings {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.database;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Database));
        }
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.auth_secret;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for MySqlSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.host.pickle(out);
        self.port.pickle(out);
        self.database.pickle(out);
        self.auth_username.pickle(out);
        self.auth_secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.database = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MySqlSettings {
    fn default() -> Self {
        Self {
            host: Default::default(),
            port: 3306u64,
            database: "stalwart".to_string(),
            auth_username: Some("stalwart".to_string()),
            auth_secret: Default::default(),
        }
    }
}

impl IntoValue for MySqlSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Database, self.database.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MySqlSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Database) => self
                .database
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl MySqlStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.max_allowed_packet {
            if *value > 1073741824 {
                errors.push(ValidationError::max_value(
                    Property::MaxAllowedPacket,
                    1073741824,
                ));
            }
            if *value < 1024 {
                errors.push(ValidationError::min_value(Property::MaxAllowedPacket, 1024));
            }
        }
        if let Some(value) = &self.pool_max_connections {
            if *value > 8192 {
                errors.push(ValidationError::max_value(
                    Property::PoolMaxConnections,
                    8192,
                ));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1));
            }
        }
        if let Some(value) = &self.pool_min_connections {
            if *value > 8192 {
                errors.push(ValidationError::max_value(
                    Property::PoolMinConnections,
                    8192,
                ));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::PoolMinConnections, 1));
            }
        }
        let value = &self.read_replicas;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.database;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Database));
        }
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.auth_secret;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for MySqlStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.timeout.pickle(out);
        self.use_tls.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.max_allowed_packet.pickle(out);
        self.pool_max_connections.pickle(out);
        self.pool_min_connections.pickle(out);
        self.read_replicas.pickle(out);
        self.host.pickle(out);
        self.port.pickle(out);
        self.database.pickle(out);
        self.auth_username.pickle(out);
        self.auth_secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.timeout = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.max_allowed_packet = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        this.pool_min_connections = Pickle::unpickle(stream)?;
        this.read_replicas = Pickle::unpickle(stream)?;
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.database = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for MySqlStore {
    fn default() -> Self {
        Self {
            timeout: Some(Duration::from_millis(15000)),
            use_tls: false,
            allow_invalid_certs: false,
            max_allowed_packet: Default::default(),
            pool_max_connections: Some(10u64),
            pool_min_connections: Some(5u64),
            read_replicas: Default::default(),
            host: Default::default(),
            port: 3306u64,
            database: "stalwart".to_string(),
            auth_username: Some("stalwart".to_string()),
            auth_secret: Default::default(),
        }
    }
}

impl IntoValue for MySqlStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(
            Property::MaxAllowedPacket,
            self.max_allowed_packet.into_value(),
        );
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        map.insert_unchecked(
            Property::PoolMinConnections,
            self.pool_min_connections.into_value(),
        );
        map.insert_unchecked(Property::ReadReplicas, self.read_replicas.into_value());
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Database, self.database.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for MySqlStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::MaxAllowedPacket) => self.max_allowed_packet.patch(pointer, value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::PoolMinConnections) => self.pool_min_connections.patch(pointer, value),
            Some(Property::ReadReplicas) => self.read_replicas.patch(pointer, value),
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Database) => self
                .database
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl NatsCoordinator {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.addresses;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Addresses));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Addresses, 1));
        }
        let value = &self.capacity_client;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::CapacityClient, 1));
        }
        let value = &self.capacity_read_buffer;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::CapacityReadBuffer, 1));
        }
        let value = &self.capacity_subscription;
        if *value < 1 {
            errors.push(ValidationError::min_value(
                Property::CapacitySubscription,
                1,
            ));
        }
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.credentials;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for NatsCoordinator {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.addresses.pickle(out);
        self.max_reconnects.pickle(out);
        self.timeout_connection.pickle(out);
        self.timeout_request.pickle(out);
        self.ping_interval.pickle(out);
        self.capacity_client.pickle(out);
        self.capacity_read_buffer.pickle(out);
        self.capacity_subscription.pickle(out);
        self.no_echo.pickle(out);
        self.use_tls.pickle(out);
        self.auth_secret.pickle(out);
        self.auth_username.pickle(out);
        self.credentials.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.addresses = Pickle::unpickle(stream)?;
        this.max_reconnects = Pickle::unpickle(stream)?;
        this.timeout_connection = Pickle::unpickle(stream)?;
        this.timeout_request = Pickle::unpickle(stream)?;
        this.ping_interval = Pickle::unpickle(stream)?;
        this.capacity_client = Pickle::unpickle(stream)?;
        this.capacity_read_buffer = Pickle::unpickle(stream)?;
        this.capacity_subscription = Pickle::unpickle(stream)?;
        this.no_echo = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.credentials = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for NatsCoordinator {
    fn default() -> Self {
        Self {
            addresses: Map::new(vec!["127.0.0.1:4444".to_string()]),
            max_reconnects: Default::default(),
            timeout_connection: Duration::from_millis(5000),
            timeout_request: Duration::from_millis(10000),
            ping_interval: Duration::from_millis(60000),
            capacity_client: 2048u64,
            capacity_read_buffer: 65535u64,
            capacity_subscription: 65536u64,
            no_echo: true,
            use_tls: false,
            auth_secret: Default::default(),
            auth_username: Some("stalwart".to_string()),
            credentials: Default::default(),
        }
    }
}

impl IntoValue for NatsCoordinator {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::Addresses, self.addresses.into_value());
        map.insert_unchecked(Property::MaxReconnects, self.max_reconnects.into_value());
        map.insert_unchecked(
            Property::TimeoutConnection,
            self.timeout_connection.into_value(),
        );
        map.insert_unchecked(Property::TimeoutRequest, self.timeout_request.into_value());
        map.insert_unchecked(Property::PingInterval, self.ping_interval.into_value());
        map.insert_unchecked(Property::CapacityClient, self.capacity_client.into_value());
        map.insert_unchecked(
            Property::CapacityReadBuffer,
            self.capacity_read_buffer.into_value(),
        );
        map.insert_unchecked(
            Property::CapacitySubscription,
            self.capacity_subscription.into_value(),
        );
        map.insert_unchecked(Property::NoEcho, self.no_echo.into_value());
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::Credentials, self.credentials.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for NatsCoordinator {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Addresses) => self.addresses.patch(pointer, value),
            Some(Property::MaxReconnects) => self.max_reconnects.patch(pointer, value),
            Some(Property::TimeoutConnection) => self.timeout_connection.patch(pointer, value),
            Some(Property::TimeoutRequest) => self.timeout_request.patch(pointer, value),
            Some(Property::PingInterval) => self.ping_interval.patch(pointer, value),
            Some(Property::CapacityClient) => self.capacity_client.patch(pointer, value),
            Some(Property::CapacityReadBuffer) => self.capacity_read_buffer.patch(pointer, value),
            Some(Property::CapacitySubscription) => {
                self.capacity_subscription.patch(pointer, value)
            }
            Some(Property::NoEcho) => self.no_echo.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Credentials) => self.credentials.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for NetworkListener {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::NetworkListener;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.bind;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::Bind, value));
            }
        }
        if value.len() < 1 {
            errors.push(ValidationError::min_items(Property::Bind, 1));
        }
        let value = &self.override_proxy_trusted_networks;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(
                    Property::OverrideProxyTrustedNetworks,
                    value,
                ));
            }
        }
        if let Some(value) = &self.socket_backlog {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::SocketBacklog, 1));
            }
        }
        if let Some(value) = &self.socket_receive_buffer_size {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::SocketReceiveBufferSize,
                    1,
                ));
            }
        }
        if let Some(value) = &self.socket_send_buffer_size {
            if *value < 1 {
                errors.push(ValidationError::min_value(
                    Property::SocketSendBufferSize,
                    1,
                ));
            }
        }
        if let Some(value) = &self.socket_tos_v4 {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::SocketTosV4, 1));
            }
        }
        if let Some(value) = &self.socket_ttl {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::SocketTtl, 1));
            }
        }
        if let Some(value) = &self.max_connections {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxConnections, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for NetworkListener {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.bind.pickle(out);
        self.protocol.pickle(out);
        self.override_proxy_trusted_networks.pickle(out);
        self.socket_backlog.pickle(out);
        self.socket_no_delay.pickle(out);
        self.socket_receive_buffer_size.pickle(out);
        self.socket_reuse_address.pickle(out);
        self.socket_reuse_port.pickle(out);
        self.socket_send_buffer_size.pickle(out);
        self.socket_tos_v4.pickle(out);
        self.socket_ttl.pickle(out);
        self.use_tls.pickle(out);
        self.tls_disable_cipher_suites.pickle(out);
        self.tls_disable_protocols.pickle(out);
        self.tls_ignore_client_order.pickle(out);
        self.tls_implicit.pickle(out);
        self.tls_timeout.pickle(out);
        self.max_connections.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.bind = Pickle::unpickle(stream)?;
        this.protocol = Pickle::unpickle(stream)?;
        this.override_proxy_trusted_networks = Pickle::unpickle(stream)?;
        this.socket_backlog = Pickle::unpickle(stream)?;
        this.socket_no_delay = Pickle::unpickle(stream)?;
        this.socket_receive_buffer_size = Pickle::unpickle(stream)?;
        this.socket_reuse_address = Pickle::unpickle(stream)?;
        this.socket_reuse_port = Pickle::unpickle(stream)?;
        this.socket_send_buffer_size = Pickle::unpickle(stream)?;
        this.socket_tos_v4 = Pickle::unpickle(stream)?;
        this.socket_ttl = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.tls_disable_cipher_suites = Pickle::unpickle(stream)?;
        this.tls_disable_protocols = Pickle::unpickle(stream)?;
        this.tls_ignore_client_order = Pickle::unpickle(stream)?;
        this.tls_implicit = Pickle::unpickle(stream)?;
        this.tls_timeout = Pickle::unpickle(stream)?;
        this.max_connections = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for NetworkListener {
    fn default() -> Self {
        Self {
            name: Default::default(),
            bind: Default::default(),
            protocol: NetworkListenerProtocol::Smtp,
            override_proxy_trusted_networks: Default::default(),
            socket_backlog: Some(1024u64),
            socket_no_delay: true,
            socket_receive_buffer_size: Default::default(),
            socket_reuse_address: true,
            socket_reuse_port: true,
            socket_send_buffer_size: Default::default(),
            socket_tos_v4: Default::default(),
            socket_ttl: Default::default(),
            use_tls: true,
            tls_disable_cipher_suites: Default::default(),
            tls_disable_protocols: Default::default(),
            tls_ignore_client_order: true,
            tls_implicit: false,
            tls_timeout: Some(Duration::from_millis(60000)),
            max_connections: Some(8192u64),
        }
    }
}

impl IntoValue for NetworkListener {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(21);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Bind, self.bind.into_value());
        map.insert_unchecked(Property::Protocol, self.protocol.into_value());
        map.insert_unchecked(
            Property::OverrideProxyTrustedNetworks,
            self.override_proxy_trusted_networks.into_value(),
        );
        map.insert_unchecked(Property::SocketBacklog, self.socket_backlog.into_value());
        map.insert_unchecked(Property::SocketNoDelay, self.socket_no_delay.into_value());
        map.insert_unchecked(
            Property::SocketReceiveBufferSize,
            self.socket_receive_buffer_size.into_value(),
        );
        map.insert_unchecked(
            Property::SocketReuseAddress,
            self.socket_reuse_address.into_value(),
        );
        map.insert_unchecked(
            Property::SocketReusePort,
            self.socket_reuse_port.into_value(),
        );
        map.insert_unchecked(
            Property::SocketSendBufferSize,
            self.socket_send_buffer_size.into_value(),
        );
        map.insert_unchecked(Property::SocketTosV4, self.socket_tos_v4.into_value());
        map.insert_unchecked(Property::SocketTtl, self.socket_ttl.into_value());
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(
            Property::TlsDisableCipherSuites,
            self.tls_disable_cipher_suites.into_value(),
        );
        map.insert_unchecked(
            Property::TlsDisableProtocols,
            self.tls_disable_protocols.into_value(),
        );
        map.insert_unchecked(
            Property::TlsIgnoreClientOrder,
            self.tls_ignore_client_order.into_value(),
        );
        map.insert_unchecked(Property::TlsImplicit, self.tls_implicit.into_value());
        map.insert_unchecked(Property::TlsTimeout, self.tls_timeout.into_value());
        map.insert_unchecked(Property::MaxConnections, self.max_connections.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for NetworkListener {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer.assert_read_only()?, value),
            Some(Property::Bind) => self
                .bind
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Protocol) => self.protocol.patch(pointer, value),
            Some(Property::OverrideProxyTrustedNetworks) => self
                .override_proxy_trusted_networks
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SocketBacklog) => self.socket_backlog.patch(pointer, value),
            Some(Property::SocketNoDelay) => self.socket_no_delay.patch(pointer, value),
            Some(Property::SocketReceiveBufferSize) => {
                self.socket_receive_buffer_size.patch(pointer, value)
            }
            Some(Property::SocketReuseAddress) => self.socket_reuse_address.patch(pointer, value),
            Some(Property::SocketReusePort) => self.socket_reuse_port.patch(pointer, value),
            Some(Property::SocketSendBufferSize) => {
                self.socket_send_buffer_size.patch(pointer, value)
            }
            Some(Property::SocketTosV4) => self.socket_tos_v4.patch(pointer, value),
            Some(Property::SocketTtl) => self.socket_ttl.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::TlsDisableCipherSuites) => {
                self.tls_disable_cipher_suites.patch(pointer, value)
            }
            Some(Property::TlsDisableProtocols) => self.tls_disable_protocols.patch(pointer, value),
            Some(Property::TlsIgnoreClientOrder) => {
                self.tls_ignore_client_order.patch(pointer, value)
            }
            Some(Property::TlsImplicit) => self.tls_implicit.patch(pointer, value),
            Some(Property::TlsTimeout) => self.tls_timeout.patch(pointer, value),
            Some(Property::MaxConnections) => self.max_connections.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for OAuthClient {
    const FLAGS: u64 = OBJ_FILTER_TENANT | OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::OAuthClient;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.client_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ClientId));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.contacts;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Contacts));
            }
        }
        if let Some(value) = &self.secret {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Secret));
            }
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.redirect_uris;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::RedirectUris));
            }
        }
        if let Some(value) = &self.logo {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Logo));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::ClientId, &self.client_id);
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        for value in self.contacts.iter() {
            i.text(Property::Text, value);
        }
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for OAuthClient {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.client_id.pickle(out);
        self.description.pickle(out);
        self.contacts.pickle(out);
        self.secret.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
        self.member_tenant_id.pickle(out);
        self.redirect_uris.pickle(out);
        self.logo.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.client_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.contacts = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.redirect_uris = Pickle::unpickle(stream)?;
        this.logo = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for OAuthClient {
    fn default() -> Self {
        Self {
            client_id: Default::default(),
            description: Default::default(),
            contacts: Default::default(),
            secret: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
            member_tenant_id: Default::default(),
            redirect_uris: Default::default(),
            logo: Default::default(),
        }
    }
}

impl IntoValue for OAuthClient {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::ClientId, self.client_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Contacts, self.contacts.into_value());
        if self.secret.is_some() {
            map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        }
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::RedirectUris, self.redirect_uris.into_value());
        map.insert_unchecked(Property::Logo, self.logo.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for OAuthClient {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ClientId) => self
                .client_id
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Contacts) => self
                .contacts
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::RedirectUris) => self.redirect_uris.patch(pointer, value),
            Some(Property::Logo) => self.logo.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl OidcDirectory {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.issuer_url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::IssuerUrl));
        }
        if let Some(value) = &self.require_audience {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::RequireAudience));
            }
        }
        let value = &self.require_scopes;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::RequireScopes));
            }
        }
        let value = &self.claim_username;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ClaimUsername));
        }
        if let Some(value) = &self.username_domain {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::UsernameDomain));
            }
        }
        if let Some(value) = &self.claim_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ClaimName));
            }
        }
        if let Some(value) = &self.claim_groups {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ClaimGroups));
            }
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for OidcDirectory {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.issuer_url.pickle(out);
        self.require_audience.pickle(out);
        self.require_scopes.pickle(out);
        self.claim_username.pickle(out);
        self.username_domain.pickle(out);
        self.claim_name.pickle(out);
        self.claim_groups.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.issuer_url = Pickle::unpickle(stream)?;
        this.require_audience = Pickle::unpickle(stream)?;
        this.require_scopes = Pickle::unpickle(stream)?;
        this.claim_username = Pickle::unpickle(stream)?;
        this.username_domain = Pickle::unpickle(stream)?;
        this.claim_name = Pickle::unpickle(stream)?;
        this.claim_groups = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for OidcDirectory {
    fn default() -> Self {
        Self {
            description: Default::default(),
            issuer_url: Default::default(),
            require_audience: Some("stalwart".to_string()),
            require_scopes: Map::new(vec!["openid".to_string(), "email".to_string()]),
            claim_username: "preferred_username".to_string(),
            username_domain: Default::default(),
            claim_name: Some("name".to_string()),
            claim_groups: Default::default(),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for OidcDirectory {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::IssuerUrl, self.issuer_url.into_value());
        map.insert_unchecked(
            Property::RequireAudience,
            self.require_audience.into_value(),
        );
        map.insert_unchecked(Property::RequireScopes, self.require_scopes.into_value());
        map.insert_unchecked(Property::ClaimUsername, self.claim_username.into_value());
        map.insert_unchecked(Property::UsernameDomain, self.username_domain.into_value());
        map.insert_unchecked(Property::ClaimName, self.claim_name.into_value());
        map.insert_unchecked(Property::ClaimGroups, self.claim_groups.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for OidcDirectory {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::IssuerUrl) => self
                .issuer_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::RequireAudience) => self
                .require_audience
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::RequireScopes) => self
                .require_scopes
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClaimUsername) => self
                .claim_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::UsernameDomain) => self.username_domain.patch(pointer, value),
            Some(Property::ClaimName) => self
                .claim_name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ClaimGroups) => self.claim_groups.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for OidcProvider {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::OidcProvider;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.auth_code_max_attempts;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::AuthCodeMaxAttempts, 1));
        }
        if *value > 1000 {
            errors.push(ValidationError::max_value(
                Property::AuthCodeMaxAttempts,
                1000,
            ));
        }
        let value = &self.encryption_key;
        value.validate(errors);
        let value = &self.signature_key;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for OidcProvider {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.auth_code_max_attempts.pickle(out);
        self.anonymous_client_registration.pickle(out);
        self.require_client_registration.pickle(out);
        self.auth_code_expiry.pickle(out);
        self.refresh_token_expiry.pickle(out);
        self.refresh_token_renewal.pickle(out);
        self.access_token_expiry.pickle(out);
        self.user_code_expiry.pickle(out);
        self.id_token_expiry.pickle(out);
        self.encryption_key.pickle(out);
        self.signature_algorithm.pickle(out);
        self.signature_key.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.auth_code_max_attempts = Pickle::unpickle(stream)?;
        this.anonymous_client_registration = Pickle::unpickle(stream)?;
        this.require_client_registration = Pickle::unpickle(stream)?;
        this.auth_code_expiry = Pickle::unpickle(stream)?;
        this.refresh_token_expiry = Pickle::unpickle(stream)?;
        this.refresh_token_renewal = Pickle::unpickle(stream)?;
        this.access_token_expiry = Pickle::unpickle(stream)?;
        this.user_code_expiry = Pickle::unpickle(stream)?;
        this.id_token_expiry = Pickle::unpickle(stream)?;
        this.encryption_key = Pickle::unpickle(stream)?;
        this.signature_algorithm = Pickle::unpickle(stream)?;
        this.signature_key = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for OidcProvider {
    fn default() -> Self {
        Self {
            auth_code_max_attempts: 3u64,
            anonymous_client_registration: false,
            require_client_registration: false,
            auth_code_expiry: Duration::from_millis(600000),
            refresh_token_expiry: Duration::from_millis(2592000000),
            refresh_token_renewal: Duration::from_millis(345600000),
            access_token_expiry: Duration::from_millis(3600000),
            user_code_expiry: Duration::from_millis(1800000),
            id_token_expiry: Duration::from_millis(900000),
            encryption_key: Default::default(),
            signature_algorithm: JwtSignatureAlgorithm::Hs256,
            signature_key: Default::default(),
        }
    }
}

impl IntoValue for OidcProvider {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(
            Property::AuthCodeMaxAttempts,
            self.auth_code_max_attempts.into_value(),
        );
        map.insert_unchecked(
            Property::AnonymousClientRegistration,
            self.anonymous_client_registration.into_value(),
        );
        map.insert_unchecked(
            Property::RequireClientRegistration,
            self.require_client_registration.into_value(),
        );
        map.insert_unchecked(Property::AuthCodeExpiry, self.auth_code_expiry.into_value());
        map.insert_unchecked(
            Property::RefreshTokenExpiry,
            self.refresh_token_expiry.into_value(),
        );
        map.insert_unchecked(
            Property::RefreshTokenRenewal,
            self.refresh_token_renewal.into_value(),
        );
        map.insert_unchecked(
            Property::AccessTokenExpiry,
            self.access_token_expiry.into_value(),
        );
        map.insert_unchecked(Property::UserCodeExpiry, self.user_code_expiry.into_value());
        map.insert_unchecked(Property::IdTokenExpiry, self.id_token_expiry.into_value());
        map.insert_unchecked(Property::EncryptionKey, self.encryption_key.into_value());
        map.insert_unchecked(
            Property::SignatureAlgorithm,
            self.signature_algorithm.into_value(),
        );
        map.insert_unchecked(Property::SignatureKey, self.signature_key.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for OidcProvider {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AuthCodeMaxAttempts) => {
                self.auth_code_max_attempts.patch(pointer, value)
            }
            Some(Property::AnonymousClientRegistration) => {
                self.anonymous_client_registration.patch(pointer, value)
            }
            Some(Property::RequireClientRegistration) => {
                self.require_client_registration.patch(pointer, value)
            }
            Some(Property::AuthCodeExpiry) => self.auth_code_expiry.patch(pointer, value),
            Some(Property::RefreshTokenExpiry) => self.refresh_token_expiry.patch(pointer, value),
            Some(Property::RefreshTokenRenewal) => self.refresh_token_renewal.patch(pointer, value),
            Some(Property::AccessTokenExpiry) => self.access_token_expiry.patch(pointer, value),
            Some(Property::UserCodeExpiry) => self.user_code_expiry.patch(pointer, value),
            Some(Property::IdTokenExpiry) => self.id_token_expiry.patch(pointer, value),
            Some(Property::EncryptionKey) => self.encryption_key.patch(pointer, value),
            Some(Property::SignatureAlgorithm) => self.signature_algorithm.patch(pointer, value),
            Some(Property::SignatureKey) => self.signature_key.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl OtpAuth {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.otp_code {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OtpCode));
            }
        }
        if let Some(value) = &self.otp_url {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OtpUrl));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for OtpAuth {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.otp_code.pickle(out);
        self.otp_url.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.otp_code = Pickle::unpickle(stream)?;
        this.otp_url = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for OtpAuth {
    fn default() -> Self {
        Self {
            otp_code: Default::default(),
            otp_url: Default::default(),
        }
    }
}

impl IntoValue for OtpAuth {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        if self.otp_code.is_some() {
            map.insert_unchecked(Property::OtpCode, JmapValue::Str(MASKED_PASSWORD.into()));
        }
        if self.otp_url.is_some() {
            map.insert_unchecked(Property::OtpUrl, JmapValue::Str(MASKED_PASSWORD.into()));
        }
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for OtpAuth {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::OtpCode) => self.otp_code.patch(pointer, value),
            Some(Property::OtpUrl) => self.otp_url.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl PasswordCredential {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.credential_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CredentialId, value));
        }
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        if let Some(value) = &self.otp_auth {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OtpAuth));
            }
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        let value = &self.allowed_ips;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::AllowedIps, value));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for PasswordCredential {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.credential_id.pickle(out);
        self.secret.pickle(out);
        self.otp_auth.pickle(out);
        self.expires_at.pickle(out);
        self.allowed_ips.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.credential_id = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.otp_auth = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.allowed_ips = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PasswordCredential {
    fn default() -> Self {
        Self {
            credential_id: Default::default(),
            secret: Default::default(),
            otp_auth: Default::default(),
            expires_at: Default::default(),
            allowed_ips: Default::default(),
        }
    }
}

impl IntoValue for PasswordCredential {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::CredentialId, self.credential_id.into_value());
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        if self.otp_auth.is_some() {
            map.insert_unchecked(Property::OtpAuth, JmapValue::Str(MASKED_PASSWORD.into()));
        }
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::AllowedIps, self.allowed_ips.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PasswordCredential {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CredentialId) => pointer.assert_server_set(),
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::OtpAuth) => self.otp_auth.patch(pointer, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::AllowedIps) => self.allowed_ips.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Permissions {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Permissions::Inherit => true,
            Permissions::Merge(inner) => inner.validate(errors),
            Permissions::Replace(inner) => inner.validate(errors),
        }
    }
}

impl Default for Permissions {
    fn default() -> Self {
        Permissions::Inherit
    }
}

impl Pickle for Permissions {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Permissions::Inherit => {
                0u16.pickle(out);
            }
            Permissions::Merge(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Permissions::Replace(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(Permissions::Inherit),
            1 => Pickle::unpickle(stream).map(Permissions::Merge),
            2 => Pickle::unpickle(stream).map(Permissions::Replace),
            _ => None,
        }
    }
}

impl IntoValue for Permissions {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Permissions::Inherit => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Inherit".into()));
                JmapValue::Object(obj)
            }
            Permissions::Merge(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Merge".into()));
                obj
            }
            Permissions::Replace(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Replace".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Permissions {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                PermissionsType::Inherit => *self = Permissions::Inherit,
                PermissionsType::Merge => *self = Permissions::Merge(Default::default()),
                PermissionsType::Replace => *self = Permissions::Replace(Default::default()),
            }
        }
        match self {
            Permissions::Inherit => pointer.assert_eof(),
            Permissions::Merge(inner) => inner.patch(pointer, value),
            Permissions::Replace(inner) => inner.patch(pointer, value),
        }
    }
}

impl Permissions {
    pub fn object_type(&self) -> PermissionsType {
        match self {
            Permissions::Inherit => PermissionsType::Inherit,
            Permissions::Merge(_) => PermissionsType::Merge,
            Permissions::Replace(_) => PermissionsType::Replace,
        }
    }
}

impl PermissionsList {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for PermissionsList {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enabled_permissions.pickle(out);
        self.disabled_permissions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enabled_permissions = Pickle::unpickle(stream)?;
        this.disabled_permissions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PermissionsList {
    fn default() -> Self {
        Self {
            enabled_permissions: Default::default(),
            disabled_permissions: Default::default(),
        }
    }
}

impl IntoValue for PermissionsList {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(
            Property::EnabledPermissions,
            self.enabled_permissions.into_value(),
        );
        map.insert_unchecked(
            Property::DisabledPermissions,
            self.disabled_permissions.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PermissionsList {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::EnabledPermissions) => self.enabled_permissions.patch(pointer, value),
            Some(Property::DisabledPermissions) => self.disabled_permissions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl PostgreSqlSettings {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.database;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Database));
        }
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.options {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Options));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for PostgreSqlSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.host.pickle(out);
        self.port.pickle(out);
        self.database.pickle(out);
        self.auth_username.pickle(out);
        self.auth_secret.pickle(out);
        self.options.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.database = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        this.options = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PostgreSqlSettings {
    fn default() -> Self {
        Self {
            host: Default::default(),
            port: 5432u64,
            database: "stalwart".to_string(),
            auth_username: Some("stalwart".to_string()),
            auth_secret: Default::default(),
            options: Default::default(),
        }
    }
}

impl IntoValue for PostgreSqlSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Database, self.database.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::Options, self.options.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PostgreSqlSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Database) => self
                .database
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::Options) => self
                .options
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl PostgreSqlStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.pool_max_connections {
            if *value > 8192 {
                errors.push(ValidationError::max_value(
                    Property::PoolMaxConnections,
                    8192,
                ));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1));
            }
        }
        let value = &self.read_replicas;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Port, 1));
        }
        let value = &self.database;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Database));
        }
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.options {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Options));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for PostgreSqlStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.timeout.pickle(out);
        self.use_tls.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.pool_max_connections.pickle(out);
        self.pool_recycling_method.pickle(out);
        self.read_replicas.pickle(out);
        self.host.pickle(out);
        self.port.pickle(out);
        self.database.pickle(out);
        self.auth_username.pickle(out);
        self.auth_secret.pickle(out);
        self.options.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.timeout = Pickle::unpickle(stream)?;
        this.use_tls = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        this.pool_recycling_method = Pickle::unpickle(stream)?;
        this.read_replicas = Pickle::unpickle(stream)?;
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.database = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        this.options = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PostgreSqlStore {
    fn default() -> Self {
        Self {
            timeout: Some(Duration::from_millis(15000)),
            use_tls: false,
            allow_invalid_certs: false,
            pool_max_connections: Some(10u64),
            pool_recycling_method: PostgreSqlRecyclingMethod::Fast,
            read_replicas: Default::default(),
            host: Default::default(),
            port: 5432u64,
            database: "stalwart".to_string(),
            auth_username: Some("stalwart".to_string()),
            auth_secret: Default::default(),
            options: Default::default(),
        }
    }
}

impl IntoValue for PostgreSqlStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::UseTls, self.use_tls.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        map.insert_unchecked(
            Property::PoolRecyclingMethod,
            self.pool_recycling_method.into_value(),
        );
        map.insert_unchecked(Property::ReadReplicas, self.read_replicas.into_value());
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Database, self.database.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::Options, self.options.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PostgreSqlStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::UseTls) => self.use_tls.patch(pointer, value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::PoolRecyclingMethod) => self.pool_recycling_method.patch(pointer, value),
            Some(Property::ReadReplicas) => self.read_replicas.patch(pointer, value),
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Database) => self
                .database
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::Options) => self
                .options
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for PublicKey {
    const FLAGS: u64 = OBJ_FILTER_ACCOUNT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::PublicKey;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.key;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Key));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        let value = &self.email_addresses;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EmailAddresses));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.search(Property::AccountId, &self.account_id);
    }
}

impl Pickle for PublicKey {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.account_id.pickle(out);
        self.key.pickle(out);
        self.description.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
        self.email_addresses.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.account_id = Pickle::unpickle(stream)?;
        this.key = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.email_addresses = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PublicKey {
    fn default() -> Self {
        Self {
            account_id: Default::default(),
            key: Default::default(),
            description: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
            email_addresses: Default::default(),
        }
    }
}

impl IntoValue for PublicKey {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::EmailAddresses, self.email_addresses.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PublicKey {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::Key) => self
                .key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::EmailAddresses) => self
                .email_addresses
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl PublicText {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            PublicText::Text(inner) => inner.validate(errors),
            PublicText::EnvironmentVariable(inner) => inner.validate(errors),
            PublicText::File(inner) => inner.validate(errors),
        }
    }
}

impl Default for PublicText {
    fn default() -> Self {
        PublicText::Text(Default::default())
    }
}

impl Pickle for PublicText {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            PublicText::Text(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            PublicText::EnvironmentVariable(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            PublicText::File(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(PublicText::Text),
            1 => Pickle::unpickle(stream).map(PublicText::EnvironmentVariable),
            2 => Pickle::unpickle(stream).map(PublicText::File),
            _ => None,
        }
    }
}

impl IntoValue for PublicText {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            PublicText::Text(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Text".into()));
                obj
            }
            PublicText::EnvironmentVariable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnvironmentVariable".into()));
                obj
            }
            PublicText::File(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("File".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for PublicText {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                PublicTextType::Text => *self = PublicText::Text(Default::default()),
                PublicTextType::EnvironmentVariable => {
                    *self = PublicText::EnvironmentVariable(Default::default())
                }
                PublicTextType::File => *self = PublicText::File(Default::default()),
            }
        }
        match self {
            PublicText::Text(inner) => inner.patch(pointer, value),
            PublicText::EnvironmentVariable(inner) => inner.patch(pointer, value),
            PublicText::File(inner) => inner.patch(pointer, value),
        }
    }
}

impl PublicText {
    pub fn object_type(&self) -> PublicTextType {
        match self {
            PublicText::Text(_) => PublicTextType::Text,
            PublicText::EnvironmentVariable(_) => PublicTextType::EnvironmentVariable,
            PublicText::File(_) => PublicTextType::File,
        }
    }
}

impl PublicTextValue {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Value));
        }
        errors.len() == neb
    }
}

impl Pickle for PublicTextValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for PublicTextValue {
    fn default() -> Self {
        Self {
            value: Default::default(),
        }
    }
}

impl IntoValue for PublicTextValue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for PublicTextValue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl QueueExpiry {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            QueueExpiry::Ttl(inner) => inner.validate(errors),
            QueueExpiry::Attempts(inner) => inner.validate(errors),
        }
    }
}

impl Default for QueueExpiry {
    fn default() -> Self {
        QueueExpiry::Ttl(Default::default())
    }
}

impl Pickle for QueueExpiry {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            QueueExpiry::Ttl(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            QueueExpiry::Attempts(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(QueueExpiry::Ttl),
            1 => Pickle::unpickle(stream).map(QueueExpiry::Attempts),
            _ => None,
        }
    }
}

impl IntoValue for QueueExpiry {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            QueueExpiry::Ttl(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ttl".into()));
                obj
            }
            QueueExpiry::Attempts(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Attempts".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for QueueExpiry {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                QueueExpiryType::Ttl => *self = QueueExpiry::Ttl(Default::default()),
                QueueExpiryType::Attempts => *self = QueueExpiry::Attempts(Default::default()),
            }
        }
        match self {
            QueueExpiry::Ttl(inner) => inner.patch(pointer, value),
            QueueExpiry::Attempts(inner) => inner.patch(pointer, value),
        }
    }
}

impl QueueExpiry {
    pub fn object_type(&self) -> QueueExpiryType {
        match self {
            QueueExpiry::Ttl(_) => QueueExpiryType::Ttl,
            QueueExpiry::Attempts(_) => QueueExpiryType::Attempts,
        }
    }
}

impl QueueExpiryAttempts {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for QueueExpiryAttempts {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.expires_attempts.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.expires_attempts = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for QueueExpiryAttempts {
    fn default() -> Self {
        Self {
            expires_attempts: 0u64,
        }
    }
}

impl IntoValue for QueueExpiryAttempts {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(
            Property::ExpiresAttempts,
            self.expires_attempts.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for QueueExpiryAttempts {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ExpiresAttempts) => self.expires_attempts.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl QueueExpiryTtl {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.expires_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ExpiresAt, value));
        }
        errors.len() == neb
    }
}

impl Pickle for QueueExpiryTtl {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.expires_at.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.expires_at = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for QueueExpiryTtl {
    fn default() -> Self {
        Self {
            expires_at: Default::default(),
        }
    }
}

impl IntoValue for QueueExpiryTtl {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for QueueExpiryTtl {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for QueuedMessage {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::QueuedMessage;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.next_retry {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::NextRetry, value));
            }
        }
        if let Some(value) = &self.next_notify {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::NextNotify, value));
            }
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        let value = &self.return_path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ReturnPath));
        }
        let value = &self.recipients;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.received_from_ip;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ReceivedFromIp, value));
        }
        let value = &self.received_via_port;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::ReceivedViaPort, 1));
        }
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::ReceivedViaPort, 65535));
        }
        if let Some(value) = &self.env_id {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EnvId));
            }
        }
        let value = &self.priority;
        if *value < (-100) {
            errors.push(ValidationError::min_value(Property::Priority, -100));
        }
        if *value > (100) {
            errors.push(ValidationError::max_value(Property::Priority, 100));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for QueuedMessage {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.created_at.pickle(out);
        self.next_retry.pickle(out);
        self.next_notify.pickle(out);
        self.blob_id.pickle(out);
        self.return_path.pickle(out);
        self.recipients.pickle(out);
        self.received_from_ip.pickle(out);
        self.received_via_port.pickle(out);
        self.flags.pickle(out);
        self.env_id.pickle(out);
        self.priority.pickle(out);
        self.size.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.created_at = Pickle::unpickle(stream)?;
        this.next_retry = Pickle::unpickle(stream)?;
        this.next_notify = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        this.return_path = Pickle::unpickle(stream)?;
        this.recipients = Pickle::unpickle(stream)?;
        this.received_from_ip = Pickle::unpickle(stream)?;
        this.received_via_port = Pickle::unpickle(stream)?;
        this.flags = Pickle::unpickle(stream)?;
        this.env_id = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        this.size = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for QueuedMessage {
    fn default() -> Self {
        Self {
            created_at: Default::default(),
            next_retry: Default::default(),
            next_notify: Default::default(),
            blob_id: Default::default(),
            return_path: Default::default(),
            recipients: Default::default(),
            received_from_ip: Default::default(),
            received_via_port: 25u64,
            flags: Default::default(),
            env_id: Default::default(),
            priority: 0i64,
            size: 0u64,
        }
    }
}

impl IntoValue for QueuedMessage {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::NextRetry, self.next_retry.into_value());
        map.insert_unchecked(Property::NextNotify, self.next_notify.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        map.insert_unchecked(Property::ReturnPath, self.return_path.into_value());
        map.insert_unchecked(Property::Recipients, self.recipients.into_value());
        map.insert_unchecked(Property::ReceivedFromIp, self.received_from_ip.into_value());
        map.insert_unchecked(
            Property::ReceivedViaPort,
            self.received_via_port.into_value(),
        );
        map.insert_unchecked(Property::Flags, self.flags.into_value());
        map.insert_unchecked(Property::EnvId, self.env_id.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        map.insert_unchecked(Property::Size, self.size.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for QueuedMessage {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::NextRetry) => self.next_retry.patch(pointer, value),
            Some(Property::NextNotify) => pointer.assert_server_set(),
            Some(Property::BlobId) => pointer.assert_server_set(),
            Some(Property::ReturnPath) => pointer.assert_server_set(),
            Some(Property::Recipients) => self.recipients.patch(pointer, value),
            Some(Property::ReceivedFromIp) => pointer.assert_server_set(),
            Some(Property::ReceivedViaPort) => pointer.assert_server_set(),
            Some(Property::Flags) => pointer.assert_server_set(),
            Some(Property::EnvId) => self.env_id.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Size) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl QueuedRecipient {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.retry_due;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::RetryDue, value));
        }
        let value = &self.notify_due;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::NotifyDue, value));
        }
        let value = &self.expires;
        value.validate(errors);
        let value = &self.queue_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::QueueName));
        }
        if value.len() > 8 {
            errors.push(ValidationError::max_length(Property::QueueName, 8));
        }
        let value = &self.status;
        value.validate(errors);
        if let Some(value) = &self.orcpt {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Orcpt));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for QueuedRecipient {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.retry_count.pickle(out);
        self.retry_due.pickle(out);
        self.notify_count.pickle(out);
        self.notify_due.pickle(out);
        self.expires.pickle(out);
        self.queue_name.pickle(out);
        self.status.pickle(out);
        self.flags.pickle(out);
        self.orcpt.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.retry_count = Pickle::unpickle(stream)?;
        this.retry_due = Pickle::unpickle(stream)?;
        this.notify_count = Pickle::unpickle(stream)?;
        this.notify_due = Pickle::unpickle(stream)?;
        this.expires = Pickle::unpickle(stream)?;
        this.queue_name = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        this.flags = Pickle::unpickle(stream)?;
        this.orcpt = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for QueuedRecipient {
    fn default() -> Self {
        Self {
            retry_count: 0u64,
            retry_due: Default::default(),
            notify_count: 0u64,
            notify_due: Default::default(),
            expires: Default::default(),
            queue_name: Default::default(),
            status: Default::default(),
            flags: Default::default(),
            orcpt: Default::default(),
        }
    }
}

impl IntoValue for QueuedRecipient {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::RetryCount, self.retry_count.into_value());
        map.insert_unchecked(Property::RetryDue, self.retry_due.into_value());
        map.insert_unchecked(Property::NotifyCount, self.notify_count.into_value());
        map.insert_unchecked(Property::NotifyDue, self.notify_due.into_value());
        map.insert_unchecked(Property::Expires, self.expires.into_value());
        map.insert_unchecked(Property::QueueName, self.queue_name.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        map.insert_unchecked(Property::Flags, self.flags.into_value());
        map.insert_unchecked(Property::Orcpt, self.orcpt.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for QueuedRecipient {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::RetryCount) => self.retry_count.patch(pointer, value),
            Some(Property::RetryDue) => self.retry_due.patch(pointer, value),
            Some(Property::NotifyCount) => self.notify_count.patch(pointer, value),
            Some(Property::NotifyDue) => self.notify_due.patch(pointer, value),
            Some(Property::Expires) => self.expires.patch(pointer, value),
            Some(Property::QueueName) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Flags) => pointer.assert_server_set(),
            Some(Property::Orcpt) => self.orcpt.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Rate {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.count;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::Count, 1));
        }
        if *value > 1000000 {
            errors.push(ValidationError::max_value(Property::Count, 1000000));
        }
        let value = &self.period;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Period, value));
        }
        if *value < Duration::from_millis(1) {
            errors.push(ValidationError::min_value(Property::Period, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for Rate {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.count.pickle(out);
        self.period.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.count = Pickle::unpickle(stream)?;
        this.period = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Rate {
    fn default() -> Self {
        Self {
            count: 0u64,
            period: Duration::from_millis(0),
        }
    }
}

impl IntoValue for Rate {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Count, self.count.into_value());
        map.insert_unchecked(Property::Period, self.period.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Rate {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Count) => self.count.patch(pointer, value),
            Some(Property::Period) => self.period.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl RecipientStatus {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            RecipientStatus::Scheduled => true,
            RecipientStatus::Completed(inner) => inner.validate(errors),
            RecipientStatus::TemporaryFailure(inner) => inner.validate(errors),
            RecipientStatus::PermanentFailure(inner) => inner.validate(errors),
        }
    }
}

impl Default for RecipientStatus {
    fn default() -> Self {
        RecipientStatus::Scheduled
    }
}

impl Pickle for RecipientStatus {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            RecipientStatus::Scheduled => {
                0u16.pickle(out);
            }
            RecipientStatus::Completed(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            RecipientStatus::TemporaryFailure(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            RecipientStatus::PermanentFailure(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(RecipientStatus::Scheduled),
            1 => Pickle::unpickle(stream).map(RecipientStatus::Completed),
            2 => Pickle::unpickle(stream).map(RecipientStatus::TemporaryFailure),
            3 => Pickle::unpickle(stream).map(RecipientStatus::PermanentFailure),
            _ => None,
        }
    }
}

impl IntoValue for RecipientStatus {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            RecipientStatus::Scheduled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Scheduled".into()));
                JmapValue::Object(obj)
            }
            RecipientStatus::Completed(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Completed".into()));
                obj
            }
            RecipientStatus::TemporaryFailure(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TemporaryFailure".into()));
                obj
            }
            RecipientStatus::PermanentFailure(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PermanentFailure".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for RecipientStatus {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                RecipientStatusType::Scheduled => *self = RecipientStatus::Scheduled,
                RecipientStatusType::Completed => {
                    *self = RecipientStatus::Completed(Default::default())
                }
                RecipientStatusType::TemporaryFailure => {
                    *self = RecipientStatus::TemporaryFailure(Default::default())
                }
                RecipientStatusType::PermanentFailure => {
                    *self = RecipientStatus::PermanentFailure(Default::default())
                }
            }
        }
        match self {
            RecipientStatus::Scheduled => pointer.assert_eof(),
            RecipientStatus::Completed(inner) => inner.patch(pointer, value),
            RecipientStatus::TemporaryFailure(inner) => inner.patch(pointer, value),
            RecipientStatus::PermanentFailure(inner) => inner.patch(pointer, value),
        }
    }
}

impl RecipientStatus {
    pub fn object_type(&self) -> RecipientStatusType {
        match self {
            RecipientStatus::Scheduled => RecipientStatusType::Scheduled,
            RecipientStatus::Completed(_) => RecipientStatusType::Completed,
            RecipientStatus::TemporaryFailure(_) => RecipientStatusType::TemporaryFailure,
            RecipientStatus::PermanentFailure(_) => RecipientStatusType::PermanentFailure,
        }
    }
}

impl RedisClusterStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.urls;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Urls));
            }
        }
        if let Some(value) = &self.auth_username {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthUsername));
            }
        }
        let value = &self.auth_secret;
        value.validate(errors);
        if let Some(value) = &self.max_retry_wait {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::MaxRetryWait, value));
            }
            if *value > Duration::from_millis(1024) {
                errors.push(ValidationError::max_value(Property::MaxRetryWait, 1024));
            }
            if *value < Duration::from_millis(1) {
                errors.push(ValidationError::min_value(Property::MaxRetryWait, 1));
            }
        }
        if let Some(value) = &self.min_retry_wait {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::MinRetryWait, value));
            }
            if *value > Duration::from_millis(1024) {
                errors.push(ValidationError::max_value(Property::MinRetryWait, 1024));
            }
            if *value < Duration::from_millis(1) {
                errors.push(ValidationError::min_value(Property::MinRetryWait, 1));
            }
        }
        if let Some(value) = &self.max_retries {
            if *value > 1024 {
                errors.push(ValidationError::max_value(Property::MaxRetries, 1024));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxRetries, 1));
            }
        }
        let value = &self.pool_max_connections;
        if *value > 8192 {
            errors.push(ValidationError::max_value(
                Property::PoolMaxConnections,
                8192,
            ));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for RedisClusterStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.urls.pickle(out);
        self.timeout.pickle(out);
        self.auth_username.pickle(out);
        self.auth_secret.pickle(out);
        self.max_retry_wait.pickle(out);
        self.min_retry_wait.pickle(out);
        self.max_retries.pickle(out);
        self.read_from_replicas.pickle(out);
        self.protocol_version.pickle(out);
        self.pool_max_connections.pickle(out);
        self.pool_timeout_create.pickle(out);
        self.pool_timeout_wait.pickle(out);
        self.pool_timeout_recycle.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.urls = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.auth_username = Pickle::unpickle(stream)?;
        this.auth_secret = Pickle::unpickle(stream)?;
        this.max_retry_wait = Pickle::unpickle(stream)?;
        this.min_retry_wait = Pickle::unpickle(stream)?;
        this.max_retries = Pickle::unpickle(stream)?;
        this.read_from_replicas = Pickle::unpickle(stream)?;
        this.protocol_version = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        this.pool_timeout_create = Pickle::unpickle(stream)?;
        this.pool_timeout_wait = Pickle::unpickle(stream)?;
        this.pool_timeout_recycle = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for RedisClusterStore {
    fn default() -> Self {
        Self {
            urls: Map::new(vec!["redis://127.0.0.1".to_string()]),
            timeout: Duration::from_millis(10000),
            auth_username: Some("stalwart".to_string()),
            auth_secret: Default::default(),
            max_retry_wait: Default::default(),
            min_retry_wait: Default::default(),
            max_retries: Default::default(),
            read_from_replicas: true,
            protocol_version: RedisProtocol::Resp2,
            pool_max_connections: 10u64,
            pool_timeout_create: Some(Duration::from_millis(30000)),
            pool_timeout_wait: Some(Duration::from_millis(30000)),
            pool_timeout_recycle: Some(Duration::from_millis(30000)),
        }
    }
}

impl IntoValue for RedisClusterStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(Property::Urls, self.urls.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::AuthUsername, self.auth_username.into_value());
        map.insert_unchecked(Property::AuthSecret, self.auth_secret.into_value());
        map.insert_unchecked(Property::MaxRetryWait, self.max_retry_wait.into_value());
        map.insert_unchecked(Property::MinRetryWait, self.min_retry_wait.into_value());
        map.insert_unchecked(Property::MaxRetries, self.max_retries.into_value());
        map.insert_unchecked(
            Property::ReadFromReplicas,
            self.read_from_replicas.into_value(),
        );
        map.insert_unchecked(
            Property::ProtocolVersion,
            self.protocol_version.into_value(),
        );
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutCreate,
            self.pool_timeout_create.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutWait,
            self.pool_timeout_wait.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutRecycle,
            self.pool_timeout_recycle.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for RedisClusterStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Urls) => self
                .urls
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AuthUsername) => self
                .auth_username
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AuthSecret) => self.auth_secret.patch(pointer, value),
            Some(Property::MaxRetryWait) => self.max_retry_wait.patch(pointer, value),
            Some(Property::MinRetryWait) => self.min_retry_wait.patch(pointer, value),
            Some(Property::MaxRetries) => self.max_retries.patch(pointer, value),
            Some(Property::ReadFromReplicas) => self.read_from_replicas.patch(pointer, value),
            Some(Property::ProtocolVersion) => self.protocol_version.patch(pointer, value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::PoolTimeoutCreate) => self.pool_timeout_create.patch(pointer, value),
            Some(Property::PoolTimeoutWait) => self.pool_timeout_wait.patch(pointer, value),
            Some(Property::PoolTimeoutRecycle) => self.pool_timeout_recycle.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl RedisStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.pool_max_connections;
        if *value > 8192 {
            errors.push(ValidationError::max_value(
                Property::PoolMaxConnections,
                8192,
            ));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for RedisStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.url.pickle(out);
        self.timeout.pickle(out);
        self.pool_max_connections.pickle(out);
        self.pool_timeout_create.pickle(out);
        self.pool_timeout_wait.pickle(out);
        self.pool_timeout_recycle.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.url = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        this.pool_timeout_create = Pickle::unpickle(stream)?;
        this.pool_timeout_wait = Pickle::unpickle(stream)?;
        this.pool_timeout_recycle = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for RedisStore {
    fn default() -> Self {
        Self {
            url: "redis://127.0.0.1".to_string(),
            timeout: Duration::from_millis(10000),
            pool_max_connections: 10u64,
            pool_timeout_create: Some(Duration::from_millis(30000)),
            pool_timeout_wait: Some(Duration::from_millis(30000)),
            pool_timeout_recycle: Some(Duration::from_millis(30000)),
        }
    }
}

impl IntoValue for RedisStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutCreate,
            self.pool_timeout_create.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutWait,
            self.pool_timeout_wait.into_value(),
        );
        map.insert_unchecked(
            Property::PoolTimeoutRecycle,
            self.pool_timeout_recycle.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for RedisStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::PoolTimeoutCreate) => self.pool_timeout_create.patch(pointer, value),
            Some(Property::PoolTimeoutWait) => self.pool_timeout_wait.patch(pointer, value),
            Some(Property::PoolTimeoutRecycle) => self.pool_timeout_recycle.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for ReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::ReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.inbound_report_addresses;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::InboundReportAddresses));
            }
        }
        if let Some(value) = &self.outbound_report_domain {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OutboundReportDomain));
            }
        }
        let value = &self.outbound_report_submitter;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl ReportSettings {
    pub fn ctx_outbound_report_submitter(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.outbound_report_submitter,
            default: Some(Expression {
                else_: "system('hostname')".to_string(),
                ..Default::default()
            }),
            property: Property::OutboundReportSubmitter,
            allowed_variables: MTA_RCPT_DOMAIN_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_outbound_report_submitter()]
    }
}

impl Pickle for ReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.inbound_report_addresses.pickle(out);
        self.inbound_report_forwarding.pickle(out);
        self.outbound_report_domain.pickle(out);
        self.outbound_report_submitter.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.inbound_report_addresses = Pickle::unpickle(stream)?;
        this.inbound_report_forwarding = Pickle::unpickle(stream)?;
        this.outbound_report_domain = Pickle::unpickle(stream)?;
        this.outbound_report_submitter = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ReportSettings {
    fn default() -> Self {
        Self {
            inbound_report_addresses: Map::new(vec!["postmaster@*".to_string()]),
            inbound_report_forwarding: true,
            outbound_report_domain: Default::default(),
            outbound_report_submitter: Expression {
                else_: "system('hostname')".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for ReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(
            Property::InboundReportAddresses,
            self.inbound_report_addresses.into_value(),
        );
        map.insert_unchecked(
            Property::InboundReportForwarding,
            self.inbound_report_forwarding.into_value(),
        );
        map.insert_unchecked(
            Property::OutboundReportDomain,
            self.outbound_report_domain.into_value(),
        );
        map.insert_unchecked(
            Property::OutboundReportSubmitter,
            self.outbound_report_submitter.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::InboundReportAddresses) => self
                .inbound_report_addresses
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::InboundReportForwarding) => {
                self.inbound_report_forwarding.patch(pointer, value)
            }
            Some(Property::OutboundReportDomain) => self
                .outbound_report_domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::OutboundReportSubmitter) => {
                self.outbound_report_submitter.patch(pointer, value)
            }
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl RocksDbStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Path));
        }
        let value = &self.blob_size;
        if *value > 1048576 {
            errors.push(ValidationError::max_value(Property::BlobSize, 1048576));
        }
        if *value < 1024 {
            errors.push(ValidationError::min_value(Property::BlobSize, 1024));
        }
        let value = &self.buffer_size;
        if *value > 1073741824 {
            errors.push(ValidationError::max_value(Property::BufferSize, 1073741824));
        }
        if *value < 8192 {
            errors.push(ValidationError::min_value(Property::BufferSize, 8192));
        }
        if let Some(value) = &self.pool_workers {
            if *value > 64 {
                errors.push(ValidationError::max_value(Property::PoolWorkers, 64));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::PoolWorkers, 1));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for RocksDbStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.path.pickle(out);
        self.blob_size.pickle(out);
        self.buffer_size.pickle(out);
        self.pool_workers.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.path = Pickle::unpickle(stream)?;
        this.blob_size = Pickle::unpickle(stream)?;
        this.buffer_size = Pickle::unpickle(stream)?;
        this.pool_workers = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for RocksDbStore {
    fn default() -> Self {
        Self {
            path: Default::default(),
            blob_size: 16834u64,
            buffer_size: 134217728u64,
            pool_workers: Default::default(),
        }
    }
}

impl IntoValue for RocksDbStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Path, self.path.into_value());
        map.insert_unchecked(Property::BlobSize, self.blob_size.into_value());
        map.insert_unchecked(Property::BufferSize, self.buffer_size.into_value());
        map.insert_unchecked(Property::PoolWorkers, self.pool_workers.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for RocksDbStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Path) => self
                .path
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::BlobSize) => self.blob_size.patch(pointer, value),
            Some(Property::BufferSize) => self.buffer_size.patch(pointer, value),
            Some(Property::PoolWorkers) => self.pool_workers.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Role {
    const FLAGS: u64 = OBJ_FILTER_TENANT | OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Role;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.role_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::RoleIds));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.text(Property::Description, &self.description);
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
        for id in self.role_ids.iter() {
            i.foreign_key(ObjectType::Role, Some(*id), None);
        }
    }
}

impl Pickle for Role {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.member_tenant_id.pickle(out);
        self.role_ids.pickle(out);
        self.enabled_permissions.pickle(out);
        self.disabled_permissions.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.role_ids = Pickle::unpickle(stream)?;
        this.enabled_permissions = Pickle::unpickle(stream)?;
        this.disabled_permissions = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Role {
    fn default() -> Self {
        Self {
            description: Default::default(),
            member_tenant_id: Default::default(),
            role_ids: Default::default(),
            enabled_permissions: Default::default(),
            disabled_permissions: Default::default(),
        }
    }
}

impl IntoValue for Role {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::RoleIds, self.role_ids.into_value());
        map.insert_unchecked(
            Property::EnabledPermissions,
            self.enabled_permissions.into_value(),
        );
        map.insert_unchecked(
            Property::DisabledPermissions,
            self.disabled_permissions.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Role {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::RoleIds) => self.role_ids.patch(pointer, value),
            Some(Property::EnabledPermissions) => self.enabled_permissions.patch(pointer, value),
            Some(Property::DisabledPermissions) => self.disabled_permissions.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Roles {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Roles::Default => true,
            Roles::Custom(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            Roles::Default => {}
            Roles::Custom(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for Roles {
    fn default() -> Self {
        Roles::Default
    }
}

impl Pickle for Roles {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Roles::Default => {
                0u16.pickle(out);
            }
            Roles::Custom(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(Roles::Default),
            1 => Pickle::unpickle(stream).map(Roles::Custom),
            _ => None,
        }
    }
}

impl IntoValue for Roles {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Roles::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            Roles::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Roles {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                RolesType::Default => *self = Roles::Default,
                RolesType::Custom => *self = Roles::Custom(Default::default()),
            }
        }
        match self {
            Roles::Default => pointer.assert_eof(),
            Roles::Custom(inner) => inner.patch(pointer, value),
        }
    }
}

impl Roles {
    pub fn object_type(&self) -> RolesType {
        match self {
            Roles::Default => RolesType::Default,
            Roles::Custom(_) => RolesType::Custom,
        }
    }
}

impl S3Store {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.region;
        value.validate(errors);
        let value = &self.bucket;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Bucket));
        }
        if let Some(value) = &self.access_key {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AccessKey));
            }
        }
        let value = &self.secret_key;
        value.validate(errors);
        let value = &self.security_token;
        value.validate(errors);
        let value = &self.session_token;
        value.validate(errors);
        if let Some(value) = &self.profile {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Profile));
            }
        }
        let value = &self.max_retries;
        if *value > 10 {
            errors.push(ValidationError::max_value(Property::MaxRetries, 10));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxRetries, 1));
        }
        if let Some(value) = &self.key_prefix {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::KeyPrefix));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for S3Store {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.region.pickle(out);
        self.bucket.pickle(out);
        self.access_key.pickle(out);
        self.secret_key.pickle(out);
        self.security_token.pickle(out);
        self.session_token.pickle(out);
        self.profile.pickle(out);
        self.timeout.pickle(out);
        self.max_retries.pickle(out);
        self.key_prefix.pickle(out);
        self.allow_invalid_certs.pickle(out);
        self.verify_after_write.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.region = Pickle::unpickle(stream)?;
        this.bucket = Pickle::unpickle(stream)?;
        this.access_key = Pickle::unpickle(stream)?;
        this.secret_key = Pickle::unpickle(stream)?;
        this.security_token = Pickle::unpickle(stream)?;
        this.session_token = Pickle::unpickle(stream)?;
        this.profile = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.max_retries = Pickle::unpickle(stream)?;
        this.key_prefix = Pickle::unpickle(stream)?;
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        if stream.version() >= 1 {
            this.verify_after_write = Pickle::unpickle(stream)?;
        }
        Some(this)
    }
}

impl Default for S3Store {
    fn default() -> Self {
        Self {
            region: Default::default(),
            bucket: Default::default(),
            access_key: Default::default(),
            secret_key: Default::default(),
            security_token: Default::default(),
            session_token: Default::default(),
            profile: Default::default(),
            timeout: Duration::from_millis(30000),
            max_retries: 3u64,
            key_prefix: Default::default(),
            allow_invalid_certs: false,
            verify_after_write: true,
        }
    }
}

impl IntoValue for S3Store {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Region, self.region.into_value());
        map.insert_unchecked(Property::Bucket, self.bucket.into_value());
        map.insert_unchecked(Property::AccessKey, self.access_key.into_value());
        map.insert_unchecked(Property::SecretKey, self.secret_key.into_value());
        map.insert_unchecked(Property::SecurityToken, self.security_token.into_value());
        map.insert_unchecked(Property::SessionToken, self.session_token.into_value());
        map.insert_unchecked(Property::Profile, self.profile.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::MaxRetries, self.max_retries.into_value());
        map.insert_unchecked(Property::KeyPrefix, self.key_prefix.into_value());
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(
            Property::VerifyAfterWrite,
            self.verify_after_write.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for S3Store {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Region) => self.region.patch(pointer, value),
            Some(Property::Bucket) => self
                .bucket
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AccessKey) => self
                .access_key
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::SecretKey) => self.secret_key.patch(pointer, value),
            Some(Property::SecurityToken) => self.security_token.patch(pointer, value),
            Some(Property::SessionToken) => self.session_token.patch(pointer, value),
            Some(Property::Profile) => self
                .profile
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::MaxRetries) => self.max_retries.patch(pointer, value),
            Some(Property::KeyPrefix) => self
                .key_prefix
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::VerifyAfterWrite) => self.verify_after_write.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl S3StoreCustomRegion {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.custom_endpoint;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::CustomEndpoint));
        }
        let value = &self.custom_region;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::CustomRegion));
        }
        errors.len() == neb
    }
}

impl Pickle for S3StoreCustomRegion {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.custom_endpoint.pickle(out);
        self.custom_region.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.custom_endpoint = Pickle::unpickle(stream)?;
        this.custom_region = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for S3StoreCustomRegion {
    fn default() -> Self {
        Self {
            custom_endpoint: Default::default(),
            custom_region: Default::default(),
        }
    }
}

impl IntoValue for S3StoreCustomRegion {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::CustomEndpoint, self.custom_endpoint.into_value());
        map.insert_unchecked(Property::CustomRegion, self.custom_region.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for S3StoreCustomRegion {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CustomEndpoint) => self
                .custom_endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::CustomRegion) => self
                .custom_region
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl S3StoreRegion {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            S3StoreRegion::UsEast1 => true,
            S3StoreRegion::UsEast2 => true,
            S3StoreRegion::UsWest1 => true,
            S3StoreRegion::UsWest2 => true,
            S3StoreRegion::CaCentral1 => true,
            S3StoreRegion::AfSouth1 => true,
            S3StoreRegion::ApEast1 => true,
            S3StoreRegion::ApSouth1 => true,
            S3StoreRegion::ApNortheast1 => true,
            S3StoreRegion::ApNortheast2 => true,
            S3StoreRegion::ApNortheast3 => true,
            S3StoreRegion::ApSoutheast1 => true,
            S3StoreRegion::ApSoutheast2 => true,
            S3StoreRegion::CnNorth1 => true,
            S3StoreRegion::CnNorthwest1 => true,
            S3StoreRegion::EuNorth1 => true,
            S3StoreRegion::EuCentral1 => true,
            S3StoreRegion::EuCentral2 => true,
            S3StoreRegion::EuWest1 => true,
            S3StoreRegion::EuWest2 => true,
            S3StoreRegion::EuWest3 => true,
            S3StoreRegion::IlCentral1 => true,
            S3StoreRegion::MeSouth1 => true,
            S3StoreRegion::SaEast1 => true,
            S3StoreRegion::DoNyc3 => true,
            S3StoreRegion::DoAms3 => true,
            S3StoreRegion::DoSgp1 => true,
            S3StoreRegion::DoFra1 => true,
            S3StoreRegion::Yandex => true,
            S3StoreRegion::WaUsEast1 => true,
            S3StoreRegion::WaUsEast2 => true,
            S3StoreRegion::WaUsCentral1 => true,
            S3StoreRegion::WaUsWest1 => true,
            S3StoreRegion::WaCaCentral1 => true,
            S3StoreRegion::WaEuCentral1 => true,
            S3StoreRegion::WaEuCentral2 => true,
            S3StoreRegion::WaEuWest1 => true,
            S3StoreRegion::WaEuWest2 => true,
            S3StoreRegion::WaApNortheast1 => true,
            S3StoreRegion::WaApNortheast2 => true,
            S3StoreRegion::WaApSoutheast1 => true,
            S3StoreRegion::WaApSoutheast2 => true,
            S3StoreRegion::Custom(inner) => inner.validate(errors),
        }
    }
}

impl Default for S3StoreRegion {
    fn default() -> Self {
        S3StoreRegion::UsEast1
    }
}

impl Pickle for S3StoreRegion {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            S3StoreRegion::UsEast1 => {
                0u16.pickle(out);
            }
            S3StoreRegion::UsEast2 => {
                1u16.pickle(out);
            }
            S3StoreRegion::UsWest1 => {
                2u16.pickle(out);
            }
            S3StoreRegion::UsWest2 => {
                3u16.pickle(out);
            }
            S3StoreRegion::CaCentral1 => {
                4u16.pickle(out);
            }
            S3StoreRegion::AfSouth1 => {
                5u16.pickle(out);
            }
            S3StoreRegion::ApEast1 => {
                6u16.pickle(out);
            }
            S3StoreRegion::ApSouth1 => {
                7u16.pickle(out);
            }
            S3StoreRegion::ApNortheast1 => {
                8u16.pickle(out);
            }
            S3StoreRegion::ApNortheast2 => {
                9u16.pickle(out);
            }
            S3StoreRegion::ApNortheast3 => {
                10u16.pickle(out);
            }
            S3StoreRegion::ApSoutheast1 => {
                11u16.pickle(out);
            }
            S3StoreRegion::ApSoutheast2 => {
                12u16.pickle(out);
            }
            S3StoreRegion::CnNorth1 => {
                13u16.pickle(out);
            }
            S3StoreRegion::CnNorthwest1 => {
                14u16.pickle(out);
            }
            S3StoreRegion::EuNorth1 => {
                15u16.pickle(out);
            }
            S3StoreRegion::EuCentral1 => {
                16u16.pickle(out);
            }
            S3StoreRegion::EuCentral2 => {
                17u16.pickle(out);
            }
            S3StoreRegion::EuWest1 => {
                18u16.pickle(out);
            }
            S3StoreRegion::EuWest2 => {
                19u16.pickle(out);
            }
            S3StoreRegion::EuWest3 => {
                20u16.pickle(out);
            }
            S3StoreRegion::IlCentral1 => {
                21u16.pickle(out);
            }
            S3StoreRegion::MeSouth1 => {
                22u16.pickle(out);
            }
            S3StoreRegion::SaEast1 => {
                23u16.pickle(out);
            }
            S3StoreRegion::DoNyc3 => {
                24u16.pickle(out);
            }
            S3StoreRegion::DoAms3 => {
                25u16.pickle(out);
            }
            S3StoreRegion::DoSgp1 => {
                26u16.pickle(out);
            }
            S3StoreRegion::DoFra1 => {
                27u16.pickle(out);
            }
            S3StoreRegion::Yandex => {
                28u16.pickle(out);
            }
            S3StoreRegion::WaUsEast1 => {
                29u16.pickle(out);
            }
            S3StoreRegion::WaUsEast2 => {
                30u16.pickle(out);
            }
            S3StoreRegion::WaUsCentral1 => {
                31u16.pickle(out);
            }
            S3StoreRegion::WaUsWest1 => {
                32u16.pickle(out);
            }
            S3StoreRegion::WaCaCentral1 => {
                33u16.pickle(out);
            }
            S3StoreRegion::WaEuCentral1 => {
                34u16.pickle(out);
            }
            S3StoreRegion::WaEuCentral2 => {
                35u16.pickle(out);
            }
            S3StoreRegion::WaEuWest1 => {
                36u16.pickle(out);
            }
            S3StoreRegion::WaEuWest2 => {
                37u16.pickle(out);
            }
            S3StoreRegion::WaApNortheast1 => {
                38u16.pickle(out);
            }
            S3StoreRegion::WaApNortheast2 => {
                39u16.pickle(out);
            }
            S3StoreRegion::WaApSoutheast1 => {
                40u16.pickle(out);
            }
            S3StoreRegion::WaApSoutheast2 => {
                41u16.pickle(out);
            }
            S3StoreRegion::Custom(inner) => {
                42u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(S3StoreRegion::UsEast1),
            1 => Some(S3StoreRegion::UsEast2),
            2 => Some(S3StoreRegion::UsWest1),
            3 => Some(S3StoreRegion::UsWest2),
            4 => Some(S3StoreRegion::CaCentral1),
            5 => Some(S3StoreRegion::AfSouth1),
            6 => Some(S3StoreRegion::ApEast1),
            7 => Some(S3StoreRegion::ApSouth1),
            8 => Some(S3StoreRegion::ApNortheast1),
            9 => Some(S3StoreRegion::ApNortheast2),
            10 => Some(S3StoreRegion::ApNortheast3),
            11 => Some(S3StoreRegion::ApSoutheast1),
            12 => Some(S3StoreRegion::ApSoutheast2),
            13 => Some(S3StoreRegion::CnNorth1),
            14 => Some(S3StoreRegion::CnNorthwest1),
            15 => Some(S3StoreRegion::EuNorth1),
            16 => Some(S3StoreRegion::EuCentral1),
            17 => Some(S3StoreRegion::EuCentral2),
            18 => Some(S3StoreRegion::EuWest1),
            19 => Some(S3StoreRegion::EuWest2),
            20 => Some(S3StoreRegion::EuWest3),
            21 => Some(S3StoreRegion::IlCentral1),
            22 => Some(S3StoreRegion::MeSouth1),
            23 => Some(S3StoreRegion::SaEast1),
            24 => Some(S3StoreRegion::DoNyc3),
            25 => Some(S3StoreRegion::DoAms3),
            26 => Some(S3StoreRegion::DoSgp1),
            27 => Some(S3StoreRegion::DoFra1),
            28 => Some(S3StoreRegion::Yandex),
            29 => Some(S3StoreRegion::WaUsEast1),
            30 => Some(S3StoreRegion::WaUsEast2),
            31 => Some(S3StoreRegion::WaUsCentral1),
            32 => Some(S3StoreRegion::WaUsWest1),
            33 => Some(S3StoreRegion::WaCaCentral1),
            34 => Some(S3StoreRegion::WaEuCentral1),
            35 => Some(S3StoreRegion::WaEuCentral2),
            36 => Some(S3StoreRegion::WaEuWest1),
            37 => Some(S3StoreRegion::WaEuWest2),
            38 => Some(S3StoreRegion::WaApNortheast1),
            39 => Some(S3StoreRegion::WaApNortheast2),
            40 => Some(S3StoreRegion::WaApSoutheast1),
            41 => Some(S3StoreRegion::WaApSoutheast2),
            42 => Pickle::unpickle(stream).map(S3StoreRegion::Custom),
            _ => None,
        }
    }
}

impl IntoValue for S3StoreRegion {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            S3StoreRegion::UsEast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("UsEast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::UsEast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("UsEast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::UsWest1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("UsWest1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::UsWest2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("UsWest2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::CaCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("CaCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::AfSouth1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("AfSouth1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApEast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApEast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApSouth1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApSouth1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApNortheast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApNortheast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApNortheast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApNortheast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApNortheast3 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApNortheast3".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApSoutheast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApSoutheast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::ApSoutheast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("ApSoutheast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::CnNorth1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("CnNorth1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::CnNorthwest1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("CnNorthwest1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuNorth1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuNorth1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuCentral2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuCentral2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuWest1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuWest1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuWest2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuWest2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::EuWest3 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("EuWest3".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::IlCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("IlCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::MeSouth1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("MeSouth1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::SaEast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("SaEast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::DoNyc3 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DoNyc3".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::DoAms3 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DoAms3".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::DoSgp1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DoSgp1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::DoFra1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("DoFra1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::Yandex => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Yandex".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaUsEast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaUsEast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaUsEast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaUsEast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaUsCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaUsCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaUsWest1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaUsWest1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaCaCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaCaCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaEuCentral1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaEuCentral1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaEuCentral2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaEuCentral2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaEuWest1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaEuWest1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaEuWest2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaEuWest2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaApNortheast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaApNortheast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaApNortheast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaApNortheast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaApSoutheast1 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaApSoutheast1".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::WaApSoutheast2 => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("WaApSoutheast2".into()));
                JmapValue::Object(obj)
            }
            S3StoreRegion::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for S3StoreRegion {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                S3StoreRegionType::UsEast1 => *self = S3StoreRegion::UsEast1,
                S3StoreRegionType::UsEast2 => *self = S3StoreRegion::UsEast2,
                S3StoreRegionType::UsWest1 => *self = S3StoreRegion::UsWest1,
                S3StoreRegionType::UsWest2 => *self = S3StoreRegion::UsWest2,
                S3StoreRegionType::CaCentral1 => *self = S3StoreRegion::CaCentral1,
                S3StoreRegionType::AfSouth1 => *self = S3StoreRegion::AfSouth1,
                S3StoreRegionType::ApEast1 => *self = S3StoreRegion::ApEast1,
                S3StoreRegionType::ApSouth1 => *self = S3StoreRegion::ApSouth1,
                S3StoreRegionType::ApNortheast1 => *self = S3StoreRegion::ApNortheast1,
                S3StoreRegionType::ApNortheast2 => *self = S3StoreRegion::ApNortheast2,
                S3StoreRegionType::ApNortheast3 => *self = S3StoreRegion::ApNortheast3,
                S3StoreRegionType::ApSoutheast1 => *self = S3StoreRegion::ApSoutheast1,
                S3StoreRegionType::ApSoutheast2 => *self = S3StoreRegion::ApSoutheast2,
                S3StoreRegionType::CnNorth1 => *self = S3StoreRegion::CnNorth1,
                S3StoreRegionType::CnNorthwest1 => *self = S3StoreRegion::CnNorthwest1,
                S3StoreRegionType::EuNorth1 => *self = S3StoreRegion::EuNorth1,
                S3StoreRegionType::EuCentral1 => *self = S3StoreRegion::EuCentral1,
                S3StoreRegionType::EuCentral2 => *self = S3StoreRegion::EuCentral2,
                S3StoreRegionType::EuWest1 => *self = S3StoreRegion::EuWest1,
                S3StoreRegionType::EuWest2 => *self = S3StoreRegion::EuWest2,
                S3StoreRegionType::EuWest3 => *self = S3StoreRegion::EuWest3,
                S3StoreRegionType::IlCentral1 => *self = S3StoreRegion::IlCentral1,
                S3StoreRegionType::MeSouth1 => *self = S3StoreRegion::MeSouth1,
                S3StoreRegionType::SaEast1 => *self = S3StoreRegion::SaEast1,
                S3StoreRegionType::DoNyc3 => *self = S3StoreRegion::DoNyc3,
                S3StoreRegionType::DoAms3 => *self = S3StoreRegion::DoAms3,
                S3StoreRegionType::DoSgp1 => *self = S3StoreRegion::DoSgp1,
                S3StoreRegionType::DoFra1 => *self = S3StoreRegion::DoFra1,
                S3StoreRegionType::Yandex => *self = S3StoreRegion::Yandex,
                S3StoreRegionType::WaUsEast1 => *self = S3StoreRegion::WaUsEast1,
                S3StoreRegionType::WaUsEast2 => *self = S3StoreRegion::WaUsEast2,
                S3StoreRegionType::WaUsCentral1 => *self = S3StoreRegion::WaUsCentral1,
                S3StoreRegionType::WaUsWest1 => *self = S3StoreRegion::WaUsWest1,
                S3StoreRegionType::WaCaCentral1 => *self = S3StoreRegion::WaCaCentral1,
                S3StoreRegionType::WaEuCentral1 => *self = S3StoreRegion::WaEuCentral1,
                S3StoreRegionType::WaEuCentral2 => *self = S3StoreRegion::WaEuCentral2,
                S3StoreRegionType::WaEuWest1 => *self = S3StoreRegion::WaEuWest1,
                S3StoreRegionType::WaEuWest2 => *self = S3StoreRegion::WaEuWest2,
                S3StoreRegionType::WaApNortheast1 => *self = S3StoreRegion::WaApNortheast1,
                S3StoreRegionType::WaApNortheast2 => *self = S3StoreRegion::WaApNortheast2,
                S3StoreRegionType::WaApSoutheast1 => *self = S3StoreRegion::WaApSoutheast1,
                S3StoreRegionType::WaApSoutheast2 => *self = S3StoreRegion::WaApSoutheast2,
                S3StoreRegionType::Custom => *self = S3StoreRegion::Custom(Default::default()),
            }
        }
        match self {
            S3StoreRegion::UsEast1 => pointer.assert_eof(),
            S3StoreRegion::UsEast2 => pointer.assert_eof(),
            S3StoreRegion::UsWest1 => pointer.assert_eof(),
            S3StoreRegion::UsWest2 => pointer.assert_eof(),
            S3StoreRegion::CaCentral1 => pointer.assert_eof(),
            S3StoreRegion::AfSouth1 => pointer.assert_eof(),
            S3StoreRegion::ApEast1 => pointer.assert_eof(),
            S3StoreRegion::ApSouth1 => pointer.assert_eof(),
            S3StoreRegion::ApNortheast1 => pointer.assert_eof(),
            S3StoreRegion::ApNortheast2 => pointer.assert_eof(),
            S3StoreRegion::ApNortheast3 => pointer.assert_eof(),
            S3StoreRegion::ApSoutheast1 => pointer.assert_eof(),
            S3StoreRegion::ApSoutheast2 => pointer.assert_eof(),
            S3StoreRegion::CnNorth1 => pointer.assert_eof(),
            S3StoreRegion::CnNorthwest1 => pointer.assert_eof(),
            S3StoreRegion::EuNorth1 => pointer.assert_eof(),
            S3StoreRegion::EuCentral1 => pointer.assert_eof(),
            S3StoreRegion::EuCentral2 => pointer.assert_eof(),
            S3StoreRegion::EuWest1 => pointer.assert_eof(),
            S3StoreRegion::EuWest2 => pointer.assert_eof(),
            S3StoreRegion::EuWest3 => pointer.assert_eof(),
            S3StoreRegion::IlCentral1 => pointer.assert_eof(),
            S3StoreRegion::MeSouth1 => pointer.assert_eof(),
            S3StoreRegion::SaEast1 => pointer.assert_eof(),
            S3StoreRegion::DoNyc3 => pointer.assert_eof(),
            S3StoreRegion::DoAms3 => pointer.assert_eof(),
            S3StoreRegion::DoSgp1 => pointer.assert_eof(),
            S3StoreRegion::DoFra1 => pointer.assert_eof(),
            S3StoreRegion::Yandex => pointer.assert_eof(),
            S3StoreRegion::WaUsEast1 => pointer.assert_eof(),
            S3StoreRegion::WaUsEast2 => pointer.assert_eof(),
            S3StoreRegion::WaUsCentral1 => pointer.assert_eof(),
            S3StoreRegion::WaUsWest1 => pointer.assert_eof(),
            S3StoreRegion::WaCaCentral1 => pointer.assert_eof(),
            S3StoreRegion::WaEuCentral1 => pointer.assert_eof(),
            S3StoreRegion::WaEuCentral2 => pointer.assert_eof(),
            S3StoreRegion::WaEuWest1 => pointer.assert_eof(),
            S3StoreRegion::WaEuWest2 => pointer.assert_eof(),
            S3StoreRegion::WaApNortheast1 => pointer.assert_eof(),
            S3StoreRegion::WaApNortheast2 => pointer.assert_eof(),
            S3StoreRegion::WaApSoutheast1 => pointer.assert_eof(),
            S3StoreRegion::WaApSoutheast2 => pointer.assert_eof(),
            S3StoreRegion::Custom(inner) => inner.patch(pointer, value),
        }
    }
}

impl S3StoreRegion {
    pub fn object_type(&self) -> S3StoreRegionType {
        match self {
            S3StoreRegion::UsEast1 => S3StoreRegionType::UsEast1,
            S3StoreRegion::UsEast2 => S3StoreRegionType::UsEast2,
            S3StoreRegion::UsWest1 => S3StoreRegionType::UsWest1,
            S3StoreRegion::UsWest2 => S3StoreRegionType::UsWest2,
            S3StoreRegion::CaCentral1 => S3StoreRegionType::CaCentral1,
            S3StoreRegion::AfSouth1 => S3StoreRegionType::AfSouth1,
            S3StoreRegion::ApEast1 => S3StoreRegionType::ApEast1,
            S3StoreRegion::ApSouth1 => S3StoreRegionType::ApSouth1,
            S3StoreRegion::ApNortheast1 => S3StoreRegionType::ApNortheast1,
            S3StoreRegion::ApNortheast2 => S3StoreRegionType::ApNortheast2,
            S3StoreRegion::ApNortheast3 => S3StoreRegionType::ApNortheast3,
            S3StoreRegion::ApSoutheast1 => S3StoreRegionType::ApSoutheast1,
            S3StoreRegion::ApSoutheast2 => S3StoreRegionType::ApSoutheast2,
            S3StoreRegion::CnNorth1 => S3StoreRegionType::CnNorth1,
            S3StoreRegion::CnNorthwest1 => S3StoreRegionType::CnNorthwest1,
            S3StoreRegion::EuNorth1 => S3StoreRegionType::EuNorth1,
            S3StoreRegion::EuCentral1 => S3StoreRegionType::EuCentral1,
            S3StoreRegion::EuCentral2 => S3StoreRegionType::EuCentral2,
            S3StoreRegion::EuWest1 => S3StoreRegionType::EuWest1,
            S3StoreRegion::EuWest2 => S3StoreRegionType::EuWest2,
            S3StoreRegion::EuWest3 => S3StoreRegionType::EuWest3,
            S3StoreRegion::IlCentral1 => S3StoreRegionType::IlCentral1,
            S3StoreRegion::MeSouth1 => S3StoreRegionType::MeSouth1,
            S3StoreRegion::SaEast1 => S3StoreRegionType::SaEast1,
            S3StoreRegion::DoNyc3 => S3StoreRegionType::DoNyc3,
            S3StoreRegion::DoAms3 => S3StoreRegionType::DoAms3,
            S3StoreRegion::DoSgp1 => S3StoreRegionType::DoSgp1,
            S3StoreRegion::DoFra1 => S3StoreRegionType::DoFra1,
            S3StoreRegion::Yandex => S3StoreRegionType::Yandex,
            S3StoreRegion::WaUsEast1 => S3StoreRegionType::WaUsEast1,
            S3StoreRegion::WaUsEast2 => S3StoreRegionType::WaUsEast2,
            S3StoreRegion::WaUsCentral1 => S3StoreRegionType::WaUsCentral1,
            S3StoreRegion::WaUsWest1 => S3StoreRegionType::WaUsWest1,
            S3StoreRegion::WaCaCentral1 => S3StoreRegionType::WaCaCentral1,
            S3StoreRegion::WaEuCentral1 => S3StoreRegionType::WaEuCentral1,
            S3StoreRegion::WaEuCentral2 => S3StoreRegionType::WaEuCentral2,
            S3StoreRegion::WaEuWest1 => S3StoreRegionType::WaEuWest1,
            S3StoreRegion::WaEuWest2 => S3StoreRegionType::WaEuWest2,
            S3StoreRegion::WaApNortheast1 => S3StoreRegionType::WaApNortheast1,
            S3StoreRegion::WaApNortheast2 => S3StoreRegionType::WaApNortheast2,
            S3StoreRegion::WaApSoutheast1 => S3StoreRegionType::WaApSoutheast1,
            S3StoreRegion::WaApSoutheast2 => S3StoreRegionType::WaApSoutheast2,
            S3StoreRegion::Custom(_) => S3StoreRegionType::Custom,
        }
    }
}

impl ObjectImpl for Search {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Search;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.index_batch_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::IndexBatchSize, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Search {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.index_batch_size.pickle(out);
        self.default_language.pickle(out);
        self.supported_languages.pickle(out);
        self.index_calendar.pickle(out);
        self.index_calendar_fields.pickle(out);
        self.index_contacts.pickle(out);
        self.index_contact_fields.pickle(out);
        self.index_email.pickle(out);
        self.index_email_fields.pickle(out);
        self.index_telemetry.pickle(out);
        self.index_tracing_fields.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.index_batch_size = Pickle::unpickle(stream)?;
        this.default_language = Pickle::unpickle(stream)?;
        this.supported_languages = Pickle::unpickle(stream)?;
        this.index_calendar = Pickle::unpickle(stream)?;
        this.index_calendar_fields = Pickle::unpickle(stream)?;
        this.index_contacts = Pickle::unpickle(stream)?;
        this.index_contact_fields = Pickle::unpickle(stream)?;
        this.index_email = Pickle::unpickle(stream)?;
        this.index_email_fields = Pickle::unpickle(stream)?;
        this.index_telemetry = Pickle::unpickle(stream)?;
        this.index_tracing_fields = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Search {
    fn default() -> Self {
        Self {
            index_batch_size: 100u64,
            default_language: Locale::EnUS,
            supported_languages: Map::new(vec![Locale::EnUS]),
            index_calendar: true,
            index_calendar_fields: Map::new(vec![
                SearchCalendarField::Title,
                SearchCalendarField::Description,
                SearchCalendarField::Location,
                SearchCalendarField::Owner,
                SearchCalendarField::Attendee,
                SearchCalendarField::Start,
                SearchCalendarField::Uid,
            ]),
            index_contacts: true,
            index_contact_fields: Map::new(vec![
                SearchContactField::Member,
                SearchContactField::Kind,
                SearchContactField::Name,
                SearchContactField::Nickname,
                SearchContactField::Organization,
                SearchContactField::Email,
                SearchContactField::Phone,
                SearchContactField::OnlineService,
                SearchContactField::Address,
                SearchContactField::Note,
                SearchContactField::Uid,
            ]),
            index_email: true,
            index_email_fields: Map::new(vec![
                SearchEmailField::From,
                SearchEmailField::To,
                SearchEmailField::Cc,
                SearchEmailField::Bcc,
                SearchEmailField::Subject,
                SearchEmailField::Body,
                SearchEmailField::Attachment,
                SearchEmailField::ReceivedAt,
                SearchEmailField::SentAt,
                SearchEmailField::Size,
                SearchEmailField::HasAttachment,
            ]),
            index_telemetry: true,
            index_tracing_fields: Map::new(vec![
                SearchTracingField::EventType,
                SearchTracingField::QueueId,
                SearchTracingField::Keywords,
            ]),
        }
    }
}

impl IntoValue for Search {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::IndexBatchSize, self.index_batch_size.into_value());
        map.insert_unchecked(
            Property::DefaultLanguage,
            self.default_language.into_value(),
        );
        map.insert_unchecked(
            Property::SupportedLanguages,
            self.supported_languages.into_value(),
        );
        map.insert_unchecked(Property::IndexCalendar, self.index_calendar.into_value());
        map.insert_unchecked(
            Property::IndexCalendarFields,
            self.index_calendar_fields.into_value(),
        );
        map.insert_unchecked(Property::IndexContacts, self.index_contacts.into_value());
        map.insert_unchecked(
            Property::IndexContactFields,
            self.index_contact_fields.into_value(),
        );
        map.insert_unchecked(Property::IndexEmail, self.index_email.into_value());
        map.insert_unchecked(
            Property::IndexEmailFields,
            self.index_email_fields.into_value(),
        );
        map.insert_unchecked(Property::IndexTelemetry, self.index_telemetry.into_value());
        map.insert_unchecked(
            Property::IndexTracingFields,
            self.index_tracing_fields.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Search {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IndexBatchSize) => self.index_batch_size.patch(pointer, value),
            Some(Property::DefaultLanguage) => self.default_language.patch(pointer, value),
            Some(Property::SupportedLanguages) => self.supported_languages.patch(pointer, value),
            Some(Property::IndexCalendar) => self.index_calendar.patch(pointer, value),
            Some(Property::IndexCalendarFields) => self.index_calendar_fields.patch(pointer, value),
            Some(Property::IndexContacts) => self.index_contacts.patch(pointer, value),
            Some(Property::IndexContactFields) => self.index_contact_fields.patch(pointer, value),
            Some(Property::IndexEmail) => self.index_email.patch(pointer, value),
            Some(Property::IndexEmailFields) => self.index_email_fields.patch(pointer, value),
            Some(Property::IndexTelemetry) => self.index_telemetry.patch(pointer, value),
            Some(Property::IndexTracingFields) => self.index_tracing_fields.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SearchStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SearchStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SearchStore::Default => true,
            SearchStore::ElasticSearch(inner) => inner.validate(errors),
            SearchStore::Meilisearch(inner) => inner.validate(errors),
            SearchStore::FoundationDb(inner) => inner.validate(errors),
            SearchStore::PostgreSql(inner) => inner.validate(errors),
            SearchStore::MySql(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for SearchStore {
    fn default() -> Self {
        SearchStore::Default
    }
}

impl Pickle for SearchStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SearchStore::Default => {
                0u16.pickle(out);
            }
            SearchStore::ElasticSearch(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SearchStore::Meilisearch(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SearchStore::FoundationDb(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            SearchStore::PostgreSql(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            SearchStore::MySql(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SearchStore::Default),
            1 => Pickle::unpickle(stream).map(SearchStore::ElasticSearch),
            2 => Pickle::unpickle(stream).map(SearchStore::Meilisearch),
            3 => Pickle::unpickle(stream).map(SearchStore::FoundationDb),
            4 => Pickle::unpickle(stream).map(SearchStore::PostgreSql),
            5 => Pickle::unpickle(stream).map(SearchStore::MySql),
            _ => None,
        }
    }
}

impl IntoValue for SearchStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SearchStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            SearchStore::ElasticSearch(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ElasticSearch".into()));
                obj
            }
            SearchStore::Meilisearch(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Meilisearch".into()));
                obj
            }
            SearchStore::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            SearchStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            SearchStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SearchStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SearchStoreType::Default => *self = SearchStore::Default,
                SearchStoreType::ElasticSearch => {
                    *self = SearchStore::ElasticSearch(Default::default())
                }
                SearchStoreType::Meilisearch => {
                    *self = SearchStore::Meilisearch(Default::default())
                }
                SearchStoreType::FoundationDb => {
                    *self = SearchStore::FoundationDb(Default::default())
                }
                SearchStoreType::PostgreSql => *self = SearchStore::PostgreSql(Default::default()),
                SearchStoreType::MySql => *self = SearchStore::MySql(Default::default()),
            }
        }
        match self {
            SearchStore::Default => pointer.assert_eof(),
            SearchStore::ElasticSearch(inner) => inner.patch(pointer, value),
            SearchStore::Meilisearch(inner) => inner.patch(pointer, value),
            SearchStore::FoundationDb(inner) => inner.patch(pointer, value),
            SearchStore::PostgreSql(inner) => inner.patch(pointer, value),
            SearchStore::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl SearchStore {
    pub fn object_type(&self) -> SearchStoreType {
        match self {
            SearchStore::Default => SearchStoreType::Default,
            SearchStore::ElasticSearch(_) => SearchStoreType::ElasticSearch,
            SearchStore::Meilisearch(_) => SearchStoreType::Meilisearch,
            SearchStore::FoundationDb(_) => SearchStoreType::FoundationDb,
            SearchStore::PostgreSql(_) => SearchStoreType::PostgreSql,
            SearchStore::MySql(_) => SearchStoreType::MySql,
        }
    }
}

impl SecondaryCredential {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.credential_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CredentialId, value));
        }
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.expires_at {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ExpiresAt, value));
            }
        }
        let value = &self.permissions;
        value.validate(errors);
        let value = &self.allowed_ips;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::AllowedIps, value));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for SecondaryCredential {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.credential_id.pickle(out);
        self.description.pickle(out);
        self.secret.pickle(out);
        self.created_at.pickle(out);
        self.expires_at.pickle(out);
        self.permissions.pickle(out);
        self.allowed_ips.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.credential_id = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.secret = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.allowed_ips = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SecondaryCredential {
    fn default() -> Self {
        Self {
            credential_id: Default::default(),
            description: Default::default(),
            secret: Default::default(),
            created_at: Default::default(),
            expires_at: Default::default(),
            permissions: Default::default(),
            allowed_ips: Default::default(),
        }
    }
}

impl IntoValue for SecondaryCredential {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::CredentialId, self.credential_id.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::AllowedIps, self.allowed_ips.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SecondaryCredential {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CredentialId) => pointer.assert_server_set(),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Secret) => pointer.assert_server_set(),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::AllowedIps) => self.allowed_ips.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SecretKey {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SecretKey::Value(inner) => inner.validate(errors),
            SecretKey::EnvironmentVariable(inner) => inner.validate(errors),
            SecretKey::File(inner) => inner.validate(errors),
        }
    }
}

impl Default for SecretKey {
    fn default() -> Self {
        SecretKey::Value(Default::default())
    }
}

impl Pickle for SecretKey {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SecretKey::Value(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SecretKey::EnvironmentVariable(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SecretKey::File(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SecretKey::Value),
            1 => Pickle::unpickle(stream).map(SecretKey::EnvironmentVariable),
            2 => Pickle::unpickle(stream).map(SecretKey::File),
            _ => None,
        }
    }
}

impl IntoValue for SecretKey {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SecretKey::Value(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Value".into()));
                obj
            }
            SecretKey::EnvironmentVariable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnvironmentVariable".into()));
                obj
            }
            SecretKey::File(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("File".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SecretKey {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SecretKeyType::Value => *self = SecretKey::Value(Default::default()),
                SecretKeyType::EnvironmentVariable => {
                    *self = SecretKey::EnvironmentVariable(Default::default())
                }
                SecretKeyType::File => *self = SecretKey::File(Default::default()),
            }
        }
        match self {
            SecretKey::Value(inner) => inner.patch(pointer, value),
            SecretKey::EnvironmentVariable(inner) => inner.patch(pointer, value),
            SecretKey::File(inner) => inner.patch(pointer, value),
        }
    }
}

impl SecretKey {
    pub fn object_type(&self) -> SecretKeyType {
        match self {
            SecretKey::Value(_) => SecretKeyType::Value,
            SecretKey::EnvironmentVariable(_) => SecretKeyType::EnvironmentVariable,
            SecretKey::File(_) => SecretKeyType::File,
        }
    }
}

impl SecretKeyEnvironmentVariable {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.variable_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::VariableName));
        }
        errors.len() == neb
    }
}

impl Pickle for SecretKeyEnvironmentVariable {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.variable_name.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.variable_name = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SecretKeyEnvironmentVariable {
    fn default() -> Self {
        Self {
            variable_name: Default::default(),
        }
    }
}

impl IntoValue for SecretKeyEnvironmentVariable {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::VariableName, self.variable_name.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SecretKeyEnvironmentVariable {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::VariableName) => self.variable_name.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SecretKeyFile {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.file_path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FilePath));
        }
        errors.len() == neb
    }
}

impl Pickle for SecretKeyFile {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.file_path.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.file_path = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SecretKeyFile {
    fn default() -> Self {
        Self {
            file_path: Default::default(),
        }
    }
}

impl IntoValue for SecretKeyFile {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::FilePath, self.file_path.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SecretKeyFile {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::FilePath) => self.file_path.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SecretKeyOptional {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SecretKeyOptional::None => true,
            SecretKeyOptional::Value(inner) => inner.validate(errors),
            SecretKeyOptional::EnvironmentVariable(inner) => inner.validate(errors),
            SecretKeyOptional::File(inner) => inner.validate(errors),
        }
    }
}

impl Default for SecretKeyOptional {
    fn default() -> Self {
        SecretKeyOptional::None
    }
}

impl Pickle for SecretKeyOptional {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SecretKeyOptional::None => {
                0u16.pickle(out);
            }
            SecretKeyOptional::Value(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SecretKeyOptional::EnvironmentVariable(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SecretKeyOptional::File(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SecretKeyOptional::None),
            1 => Pickle::unpickle(stream).map(SecretKeyOptional::Value),
            2 => Pickle::unpickle(stream).map(SecretKeyOptional::EnvironmentVariable),
            3 => Pickle::unpickle(stream).map(SecretKeyOptional::File),
            _ => None,
        }
    }
}

impl IntoValue for SecretKeyOptional {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SecretKeyOptional::None => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("None".into()));
                JmapValue::Object(obj)
            }
            SecretKeyOptional::Value(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Value".into()));
                obj
            }
            SecretKeyOptional::EnvironmentVariable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnvironmentVariable".into()));
                obj
            }
            SecretKeyOptional::File(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("File".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SecretKeyOptional {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SecretKeyOptionalType::None => *self = SecretKeyOptional::None,
                SecretKeyOptionalType::Value => {
                    *self = SecretKeyOptional::Value(Default::default())
                }
                SecretKeyOptionalType::EnvironmentVariable => {
                    *self = SecretKeyOptional::EnvironmentVariable(Default::default())
                }
                SecretKeyOptionalType::File => *self = SecretKeyOptional::File(Default::default()),
            }
        }
        match self {
            SecretKeyOptional::None => pointer.assert_eof(),
            SecretKeyOptional::Value(inner) => inner.patch(pointer, value),
            SecretKeyOptional::EnvironmentVariable(inner) => inner.patch(pointer, value),
            SecretKeyOptional::File(inner) => inner.patch(pointer, value),
        }
    }
}

impl SecretKeyOptional {
    pub fn object_type(&self) -> SecretKeyOptionalType {
        match self {
            SecretKeyOptional::None => SecretKeyOptionalType::None,
            SecretKeyOptional::Value(_) => SecretKeyOptionalType::Value,
            SecretKeyOptional::EnvironmentVariable(_) => SecretKeyOptionalType::EnvironmentVariable,
            SecretKeyOptional::File(_) => SecretKeyOptionalType::File,
        }
    }
}

impl SecretKeyValue {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        errors.len() == neb
    }
}

impl Pickle for SecretKeyValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SecretKeyValue {
    fn default() -> Self {
        Self {
            secret: Default::default(),
        }
    }
}

impl IntoValue for SecretKeyValue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SecretKeyValue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SecretText {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SecretText::Text(inner) => inner.validate(errors),
            SecretText::EnvironmentVariable(inner) => inner.validate(errors),
            SecretText::File(inner) => inner.validate(errors),
        }
    }
}

impl Default for SecretText {
    fn default() -> Self {
        SecretText::Text(Default::default())
    }
}

impl Pickle for SecretText {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SecretText::Text(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SecretText::EnvironmentVariable(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SecretText::File(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SecretText::Text),
            1 => Pickle::unpickle(stream).map(SecretText::EnvironmentVariable),
            2 => Pickle::unpickle(stream).map(SecretText::File),
            _ => None,
        }
    }
}

impl IntoValue for SecretText {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SecretText::Text(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Text".into()));
                obj
            }
            SecretText::EnvironmentVariable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnvironmentVariable".into()));
                obj
            }
            SecretText::File(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("File".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SecretText {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SecretTextType::Text => *self = SecretText::Text(Default::default()),
                SecretTextType::EnvironmentVariable => {
                    *self = SecretText::EnvironmentVariable(Default::default())
                }
                SecretTextType::File => *self = SecretText::File(Default::default()),
            }
        }
        match self {
            SecretText::Text(inner) => inner.patch(pointer, value),
            SecretText::EnvironmentVariable(inner) => inner.patch(pointer, value),
            SecretText::File(inner) => inner.patch(pointer, value),
        }
    }
}

impl SecretText {
    pub fn object_type(&self) -> SecretTextType {
        match self {
            SecretText::Text(_) => SecretTextType::Text,
            SecretText::EnvironmentVariable(_) => SecretTextType::EnvironmentVariable,
            SecretText::File(_) => SecretTextType::File,
        }
    }
}

impl SecretTextOptional {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SecretTextOptional::None => true,
            SecretTextOptional::Text(inner) => inner.validate(errors),
            SecretTextOptional::EnvironmentVariable(inner) => inner.validate(errors),
            SecretTextOptional::File(inner) => inner.validate(errors),
        }
    }
}

impl Default for SecretTextOptional {
    fn default() -> Self {
        SecretTextOptional::None
    }
}

impl Pickle for SecretTextOptional {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SecretTextOptional::None => {
                0u16.pickle(out);
            }
            SecretTextOptional::Text(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SecretTextOptional::EnvironmentVariable(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SecretTextOptional::File(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SecretTextOptional::None),
            1 => Pickle::unpickle(stream).map(SecretTextOptional::Text),
            2 => Pickle::unpickle(stream).map(SecretTextOptional::EnvironmentVariable),
            3 => Pickle::unpickle(stream).map(SecretTextOptional::File),
            _ => None,
        }
    }
}

impl IntoValue for SecretTextOptional {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SecretTextOptional::None => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("None".into()));
                JmapValue::Object(obj)
            }
            SecretTextOptional::Text(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Text".into()));
                obj
            }
            SecretTextOptional::EnvironmentVariable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("EnvironmentVariable".into()));
                obj
            }
            SecretTextOptional::File(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("File".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SecretTextOptional {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SecretTextOptionalType::None => *self = SecretTextOptional::None,
                SecretTextOptionalType::Text => {
                    *self = SecretTextOptional::Text(Default::default())
                }
                SecretTextOptionalType::EnvironmentVariable => {
                    *self = SecretTextOptional::EnvironmentVariable(Default::default())
                }
                SecretTextOptionalType::File => {
                    *self = SecretTextOptional::File(Default::default())
                }
            }
        }
        match self {
            SecretTextOptional::None => pointer.assert_eof(),
            SecretTextOptional::Text(inner) => inner.patch(pointer, value),
            SecretTextOptional::EnvironmentVariable(inner) => inner.patch(pointer, value),
            SecretTextOptional::File(inner) => inner.patch(pointer, value),
        }
    }
}

impl SecretTextOptional {
    pub fn object_type(&self) -> SecretTextOptionalType {
        match self {
            SecretTextOptional::None => SecretTextOptionalType::None,
            SecretTextOptional::Text(_) => SecretTextOptionalType::Text,
            SecretTextOptional::EnvironmentVariable(_) => {
                SecretTextOptionalType::EnvironmentVariable
            }
            SecretTextOptional::File(_) => SecretTextOptionalType::File,
        }
    }
}

impl SecretTextValue {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Secret));
        }
        errors.len() == neb
    }
}

impl Pickle for SecretTextValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.secret.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.secret = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SecretTextValue {
    fn default() -> Self {
        Self {
            secret: Default::default(),
        }
    }
}

impl IntoValue for SecretTextValue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Secret, JmapValue::Str(MASKED_PASSWORD.into()));
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SecretTextValue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Secret) => self.secret.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Security {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Security;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.abuse_ban_rate {
            value.validate(errors);
        }
        if let Some(value) = &self.auth_ban_rate {
            value.validate(errors);
        }
        if let Some(value) = &self.loiter_ban_rate {
            value.validate(errors);
        }
        let value = &self.scan_ban_paths;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ScanBanPaths));
            }
        }
        if let Some(value) = &self.scan_ban_rate {
            value.validate(errors);
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Security {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.abuse_ban_rate.pickle(out);
        self.abuse_ban_period.pickle(out);
        self.auth_ban_rate.pickle(out);
        self.auth_ban_period.pickle(out);
        self.loiter_ban_rate.pickle(out);
        self.loiter_ban_period.pickle(out);
        self.scan_ban_paths.pickle(out);
        self.scan_ban_rate.pickle(out);
        self.scan_ban_period.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.abuse_ban_rate = Pickle::unpickle(stream)?;
        this.abuse_ban_period = Pickle::unpickle(stream)?;
        this.auth_ban_rate = Pickle::unpickle(stream)?;
        this.auth_ban_period = Pickle::unpickle(stream)?;
        this.loiter_ban_rate = Pickle::unpickle(stream)?;
        this.loiter_ban_period = Pickle::unpickle(stream)?;
        this.scan_ban_paths = Pickle::unpickle(stream)?;
        this.scan_ban_rate = Pickle::unpickle(stream)?;
        this.scan_ban_period = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Security {
    fn default() -> Self {
        Self {
            abuse_ban_rate: Some(Rate {
                count: 35u64,
                period: Duration::from_millis(86400000),
            }),
            abuse_ban_period: Default::default(),
            auth_ban_rate: Some(Rate {
                count: 100u64,
                period: Duration::from_millis(86400000),
            }),
            auth_ban_period: Default::default(),
            loiter_ban_rate: Some(Rate {
                count: 150u64,
                period: Duration::from_millis(86400000),
            }),
            loiter_ban_period: Default::default(),
            scan_ban_paths: Map::new(vec![
                "*.php*".to_string(),
                "*.cgi*".to_string(),
                "*.asp*".to_string(),
                "*/wp-*".to_string(),
                "*/php*".to_string(),
                "*/cgi-bin*".to_string(),
                "*xmlrpc*".to_string(),
                "*../*".to_string(),
                "*/..*".to_string(),
                "*joomla*".to_string(),
                "*wordpress*".to_string(),
                "*drupal*".to_string(),
            ]),
            scan_ban_rate: Some(Rate {
                count: 30u64,
                period: Duration::from_millis(86400000),
            }),
            scan_ban_period: Default::default(),
        }
    }
}

impl IntoValue for Security {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AbuseBanRate, self.abuse_ban_rate.into_value());
        map.insert_unchecked(Property::AbuseBanPeriod, self.abuse_ban_period.into_value());
        map.insert_unchecked(Property::AuthBanRate, self.auth_ban_rate.into_value());
        map.insert_unchecked(Property::AuthBanPeriod, self.auth_ban_period.into_value());
        map.insert_unchecked(Property::LoiterBanRate, self.loiter_ban_rate.into_value());
        map.insert_unchecked(
            Property::LoiterBanPeriod,
            self.loiter_ban_period.into_value(),
        );
        map.insert_unchecked(Property::ScanBanPaths, self.scan_ban_paths.into_value());
        map.insert_unchecked(Property::ScanBanRate, self.scan_ban_rate.into_value());
        map.insert_unchecked(Property::ScanBanPeriod, self.scan_ban_period.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Security {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AbuseBanRate) => self.abuse_ban_rate.patch(pointer, value),
            Some(Property::AbuseBanPeriod) => self.abuse_ban_period.patch(pointer, value),
            Some(Property::AuthBanRate) => self.auth_ban_rate.patch(pointer, value),
            Some(Property::AuthBanPeriod) => self.auth_ban_period.patch(pointer, value),
            Some(Property::LoiterBanRate) => self.loiter_ban_rate.patch(pointer, value),
            Some(Property::LoiterBanPeriod) => self.loiter_ban_period.patch(pointer, value),
            Some(Property::ScanBanPaths) => self
                .scan_ban_paths
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ScanBanRate) => self.scan_ban_rate.patch(pointer, value),
            Some(Property::ScanBanPeriod) => self.scan_ban_period.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SenderAuth {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SenderAuth;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        let value = &self.dkim_verify;
        value.validate(errors);
        let value = &self.spf_ehlo_verify;
        value.validate(errors);
        let value = &self.spf_from_verify;
        value.validate(errors);
        let value = &self.arc_verify;
        value.validate(errors);
        let value = &self.dmarc_verify;
        value.validate(errors);
        let value = &self.reverse_ip_verify;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl SenderAuth {
    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "is_local_domain(sender_domain) && !is_empty(authenticated_as)"
                        .to_string(),
                    then: "sender_domain".to_string(),
                }]),
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dkim_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_verify,
            default: Some(Expression {
                else_: "relaxed".to_string(),
                match_: List::from_iter([]),
            }),
            property: Property::DkimVerify,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn ctx_spf_ehlo_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.spf_ehlo_verify,
            default: Some(Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            }),
            property: Property::SpfEhloVerify,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn ctx_spf_from_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.spf_from_verify,
            default: Some(Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            }),
            property: Property::SpfFromVerify,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn ctx_arc_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.arc_verify,
            default: Some(Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([]),
            }),
            property: Property::ArcVerify,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn ctx_dmarc_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dmarc_verify,
            default: Some(Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            }),
            property: Property::DmarcVerify,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn ctx_reverse_ip_verify(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.reverse_ip_verify,
            default: Some(Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            }),
            property: Property::ReverseIpVerify,
            allowed_variables: MTA_CONNECTION_VARIABLE,
            allowed_constants: MTA_VERIFY_CONSTANT,
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_dkim_sign_domain(),
            self.ctx_dkim_verify(),
            self.ctx_spf_ehlo_verify(),
            self.ctx_spf_from_verify(),
            self.ctx_arc_verify(),
            self.ctx_dmarc_verify(),
            self.ctx_reverse_ip_verify(),
        ]
    }
}

impl Pickle for SenderAuth {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.dkim_sign_domain.pickle(out);
        self.dkim_strict.pickle(out);
        self.dkim_verify.pickle(out);
        self.spf_ehlo_verify.pickle(out);
        self.spf_from_verify.pickle(out);
        self.arc_verify.pickle(out);
        self.dmarc_verify.pickle(out);
        self.reverse_ip_verify.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        this.dkim_strict = Pickle::unpickle(stream)?;
        this.dkim_verify = Pickle::unpickle(stream)?;
        this.spf_ehlo_verify = Pickle::unpickle(stream)?;
        this.spf_from_verify = Pickle::unpickle(stream)?;
        this.arc_verify = Pickle::unpickle(stream)?;
        this.dmarc_verify = Pickle::unpickle(stream)?;
        this.reverse_ip_verify = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SenderAuth {
    fn default() -> Self {
        Self {
            dkim_sign_domain: Expression {
                else_: "false".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "is_local_domain(sender_domain) && !is_empty(authenticated_as)"
                        .to_string(),
                    then: "sender_domain".to_string(),
                }]),
            },
            dkim_strict: true,
            dkim_verify: Expression {
                else_: "relaxed".to_string(),
                match_: List::from_iter([]),
            },
            spf_ehlo_verify: Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            },
            spf_from_verify: Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            },
            arc_verify: Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([]),
            },
            dmarc_verify: Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            },
            reverse_ip_verify: Expression {
                else_: "disable".to_string(),
                match_: List::from_iter([ExpressionMatch {
                    if_: "local_port == 25".to_string(),
                    then: "relaxed".to_string(),
                }]),
            },
        }
    }
}

impl IntoValue for SenderAuth {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        map.insert_unchecked(Property::DkimStrict, self.dkim_strict.into_value());
        map.insert_unchecked(Property::DkimVerify, self.dkim_verify.into_value());
        map.insert_unchecked(Property::SpfEhloVerify, self.spf_ehlo_verify.into_value());
        map.insert_unchecked(Property::SpfFromVerify, self.spf_from_verify.into_value());
        map.insert_unchecked(Property::ArcVerify, self.arc_verify.into_value());
        map.insert_unchecked(Property::DmarcVerify, self.dmarc_verify.into_value());
        map.insert_unchecked(
            Property::ReverseIpVerify,
            self.reverse_ip_verify.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SenderAuth {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::DkimStrict) => self.dkim_strict.patch(pointer, value),
            Some(Property::DkimVerify) => self.dkim_verify.patch(pointer, value),
            Some(Property::SpfEhloVerify) => self.spf_ehlo_verify.patch(pointer, value),
            Some(Property::SpfFromVerify) => self.spf_from_verify.patch(pointer, value),
            Some(Property::ArcVerify) => self.arc_verify.patch(pointer, value),
            Some(Property::DmarcVerify) => self.dmarc_verify.patch(pointer, value),
            Some(Property::ReverseIpVerify) => self.reverse_ip_verify.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ServerResponse {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.response_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseHostname));
            }
        }
        if let Some(value) = &self.response_code {
            if *value < 100 {
                errors.push(ValidationError::min_value(Property::ResponseCode, 100));
            }
            if *value > 599 {
                errors.push(ValidationError::max_value(Property::ResponseCode, 599));
            }
        }
        if let Some(value) = &self.response_enhanced {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseEnhanced));
            }
        }
        if let Some(value) = &self.response_message {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ResponseMessage));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for ServerResponse {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.response_hostname.pickle(out);
        self.response_code.pickle(out);
        self.response_enhanced.pickle(out);
        self.response_message.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.response_hostname = Pickle::unpickle(stream)?;
        this.response_code = Pickle::unpickle(stream)?;
        this.response_enhanced = Pickle::unpickle(stream)?;
        this.response_message = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ServerResponse {
    fn default() -> Self {
        Self {
            response_hostname: Default::default(),
            response_code: Default::default(),
            response_enhanced: Default::default(),
            response_message: Default::default(),
        }
    }
}

impl IntoValue for ServerResponse {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(
            Property::ResponseHostname,
            self.response_hostname.into_value(),
        );
        map.insert_unchecked(Property::ResponseCode, self.response_code.into_value());
        map.insert_unchecked(
            Property::ResponseEnhanced,
            self.response_enhanced.into_value(),
        );
        map.insert_unchecked(
            Property::ResponseMessage,
            self.response_message.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ServerResponse {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ResponseHostname) => self.response_hostname.patch(pointer, value),
            Some(Property::ResponseCode) => self.response_code.patch(pointer, value),
            Some(Property::ResponseEnhanced) => self.response_enhanced.patch(pointer, value),
            Some(Property::ResponseMessage) => self.response_message.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl Service {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Hostname));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for Service {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.hostname.pickle(out);
        self.cleartext.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.hostname = Pickle::unpickle(stream)?;
        this.cleartext = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Service {
    fn default() -> Self {
        Self {
            hostname: Default::default(),
            cleartext: false,
        }
    }
}

impl IntoValue for Service {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Hostname, self.hostname.into_value());
        map.insert_unchecked(Property::Cleartext, self.cleartext.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Service {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Hostname) => self
                .hostname
                .patch(pointer.with_validators(&[StringValidator::Hostname]), value),
            Some(Property::Cleartext) => self.cleartext.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ShardedBlobStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.stores;
        for value in value.values() {
            value.validate(errors);
        }
        if value.len() < 2 {
            errors.push(ValidationError::min_items(Property::Stores, 2));
        }
        errors.len() == neb
    }
}

impl Pickle for ShardedBlobStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.stores.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.stores = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ShardedBlobStore {
    fn default() -> Self {
        Self {
            stores: Default::default(),
        }
    }
}

impl IntoValue for ShardedBlobStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Stores, self.stores.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ShardedBlobStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Stores) => self.stores.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ShardedInMemoryStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.stores;
        for value in value.values() {
            value.validate(errors);
        }
        if value.len() < 2 {
            errors.push(ValidationError::min_items(Property::Stores, 2));
        }
        errors.len() == neb
    }
}

impl Pickle for ShardedInMemoryStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.stores.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.stores = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ShardedInMemoryStore {
    fn default() -> Self {
        Self {
            stores: Default::default(),
        }
    }
}

impl IntoValue for ShardedInMemoryStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Stores, self.stores.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ShardedInMemoryStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Stores) => self.stores.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Sharing {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Sharing;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_shares;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxShares, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Sharing {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_directory_queries.pickle(out);
        self.max_shares.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_directory_queries = Pickle::unpickle(stream)?;
        this.max_shares = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Sharing {
    fn default() -> Self {
        Self {
            allow_directory_queries: false,
            max_shares: 10u64,
        }
    }
}

impl IntoValue for Sharing {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(
            Property::AllowDirectoryQueries,
            self.allow_directory_queries.into_value(),
        );
        map.insert_unchecked(Property::MaxShares, self.max_shares.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Sharing {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowDirectoryQueries) => {
                self.allow_directory_queries.patch(pointer, value)
            }
            Some(Property::MaxShares) => self.max_shares.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SieveSystemInterpreter {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SieveSystemInterpreter;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.default_from_address;
        value.validate(errors);
        let value = &self.default_from_name;
        value.validate(errors);
        if let Some(value) = &self.message_id_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MessageIdHostname));
            }
        }
        let value = &self.default_return_path;
        value.validate(errors);
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        let value = &self.max_cpu_cycles;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxCpuCycles, 1));
        }
        let value = &self.max_nested_includes;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxNestedIncludes, 1));
        }
        let value = &self.max_received_headers;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxReceivedHeaders, 1));
        }
        let value = &self.max_var_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxVarSize, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl SieveSystemInterpreter {
    pub fn ctx_default_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.default_from_address,
            default: Some(Expression {
                else_: "'MAILER-DAEMON@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DefaultFromAddress,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_default_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.default_from_name,
            default: Some(Expression {
                else_: "'Automated Message'".to_string(),
                ..Default::default()
            }),
            property: Property::DefaultFromName,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_default_return_path(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.default_return_path,
            default: None,
            property: Property::DefaultReturnPath,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_RCPT_TO_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_default_from_address(),
            self.ctx_default_from_name(),
            self.ctx_default_return_path(),
            self.ctx_dkim_sign_domain(),
        ]
    }
}

impl Pickle for SieveSystemInterpreter {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.default_from_address.pickle(out);
        self.default_from_name.pickle(out);
        self.message_id_hostname.pickle(out);
        self.duplicate_expiry.pickle(out);
        self.no_capability_check.pickle(out);
        self.default_return_path.pickle(out);
        self.dkim_sign_domain.pickle(out);
        self.max_cpu_cycles.pickle(out);
        self.max_nested_includes.pickle(out);
        self.max_out_messages.pickle(out);
        self.max_received_headers.pickle(out);
        self.max_redirects.pickle(out);
        self.max_var_size.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.default_from_address = Pickle::unpickle(stream)?;
        this.default_from_name = Pickle::unpickle(stream)?;
        this.message_id_hostname = Pickle::unpickle(stream)?;
        this.duplicate_expiry = Pickle::unpickle(stream)?;
        this.no_capability_check = Pickle::unpickle(stream)?;
        this.default_return_path = Pickle::unpickle(stream)?;
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        this.max_cpu_cycles = Pickle::unpickle(stream)?;
        this.max_nested_includes = Pickle::unpickle(stream)?;
        this.max_out_messages = Pickle::unpickle(stream)?;
        this.max_received_headers = Pickle::unpickle(stream)?;
        this.max_redirects = Pickle::unpickle(stream)?;
        this.max_var_size = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SieveSystemInterpreter {
    fn default() -> Self {
        Self {
            default_from_address: Expression {
                else_: "'MAILER-DAEMON@' + system('domain')".to_string(),
                ..Default::default()
            },
            default_from_name: Expression {
                else_: "'Automated Message'".to_string(),
                ..Default::default()
            },
            message_id_hostname: Default::default(),
            duplicate_expiry: Duration::from_millis(604800000),
            no_capability_check: true,
            default_return_path: Default::default(),
            dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            max_cpu_cycles: 1048576u64,
            max_nested_includes: 5u64,
            max_out_messages: 5u64,
            max_received_headers: 50u64,
            max_redirects: 3u64,
            max_var_size: 52428800u64,
        }
    }
}

impl IntoValue for SieveSystemInterpreter {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(
            Property::DefaultFromAddress,
            self.default_from_address.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultFromName,
            self.default_from_name.into_value(),
        );
        map.insert_unchecked(
            Property::MessageIdHostname,
            self.message_id_hostname.into_value(),
        );
        map.insert_unchecked(
            Property::DuplicateExpiry,
            self.duplicate_expiry.into_value(),
        );
        map.insert_unchecked(
            Property::NoCapabilityCheck,
            self.no_capability_check.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultReturnPath,
            self.default_return_path.into_value(),
        );
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        map.insert_unchecked(Property::MaxCpuCycles, self.max_cpu_cycles.into_value());
        map.insert_unchecked(
            Property::MaxNestedIncludes,
            self.max_nested_includes.into_value(),
        );
        map.insert_unchecked(Property::MaxOutMessages, self.max_out_messages.into_value());
        map.insert_unchecked(
            Property::MaxReceivedHeaders,
            self.max_received_headers.into_value(),
        );
        map.insert_unchecked(Property::MaxRedirects, self.max_redirects.into_value());
        map.insert_unchecked(Property::MaxVarSize, self.max_var_size.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SieveSystemInterpreter {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DefaultFromAddress) => self.default_from_address.patch(pointer, value),
            Some(Property::DefaultFromName) => self.default_from_name.patch(pointer, value),
            Some(Property::MessageIdHostname) => self
                .message_id_hostname
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DuplicateExpiry) => self.duplicate_expiry.patch(pointer, value),
            Some(Property::NoCapabilityCheck) => self.no_capability_check.patch(pointer, value),
            Some(Property::DefaultReturnPath) => self.default_return_path.patch(pointer, value),
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::MaxCpuCycles) => self.max_cpu_cycles.patch(pointer, value),
            Some(Property::MaxNestedIncludes) => self.max_nested_includes.patch(pointer, value),
            Some(Property::MaxOutMessages) => self.max_out_messages.patch(pointer, value),
            Some(Property::MaxReceivedHeaders) => self.max_received_headers.patch(pointer, value),
            Some(Property::MaxRedirects) => self.max_redirects.patch(pointer, value),
            Some(Property::MaxVarSize) => self.max_var_size.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SieveSystemScript {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SieveSystemScript;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.contents;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Contents));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for SieveSystemScript {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.is_active.pickle(out);
        self.contents.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.is_active = Pickle::unpickle(stream)?;
        this.contents = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SieveSystemScript {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            is_active: false,
            contents: Default::default(),
        }
    }
}

impl IntoValue for SieveSystemScript {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::IsActive, self.is_active.into_value());
        map.insert_unchecked(Property::Contents, self.contents.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SieveSystemScript {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self
                .name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::IsActive) => self.is_active.patch(pointer, value),
            Some(Property::Contents) => self
                .contents
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SieveUserInterpreter {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SieveUserInterpreter;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.allowed_notify_uris;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AllowedNotifyUris));
            }
        }
        let value = &self.protected_headers;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ProtectedHeaders));
            }
        }
        let value = &self.default_subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultSubject));
        }
        let value = &self.default_subject_prefix;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultSubjectPrefix));
        }
        let value = &self.max_cpu_cycles;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxCpuCycles, 1));
        }
        let value = &self.max_header_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxHeaderSize, 1));
        }
        let value = &self.max_includes;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxIncludes, 1));
        }
        let value = &self.max_local_vars;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxLocalVars, 1));
        }
        let value = &self.max_match_vars;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxMatchVars, 1));
        }
        let value = &self.max_script_name_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxScriptNameLength, 1));
        }
        let value = &self.max_nested_blocks;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxNestedBlocks, 1));
        }
        let value = &self.max_nested_for_every;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxNestedForEvery, 1));
        }
        let value = &self.max_nested_includes;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxNestedIncludes, 1));
        }
        let value = &self.max_nested_tests;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxNestedTests, 1));
        }
        let value = &self.max_received_headers;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxReceivedHeaders, 1));
        }
        let value = &self.max_script_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxScriptSize, 1));
        }
        let value = &self.max_string_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxStringLength, 1));
        }
        let value = &self.max_var_name_length;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxVarNameLength, 1));
        }
        let value = &self.max_var_size;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxVarSize, 1));
        }
        if let Some(value) = &self.max_scripts {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::MaxScripts, 1));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for SieveUserInterpreter {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.default_expiry_duplicate.pickle(out);
        self.default_expiry_vacation.pickle(out);
        self.disable_capabilities.pickle(out);
        self.allowed_notify_uris.pickle(out);
        self.protected_headers.pickle(out);
        self.default_subject.pickle(out);
        self.default_subject_prefix.pickle(out);
        self.max_cpu_cycles.pickle(out);
        self.max_header_size.pickle(out);
        self.max_includes.pickle(out);
        self.max_local_vars.pickle(out);
        self.max_match_vars.pickle(out);
        self.max_script_name_length.pickle(out);
        self.max_nested_blocks.pickle(out);
        self.max_nested_for_every.pickle(out);
        self.max_nested_includes.pickle(out);
        self.max_nested_tests.pickle(out);
        self.max_out_messages.pickle(out);
        self.max_received_headers.pickle(out);
        self.max_redirects.pickle(out);
        self.max_script_size.pickle(out);
        self.max_string_length.pickle(out);
        self.max_var_name_length.pickle(out);
        self.max_var_size.pickle(out);
        self.max_scripts.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.default_expiry_duplicate = Pickle::unpickle(stream)?;
        this.default_expiry_vacation = Pickle::unpickle(stream)?;
        this.disable_capabilities = Pickle::unpickle(stream)?;
        this.allowed_notify_uris = Pickle::unpickle(stream)?;
        this.protected_headers = Pickle::unpickle(stream)?;
        this.default_subject = Pickle::unpickle(stream)?;
        this.default_subject_prefix = Pickle::unpickle(stream)?;
        this.max_cpu_cycles = Pickle::unpickle(stream)?;
        this.max_header_size = Pickle::unpickle(stream)?;
        this.max_includes = Pickle::unpickle(stream)?;
        this.max_local_vars = Pickle::unpickle(stream)?;
        this.max_match_vars = Pickle::unpickle(stream)?;
        this.max_script_name_length = Pickle::unpickle(stream)?;
        this.max_nested_blocks = Pickle::unpickle(stream)?;
        this.max_nested_for_every = Pickle::unpickle(stream)?;
        this.max_nested_includes = Pickle::unpickle(stream)?;
        this.max_nested_tests = Pickle::unpickle(stream)?;
        this.max_out_messages = Pickle::unpickle(stream)?;
        this.max_received_headers = Pickle::unpickle(stream)?;
        this.max_redirects = Pickle::unpickle(stream)?;
        this.max_script_size = Pickle::unpickle(stream)?;
        this.max_string_length = Pickle::unpickle(stream)?;
        this.max_var_name_length = Pickle::unpickle(stream)?;
        this.max_var_size = Pickle::unpickle(stream)?;
        this.max_scripts = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SieveUserInterpreter {
    fn default() -> Self {
        Self {
            default_expiry_duplicate: Duration::from_millis(604800000),
            default_expiry_vacation: Duration::from_millis(2592000000),
            disable_capabilities: Default::default(),
            allowed_notify_uris: Map::new(vec!["mailto".to_string()]),
            protected_headers: Map::new(vec![
                "Original-Subject".to_string(),
                "Original-From".to_string(),
                "Received".to_string(),
                "Auto-Submitted".to_string(),
            ]),
            default_subject: "Automated reply".to_string(),
            default_subject_prefix: "Auto: ".to_string(),
            max_cpu_cycles: 5000u64,
            max_header_size: 1024u64,
            max_includes: 3u64,
            max_local_vars: 128u64,
            max_match_vars: 30u64,
            max_script_name_length: 512u64,
            max_nested_blocks: 15u64,
            max_nested_for_every: 3u64,
            max_nested_includes: 3u64,
            max_nested_tests: 15u64,
            max_out_messages: 3u64,
            max_received_headers: 10u64,
            max_redirects: 1u64,
            max_script_size: 102400,
            max_string_length: 4096u64,
            max_var_name_length: 32u64,
            max_var_size: 4096u64,
            max_scripts: Some(100u64),
        }
    }
}

impl IntoValue for SieveUserInterpreter {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(27);
        map.insert_unchecked(
            Property::DefaultExpiryDuplicate,
            self.default_expiry_duplicate.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultExpiryVacation,
            self.default_expiry_vacation.into_value(),
        );
        map.insert_unchecked(
            Property::DisableCapabilities,
            self.disable_capabilities.into_value(),
        );
        map.insert_unchecked(
            Property::AllowedNotifyUris,
            self.allowed_notify_uris.into_value(),
        );
        map.insert_unchecked(
            Property::ProtectedHeaders,
            self.protected_headers.into_value(),
        );
        map.insert_unchecked(Property::DefaultSubject, self.default_subject.into_value());
        map.insert_unchecked(
            Property::DefaultSubjectPrefix,
            self.default_subject_prefix.into_value(),
        );
        map.insert_unchecked(Property::MaxCpuCycles, self.max_cpu_cycles.into_value());
        map.insert_unchecked(Property::MaxHeaderSize, self.max_header_size.into_value());
        map.insert_unchecked(Property::MaxIncludes, self.max_includes.into_value());
        map.insert_unchecked(Property::MaxLocalVars, self.max_local_vars.into_value());
        map.insert_unchecked(Property::MaxMatchVars, self.max_match_vars.into_value());
        map.insert_unchecked(
            Property::MaxScriptNameLength,
            self.max_script_name_length.into_value(),
        );
        map.insert_unchecked(
            Property::MaxNestedBlocks,
            self.max_nested_blocks.into_value(),
        );
        map.insert_unchecked(
            Property::MaxNestedForEvery,
            self.max_nested_for_every.into_value(),
        );
        map.insert_unchecked(
            Property::MaxNestedIncludes,
            self.max_nested_includes.into_value(),
        );
        map.insert_unchecked(Property::MaxNestedTests, self.max_nested_tests.into_value());
        map.insert_unchecked(Property::MaxOutMessages, self.max_out_messages.into_value());
        map.insert_unchecked(
            Property::MaxReceivedHeaders,
            self.max_received_headers.into_value(),
        );
        map.insert_unchecked(Property::MaxRedirects, self.max_redirects.into_value());
        map.insert_unchecked(Property::MaxScriptSize, self.max_script_size.into_value());
        map.insert_unchecked(
            Property::MaxStringLength,
            self.max_string_length.into_value(),
        );
        map.insert_unchecked(
            Property::MaxVarNameLength,
            self.max_var_name_length.into_value(),
        );
        map.insert_unchecked(Property::MaxVarSize, self.max_var_size.into_value());
        map.insert_unchecked(Property::MaxScripts, self.max_scripts.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SieveUserInterpreter {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DefaultExpiryDuplicate) => {
                self.default_expiry_duplicate.patch(pointer, value)
            }
            Some(Property::DefaultExpiryVacation) => {
                self.default_expiry_vacation.patch(pointer, value)
            }
            Some(Property::DisableCapabilities) => self.disable_capabilities.patch(pointer, value),
            Some(Property::AllowedNotifyUris) => self
                .allowed_notify_uris
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ProtectedHeaders) => self
                .protected_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DefaultSubject) => self
                .default_subject
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::DefaultSubjectPrefix) => {
                self.default_subject_prefix.patch(pointer, value)
            }
            Some(Property::MaxCpuCycles) => self.max_cpu_cycles.patch(pointer, value),
            Some(Property::MaxHeaderSize) => self.max_header_size.patch(pointer, value),
            Some(Property::MaxIncludes) => self.max_includes.patch(pointer, value),
            Some(Property::MaxLocalVars) => self.max_local_vars.patch(pointer, value),
            Some(Property::MaxMatchVars) => self.max_match_vars.patch(pointer, value),
            Some(Property::MaxScriptNameLength) => {
                self.max_script_name_length.patch(pointer, value)
            }
            Some(Property::MaxNestedBlocks) => self.max_nested_blocks.patch(pointer, value),
            Some(Property::MaxNestedForEvery) => self.max_nested_for_every.patch(pointer, value),
            Some(Property::MaxNestedIncludes) => self.max_nested_includes.patch(pointer, value),
            Some(Property::MaxNestedTests) => self.max_nested_tests.patch(pointer, value),
            Some(Property::MaxOutMessages) => self.max_out_messages.patch(pointer, value),
            Some(Property::MaxReceivedHeaders) => self.max_received_headers.patch(pointer, value),
            Some(Property::MaxRedirects) => self.max_redirects.patch(pointer, value),
            Some(Property::MaxScriptSize) => self.max_script_size.patch(pointer, value),
            Some(Property::MaxStringLength) => self.max_string_length.patch(pointer, value),
            Some(Property::MaxVarNameLength) => self.max_var_name_length.patch(pointer, value),
            Some(Property::MaxVarSize) => self.max_var_size.patch(pointer, value),
            Some(Property::MaxScripts) => self.max_scripts.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SieveUserScript {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SieveUserScript;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.contents;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Contents));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl Pickle for SieveUserScript {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.description.pickle(out);
        self.is_active.pickle(out);
        self.contents.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.is_active = Pickle::unpickle(stream)?;
        this.contents = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SieveUserScript {
    fn default() -> Self {
        Self {
            name: Default::default(),
            description: Default::default(),
            is_active: false,
            contents: Default::default(),
        }
    }
}

impl IntoValue for SieveUserScript {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::IsActive, self.is_active.into_value());
        map.insert_unchecked(Property::Contents, self.contents.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SieveUserScript {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self
                .name
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::IsActive) => self.is_active.patch(pointer, value),
            Some(Property::Contents) => self
                .contents
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamClassifier {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamClassifier;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.model;
        value.validate(errors);
        let value = &self.learn_spam_from_rbl_hits;
        if *value > 100 {
            errors.push(ValidationError::max_value(
                Property::LearnSpamFromRblHits,
                100,
            ));
        }
        let value = &self.min_ham_samples;
        if *value > 10000 {
            errors.push(ValidationError::max_value(Property::MinHamSamples, 10000));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MinHamSamples, 1));
        }
        let value = &self.min_spam_samples;
        if *value > 10000 {
            errors.push(ValidationError::max_value(Property::MinSpamSamples, 10000));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MinSpamSamples, 1));
        }
        let value = &self.reservoir_capacity;
        if *value > 100000 {
            errors.push(ValidationError::max_value(
                Property::ReservoirCapacity,
                100000,
            ));
        }
        if *value < 100 {
            errors.push(ValidationError::min_value(Property::ReservoirCapacity, 100));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for SpamClassifier {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.model.pickle(out);
        self.learn_ham_from_card.pickle(out);
        self.learn_spam_from_rbl_hits.pickle(out);
        self.learn_spam_from_traps.pickle(out);
        self.hold_samples_for.pickle(out);
        self.min_ham_samples.pickle(out);
        self.min_spam_samples.pickle(out);
        self.reservoir_capacity.pickle(out);
        self.train_frequency.pickle(out);
        self.learn_ham_from_reply.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.model = Pickle::unpickle(stream)?;
        this.learn_ham_from_card = Pickle::unpickle(stream)?;
        this.learn_spam_from_rbl_hits = Pickle::unpickle(stream)?;
        this.learn_spam_from_traps = Pickle::unpickle(stream)?;
        this.hold_samples_for = Pickle::unpickle(stream)?;
        this.min_ham_samples = Pickle::unpickle(stream)?;
        this.min_spam_samples = Pickle::unpickle(stream)?;
        this.reservoir_capacity = Pickle::unpickle(stream)?;
        this.train_frequency = Pickle::unpickle(stream)?;
        this.learn_ham_from_reply = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamClassifier {
    fn default() -> Self {
        Self {
            model: Default::default(),
            learn_ham_from_card: true,
            learn_spam_from_rbl_hits: 2u64,
            learn_spam_from_traps: true,
            hold_samples_for: Duration::from_millis(15552000000),
            min_ham_samples: 100u64,
            min_spam_samples: 100u64,
            reservoir_capacity: 1024u64,
            train_frequency: Some(Duration::from_millis(43200000)),
            learn_ham_from_reply: true,
        }
    }
}

impl IntoValue for SpamClassifier {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Model, self.model.into_value());
        map.insert_unchecked(
            Property::LearnHamFromCard,
            self.learn_ham_from_card.into_value(),
        );
        map.insert_unchecked(
            Property::LearnSpamFromRblHits,
            self.learn_spam_from_rbl_hits.into_value(),
        );
        map.insert_unchecked(
            Property::LearnSpamFromTraps,
            self.learn_spam_from_traps.into_value(),
        );
        map.insert_unchecked(Property::HoldSamplesFor, self.hold_samples_for.into_value());
        map.insert_unchecked(Property::MinHamSamples, self.min_ham_samples.into_value());
        map.insert_unchecked(Property::MinSpamSamples, self.min_spam_samples.into_value());
        map.insert_unchecked(
            Property::ReservoirCapacity,
            self.reservoir_capacity.into_value(),
        );
        map.insert_unchecked(Property::TrainFrequency, self.train_frequency.into_value());
        map.insert_unchecked(
            Property::LearnHamFromReply,
            self.learn_ham_from_reply.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamClassifier {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Model) => self.model.patch(pointer, value),
            Some(Property::LearnHamFromCard) => self.learn_ham_from_card.patch(pointer, value),
            Some(Property::LearnSpamFromRblHits) => {
                self.learn_spam_from_rbl_hits.patch(pointer, value)
            }
            Some(Property::LearnSpamFromTraps) => self.learn_spam_from_traps.patch(pointer, value),
            Some(Property::HoldSamplesFor) => self.hold_samples_for.patch(pointer, value),
            Some(Property::MinHamSamples) => self.min_ham_samples.patch(pointer, value),
            Some(Property::MinSpamSamples) => self.min_spam_samples.patch(pointer, value),
            Some(Property::ReservoirCapacity) => self.reservoir_capacity.patch(pointer, value),
            Some(Property::TrainFrequency) => self.train_frequency.patch(pointer, value),
            Some(Property::LearnHamFromReply) => self.learn_ham_from_reply.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamClassifierFtrlCcfh {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.indicator_parameters;
        value.validate(errors);
        let value = &self.parameters;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for SpamClassifierFtrlCcfh {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.indicator_parameters.pickle(out);
        self.parameters.pickle(out);
        self.feature_l2_normalize.pickle(out);
        self.feature_log_scale.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.indicator_parameters = Pickle::unpickle(stream)?;
        this.parameters = Pickle::unpickle(stream)?;
        this.feature_l2_normalize = Pickle::unpickle(stream)?;
        this.feature_log_scale = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamClassifierFtrlCcfh {
    fn default() -> Self {
        Self {
            indicator_parameters: FtrlParameters {
                num_features: ModelSize::V18,
                ..Default::default()
            },
            parameters: FtrlParameters {
                num_features: ModelSize::V20,
                ..Default::default()
            },
            feature_l2_normalize: true,
            feature_log_scale: true,
        }
    }
}

impl IntoValue for SpamClassifierFtrlCcfh {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(
            Property::IndicatorParameters,
            self.indicator_parameters.into_value(),
        );
        map.insert_unchecked(Property::Parameters, self.parameters.into_value());
        map.insert_unchecked(
            Property::FeatureL2Normalize,
            self.feature_l2_normalize.into_value(),
        );
        map.insert_unchecked(
            Property::FeatureLogScale,
            self.feature_log_scale.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamClassifierFtrlCcfh {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::IndicatorParameters) => self.indicator_parameters.patch(pointer, value),
            Some(Property::Parameters) => self.parameters.patch(pointer, value),
            Some(Property::FeatureL2Normalize) => self.feature_l2_normalize.patch(pointer, value),
            Some(Property::FeatureLogScale) => self.feature_log_scale.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamClassifierFtrlFh {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.parameters;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for SpamClassifierFtrlFh {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.parameters.pickle(out);
        self.feature_l2_normalize.pickle(out);
        self.feature_log_scale.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.parameters = Pickle::unpickle(stream)?;
        this.feature_l2_normalize = Pickle::unpickle(stream)?;
        this.feature_log_scale = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamClassifierFtrlFh {
    fn default() -> Self {
        Self {
            parameters: FtrlParameters {
                num_features: ModelSize::V20,
                ..Default::default()
            },
            feature_l2_normalize: true,
            feature_log_scale: true,
        }
    }
}

impl IntoValue for SpamClassifierFtrlFh {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Parameters, self.parameters.into_value());
        map.insert_unchecked(
            Property::FeatureL2Normalize,
            self.feature_l2_normalize.into_value(),
        );
        map.insert_unchecked(
            Property::FeatureLogScale,
            self.feature_log_scale.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamClassifierFtrlFh {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Parameters) => self.parameters.patch(pointer, value),
            Some(Property::FeatureL2Normalize) => self.feature_l2_normalize.patch(pointer, value),
            Some(Property::FeatureLogScale) => self.feature_log_scale.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamClassifierModel {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SpamClassifierModel::FtrlFh(inner) => inner.validate(errors),
            SpamClassifierModel::FtrlCcfh(inner) => inner.validate(errors),
            SpamClassifierModel::Disabled => true,
        }
    }
}

impl Default for SpamClassifierModel {
    fn default() -> Self {
        SpamClassifierModel::FtrlFh(Default::default())
    }
}

impl Pickle for SpamClassifierModel {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SpamClassifierModel::FtrlFh(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SpamClassifierModel::FtrlCcfh(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SpamClassifierModel::Disabled => {
                2u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SpamClassifierModel::FtrlFh),
            1 => Pickle::unpickle(stream).map(SpamClassifierModel::FtrlCcfh),
            2 => Some(SpamClassifierModel::Disabled),
            _ => None,
        }
    }
}

impl IntoValue for SpamClassifierModel {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SpamClassifierModel::FtrlFh(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FtrlFh".into()));
                obj
            }
            SpamClassifierModel::FtrlCcfh(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FtrlCcfh".into()));
                obj
            }
            SpamClassifierModel::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for SpamClassifierModel {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SpamClassifierModelType::FtrlFh => {
                    *self = SpamClassifierModel::FtrlFh(Default::default())
                }
                SpamClassifierModelType::FtrlCcfh => {
                    *self = SpamClassifierModel::FtrlCcfh(Default::default())
                }
                SpamClassifierModelType::Disabled => *self = SpamClassifierModel::Disabled,
            }
        }
        match self {
            SpamClassifierModel::FtrlFh(inner) => inner.patch(pointer, value),
            SpamClassifierModel::FtrlCcfh(inner) => inner.patch(pointer, value),
            SpamClassifierModel::Disabled => pointer.assert_eof(),
        }
    }
}

impl SpamClassifierModel {
    pub fn object_type(&self) -> SpamClassifierModelType {
        match self {
            SpamClassifierModel::FtrlFh(_) => SpamClassifierModelType::FtrlFh,
            SpamClassifierModel::FtrlCcfh(_) => SpamClassifierModelType::FtrlCcfh,
            SpamClassifierModel::Disabled => SpamClassifierModelType::Disabled,
        }
    }
}

impl SpamClassify {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.message;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Message));
        }
        let value = &self.remote_ip;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::RemoteIp, value));
        }
        let value = &self.ehlo_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::EhloDomain));
        }
        if let Some(value) = &self.authenticated_as {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AuthenticatedAs));
            }
        }
        let value = &self.env_from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::EnvFrom));
        }
        let value = &self.env_rcpt_to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::EnvRcptTo));
            }
        }
        let value = &self.tags;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for SpamClassify {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.message.pickle(out);
        self.remote_ip.pickle(out);
        self.ehlo_domain.pickle(out);
        self.authenticated_as.pickle(out);
        self.is_tls.pickle(out);
        self.env_from.pickle(out);
        self.env_from_parameters.pickle(out);
        self.env_rcpt_to.pickle(out);
        self.score.pickle(out);
        self.tags.pickle(out);
        self.result.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.message = Pickle::unpickle(stream)?;
        this.remote_ip = Pickle::unpickle(stream)?;
        this.ehlo_domain = Pickle::unpickle(stream)?;
        this.authenticated_as = Pickle::unpickle(stream)?;
        this.is_tls = Pickle::unpickle(stream)?;
        this.env_from = Pickle::unpickle(stream)?;
        this.env_from_parameters = Pickle::unpickle(stream)?;
        this.env_rcpt_to = Pickle::unpickle(stream)?;
        this.score = Pickle::unpickle(stream)?;
        this.tags = Pickle::unpickle(stream)?;
        this.result = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamClassify {
    fn default() -> Self {
        Self {
            message: Default::default(),
            remote_ip: Default::default(),
            ehlo_domain: Default::default(),
            authenticated_as: Default::default(),
            is_tls: true,
            env_from: Default::default(),
            env_from_parameters: Default::default(),
            env_rcpt_to: Default::default(),
            score: Float::new(0.0f64),
            tags: Default::default(),
            result: Default::default(),
        }
    }
}

impl IntoValue for SpamClassify {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::Message, self.message.into_value());
        map.insert_unchecked(Property::RemoteIp, self.remote_ip.into_value());
        map.insert_unchecked(Property::EhloDomain, self.ehlo_domain.into_value());
        map.insert_unchecked(
            Property::AuthenticatedAs,
            self.authenticated_as.into_value(),
        );
        map.insert_unchecked(Property::IsTls, self.is_tls.into_value());
        map.insert_unchecked(Property::EnvFrom, self.env_from.into_value());
        map.insert_unchecked(
            Property::EnvFromParameters,
            self.env_from_parameters.into_value(),
        );
        map.insert_unchecked(Property::EnvRcptTo, self.env_rcpt_to.into_value());
        map.insert_unchecked(Property::Score, self.score.into_value());
        map.insert_unchecked(Property::Tags, self.tags.into_value());
        map.insert_unchecked(Property::Result, self.result.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamClassify {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Message) => self.message.patch(pointer, value),
            Some(Property::RemoteIp) => self.remote_ip.patch(pointer, value),
            Some(Property::EhloDomain) => self.ehlo_domain.patch(pointer, value),
            Some(Property::AuthenticatedAs) => self.authenticated_as.patch(pointer, value),
            Some(Property::IsTls) => self.is_tls.patch(pointer, value),
            Some(Property::EnvFrom) => self
                .env_from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::EnvFromParameters) => self.env_from_parameters.patch(pointer, value),
            Some(Property::EnvRcptTo) => self
                .env_rcpt_to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Score) => pointer.assert_server_set(),
            Some(Property::Tags) => pointer.assert_server_set(),
            Some(Property::Result) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamClassifyTag {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for SpamClassifyTag {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.score.pickle(out);
        self.disposition.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.score = Pickle::unpickle(stream)?;
        this.disposition = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamClassifyTag {
    fn default() -> Self {
        Self {
            score: Float::new(0.0f64),
            disposition: Default::default(),
        }
    }
}

impl IntoValue for SpamClassifyTag {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Score, self.score.into_value());
        map.insert_unchecked(Property::Disposition, self.disposition.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamClassifyTag {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Score) => pointer.assert_server_set(),
            Some(Property::Disposition) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamDnsblServer {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamDnsblServer;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SpamDnsblServer::Any(inner) => inner.validate(errors),
            SpamDnsblServer::Url(inner) => inner.validate(errors),
            SpamDnsblServer::Domain(inner) => inner.validate(errors),
            SpamDnsblServer::Email(inner) => inner.validate(errors),
            SpamDnsblServer::Ip(inner) => inner.validate(errors),
            SpamDnsblServer::Header(inner) => inner.validate(errors),
            SpamDnsblServer::Body(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            SpamDnsblServer::Any(object) => {
                object.index(i);
            }
            SpamDnsblServer::Url(object) => {
                object.index(i);
            }
            SpamDnsblServer::Domain(object) => {
                object.index(i);
            }
            SpamDnsblServer::Email(object) => {
                object.index(i);
            }
            SpamDnsblServer::Ip(object) => {
                object.index(i);
            }
            SpamDnsblServer::Header(object) => {
                object.index(i);
            }
            SpamDnsblServer::Body(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for SpamDnsblServer {
    fn default() -> Self {
        SpamDnsblServer::Any(Default::default())
    }
}

impl Pickle for SpamDnsblServer {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SpamDnsblServer::Any(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Url(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Domain(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Email(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Ip(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Header(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            SpamDnsblServer::Body(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SpamDnsblServer::Any),
            1 => Pickle::unpickle(stream).map(SpamDnsblServer::Url),
            2 => Pickle::unpickle(stream).map(SpamDnsblServer::Domain),
            3 => Pickle::unpickle(stream).map(SpamDnsblServer::Email),
            4 => Pickle::unpickle(stream).map(SpamDnsblServer::Ip),
            5 => Pickle::unpickle(stream).map(SpamDnsblServer::Header),
            6 => Pickle::unpickle(stream).map(SpamDnsblServer::Body),
            _ => None,
        }
    }
}

impl IntoValue for SpamDnsblServer {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SpamDnsblServer::Any(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Any".into()));
                obj
            }
            SpamDnsblServer::Url(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Url".into()));
                obj
            }
            SpamDnsblServer::Domain(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Domain".into()));
                obj
            }
            SpamDnsblServer::Email(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Email".into()));
                obj
            }
            SpamDnsblServer::Ip(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ip".into()));
                obj
            }
            SpamDnsblServer::Header(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Header".into()));
                obj
            }
            SpamDnsblServer::Body(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Body".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SpamDnsblServer {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SpamDnsblServerType::Any => *self = SpamDnsblServer::Any(Default::default()),
                SpamDnsblServerType::Url => *self = SpamDnsblServer::Url(Default::default()),
                SpamDnsblServerType::Domain => *self = SpamDnsblServer::Domain(Default::default()),
                SpamDnsblServerType::Email => *self = SpamDnsblServer::Email(Default::default()),
                SpamDnsblServerType::Ip => *self = SpamDnsblServer::Ip(Default::default()),
                SpamDnsblServerType::Header => *self = SpamDnsblServer::Header(Default::default()),
                SpamDnsblServerType::Body => *self = SpamDnsblServer::Body(Default::default()),
            }
        }
        match self {
            SpamDnsblServer::Any(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Url(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Domain(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Email(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Ip(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Header(inner) => inner.patch(pointer, value),
            SpamDnsblServer::Body(inner) => inner.patch(pointer, value),
        }
    }
}

impl SpamDnsblServer {
    pub fn object_type(&self) -> SpamDnsblServerType {
        match self {
            SpamDnsblServer::Any(_) => SpamDnsblServerType::Any,
            SpamDnsblServer::Url(_) => SpamDnsblServerType::Url,
            SpamDnsblServer::Domain(_) => SpamDnsblServerType::Domain,
            SpamDnsblServer::Email(_) => SpamDnsblServerType::Email,
            SpamDnsblServer::Ip(_) => SpamDnsblServerType::Ip,
            SpamDnsblServer::Header(_) => SpamDnsblServerType::Header,
            SpamDnsblServer::Body(_) => SpamDnsblServerType::Body,
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        match self {
            SpamDnsblServer::Any(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Url(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Domain(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Email(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Ip(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Header(obj) => obj.expression_ctxs(),
            SpamDnsblServer::Body(obj) => obj.expression_ctxs(),
        }
    }
}

impl SpamDnsblServerAny {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerAny {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerAny {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerAny {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerAny {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerAny {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerBody {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerBody {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerBody {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerBody {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerBody {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerBody {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerDomain {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerDomain {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerDomain {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerDomain {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerDomain {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerDomain {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerEmail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerEmail {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_EMAIL_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerEmail {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerEmail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerEmail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerHeader {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerHeader {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_HEADER_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerHeader {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerHeader {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerHeader {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerHeader {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerIp {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerIp {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerIp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerIp {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerIp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerIp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamDnsblServerUrl {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        value.validate(errors);
        let value = &self.zone;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamDnsblServerUrl {
    pub fn ctx_tag(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.tag,
            default: None,
            property: Property::Tag,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_zone(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.zone,
            default: None,
            property: Property::Zone,
            allowed_variables: SPAM_URL_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_tag(), self.ctx_zone()]
    }
}

impl Pickle for SpamDnsblServerUrl {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.zone.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.zone = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblServerUrl {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            zone: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
        }
    }
}

impl IntoValue for SpamDnsblServerUrl {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Zone, self.zone.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblServerUrl {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(pointer, value),
            Some(Property::Zone) => self.zone.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamDnsblSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamDnsblSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.domain_limit;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::DomainLimit, 1));
        }
        let value = &self.email_limit;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::EmailLimit, 1));
        }
        let value = &self.ip_limit;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::IpLimit, 1));
        }
        let value = &self.url_limit;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::UrlLimit, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for SpamDnsblSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.domain_limit.pickle(out);
        self.email_limit.pickle(out);
        self.ip_limit.pickle(out);
        self.url_limit.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.domain_limit = Pickle::unpickle(stream)?;
        this.email_limit = Pickle::unpickle(stream)?;
        this.ip_limit = Pickle::unpickle(stream)?;
        this.url_limit = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamDnsblSettings {
    fn default() -> Self {
        Self {
            domain_limit: 50u64,
            email_limit: 50u64,
            ip_limit: 50u64,
            url_limit: 50u64,
        }
    }
}

impl IntoValue for SpamDnsblSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::DomainLimit, self.domain_limit.into_value());
        map.insert_unchecked(Property::EmailLimit, self.email_limit.into_value());
        map.insert_unchecked(Property::IpLimit, self.ip_limit.into_value());
        map.insert_unchecked(Property::UrlLimit, self.url_limit.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamDnsblSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DomainLimit) => self.domain_limit.patch(pointer, value),
            Some(Property::EmailLimit) => self.email_limit.patch(pointer, value),
            Some(Property::IpLimit) => self.ip_limit.patch(pointer, value),
            Some(Property::UrlLimit) => self.url_limit.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamFileExtension {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamFileExtension;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.extension;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Extension));
        }
        let value = &self.content_types;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ContentTypes));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Extension, &self.extension);
    }
}

impl Pickle for SpamFileExtension {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.extension.pickle(out);
        self.is_archive.pickle(out);
        self.is_bad.pickle(out);
        self.is_nz.pickle(out);
        self.content_types.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.extension = Pickle::unpickle(stream)?;
        this.is_archive = Pickle::unpickle(stream)?;
        this.is_bad = Pickle::unpickle(stream)?;
        this.is_nz = Pickle::unpickle(stream)?;
        this.content_types = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamFileExtension {
    fn default() -> Self {
        Self {
            extension: Default::default(),
            is_archive: false,
            is_bad: false,
            is_nz: false,
            content_types: Default::default(),
        }
    }
}

impl IntoValue for SpamFileExtension {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Extension, self.extension.into_value());
        map.insert_unchecked(Property::IsArchive, self.is_archive.into_value());
        map.insert_unchecked(Property::IsBad, self.is_bad.into_value());
        map.insert_unchecked(Property::IsNz, self.is_nz.into_value());
        map.insert_unchecked(Property::ContentTypes, self.content_types.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamFileExtension {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Extension) => self.extension.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Lowercase]),
                value,
            ),
            Some(Property::IsArchive) => self.is_archive.patch(pointer, value),
            Some(Property::IsBad) => self.is_bad.patch(pointer, value),
            Some(Property::IsNz) => self.is_nz.patch(pointer, value),
            Some(Property::ContentTypes) => self
                .content_types
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamLlm {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamLlm;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SpamLlm::Disable => true,
            SpamLlm::Enable(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            SpamLlm::Disable => {}
            SpamLlm::Enable(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for SpamLlm {
    fn default() -> Self {
        SpamLlm::Disable
    }
}

impl Pickle for SpamLlm {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SpamLlm::Disable => {
                0u16.pickle(out);
            }
            SpamLlm::Enable(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SpamLlm::Disable),
            1 => Pickle::unpickle(stream).map(SpamLlm::Enable),
            _ => None,
        }
    }
}

impl IntoValue for SpamLlm {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SpamLlm::Disable => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disable".into()));
                JmapValue::Object(obj)
            }
            SpamLlm::Enable(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Enable".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SpamLlm {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SpamLlmType::Disable => *self = SpamLlm::Disable,
                SpamLlmType::Enable => *self = SpamLlm::Enable(Default::default()),
            }
        }
        match self {
            SpamLlm::Disable => pointer.assert_eof(),
            SpamLlm::Enable(inner) => inner.patch(pointer, value),
        }
    }
}

impl SpamLlm {
    pub fn object_type(&self) -> SpamLlmType {
        match self {
            SpamLlm::Disable => SpamLlmType::Disable,
            SpamLlm::Enable(_) => SpamLlmType::Enable,
        }
    }
}

impl SpamLlmProperties {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.categories;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Categories));
            }
        }
        if value.len() < 2 {
            errors.push(ValidationError::min_items(Property::Categories, 2));
        }
        let value = &self.confidence;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Confidence));
            }
        }
        let value = &self.model_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::ModelId));
        }
        let value = &self.prompt;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Prompt));
        }
        let value = &self.separator;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Separator));
        }
        let value = &self.temperature;
        if *value > Float::new(1.0) {
            errors.push(ValidationError::max_value(Property::Temperature, 1));
        }
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::Temperature, 0));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::AiModel, self.model_id.into(), None);
    }
}

impl Pickle for SpamLlmProperties {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.categories.pickle(out);
        self.confidence.pickle(out);
        self.response_pos_category.pickle(out);
        self.response_pos_confidence.pickle(out);
        self.response_pos_explanation.pickle(out);
        self.model_id.pickle(out);
        self.prompt.pickle(out);
        self.separator.pickle(out);
        self.temperature.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.categories = Pickle::unpickle(stream)?;
        this.confidence = Pickle::unpickle(stream)?;
        this.response_pos_category = Pickle::unpickle(stream)?;
        this.response_pos_confidence = Pickle::unpickle(stream)?;
        this.response_pos_explanation = Pickle::unpickle(stream)?;
        this.model_id = Pickle::unpickle(stream)?;
        this.prompt = Pickle::unpickle(stream)?;
        this.separator = Pickle::unpickle(stream)?;
        this.temperature = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamLlmProperties {
    fn default() -> Self {
        Self {
            categories: Map::new(vec![
                "Unsolicited".to_string(),
                "Commercial".to_string(),
                "Harmful".to_string(),
                "Legitimate".to_string(),
            ]),
            confidence: Map::new(vec![
                "High".to_string(),
                "Medium".to_string(),
                "Low".to_string(),
            ]),
            response_pos_category: 0u64,
            response_pos_confidence: Some(1u64),
            response_pos_explanation: Some(2u64),
            model_id: Default::default(),
            prompt: Default::default(),
            separator: ",".to_string(),
            temperature: Float::new(0.5f64),
        }
    }
}

impl IntoValue for SpamLlmProperties {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::Categories, self.categories.into_value());
        map.insert_unchecked(Property::Confidence, self.confidence.into_value());
        map.insert_unchecked(
            Property::ResponsePosCategory,
            self.response_pos_category.into_value(),
        );
        map.insert_unchecked(
            Property::ResponsePosConfidence,
            self.response_pos_confidence.into_value(),
        );
        map.insert_unchecked(
            Property::ResponsePosExplanation,
            self.response_pos_explanation.into_value(),
        );
        map.insert_unchecked(Property::ModelId, self.model_id.into_value());
        map.insert_unchecked(Property::Prompt, self.prompt.into_value());
        map.insert_unchecked(Property::Separator, self.separator.into_value());
        map.insert_unchecked(Property::Temperature, self.temperature.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamLlmProperties {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Categories) => self.categories.patch(pointer, value),
            Some(Property::Confidence) => self.confidence.patch(pointer, value),
            Some(Property::ResponsePosCategory) => self.response_pos_category.patch(pointer, value),
            Some(Property::ResponsePosConfidence) => {
                self.response_pos_confidence.patch(pointer, value)
            }
            Some(Property::ResponsePosExplanation) => {
                self.response_pos_explanation.patch(pointer, value)
            }
            Some(Property::ModelId) => self.model_id.patch(pointer, value),
            Some(Property::Prompt) => self.prompt.patch(pointer, value),
            Some(Property::Separator) => self
                .separator
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Temperature) => self.temperature.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamPyzor {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamPyzor;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.block_count;
        if *value > 1000 {
            errors.push(ValidationError::max_value(Property::BlockCount, 1000));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::BlockCount, 1));
        }
        let value = &self.host;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Host));
        }
        let value = &self.port;
        if *value > 65535 {
            errors.push(ValidationError::max_value(Property::Port, 65535));
        }
        if *value < 100 {
            errors.push(ValidationError::min_value(Property::Port, 100));
        }
        let value = &self.ratio;
        if *value > Float::new(1.0) {
            errors.push(ValidationError::max_value(Property::Ratio, 1));
        }
        if *value < Float::new(0.0) {
            errors.push(ValidationError::min_value(Property::Ratio, 0));
        }
        let value = &self.allow_count;
        if *value > 1000 {
            errors.push(ValidationError::max_value(Property::AllowCount, 1000));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::AllowCount, 1));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for SpamPyzor {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.block_count.pickle(out);
        self.enable.pickle(out);
        self.host.pickle(out);
        self.port.pickle(out);
        self.ratio.pickle(out);
        self.timeout.pickle(out);
        self.allow_count.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.block_count = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.host = Pickle::unpickle(stream)?;
        this.port = Pickle::unpickle(stream)?;
        this.ratio = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.allow_count = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamPyzor {
    fn default() -> Self {
        Self {
            block_count: 5u64,
            enable: true,
            host: "public.pyzor.org".to_string(),
            port: 24441u64,
            ratio: Float::new(0.2f64),
            timeout: Duration::from_millis(5000),
            allow_count: 10u64,
        }
    }
}

impl IntoValue for SpamPyzor {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::BlockCount, self.block_count.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Host, self.host.into_value());
        map.insert_unchecked(Property::Port, self.port.into_value());
        map.insert_unchecked(Property::Ratio, self.ratio.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::AllowCount, self.allow_count.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamPyzor {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BlockCount) => self.block_count.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Host) => self
                .host
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Port) => self.port.patch(pointer, value),
            Some(Property::Ratio) => self.ratio.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::AllowCount) => self.allow_count.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamRule {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamRule;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SpamRule::Any(inner) => inner.validate(errors),
            SpamRule::Url(inner) => inner.validate(errors),
            SpamRule::Domain(inner) => inner.validate(errors),
            SpamRule::Email(inner) => inner.validate(errors),
            SpamRule::Ip(inner) => inner.validate(errors),
            SpamRule::Header(inner) => inner.validate(errors),
            SpamRule::Body(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            SpamRule::Any(object) => {
                object.index(i);
            }
            SpamRule::Url(object) => {
                object.index(i);
            }
            SpamRule::Domain(object) => {
                object.index(i);
            }
            SpamRule::Email(object) => {
                object.index(i);
            }
            SpamRule::Ip(object) => {
                object.index(i);
            }
            SpamRule::Header(object) => {
                object.index(i);
            }
            SpamRule::Body(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for SpamRule {
    fn default() -> Self {
        SpamRule::Any(Default::default())
    }
}

impl Pickle for SpamRule {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SpamRule::Any(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Url(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Domain(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Email(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Ip(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Header(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            SpamRule::Body(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SpamRule::Any),
            1 => Pickle::unpickle(stream).map(SpamRule::Url),
            2 => Pickle::unpickle(stream).map(SpamRule::Domain),
            3 => Pickle::unpickle(stream).map(SpamRule::Email),
            4 => Pickle::unpickle(stream).map(SpamRule::Ip),
            5 => Pickle::unpickle(stream).map(SpamRule::Header),
            6 => Pickle::unpickle(stream).map(SpamRule::Body),
            _ => None,
        }
    }
}

impl IntoValue for SpamRule {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SpamRule::Any(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Any".into()));
                obj
            }
            SpamRule::Url(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Url".into()));
                obj
            }
            SpamRule::Domain(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Domain".into()));
                obj
            }
            SpamRule::Email(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Email".into()));
                obj
            }
            SpamRule::Ip(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Ip".into()));
                obj
            }
            SpamRule::Header(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Header".into()));
                obj
            }
            SpamRule::Body(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Body".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SpamRule {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SpamRuleType::Any => *self = SpamRule::Any(Default::default()),
                SpamRuleType::Url => *self = SpamRule::Url(Default::default()),
                SpamRuleType::Domain => *self = SpamRule::Domain(Default::default()),
                SpamRuleType::Email => *self = SpamRule::Email(Default::default()),
                SpamRuleType::Ip => *self = SpamRule::Ip(Default::default()),
                SpamRuleType::Header => *self = SpamRule::Header(Default::default()),
                SpamRuleType::Body => *self = SpamRule::Body(Default::default()),
            }
        }
        match self {
            SpamRule::Any(inner) => inner.patch(pointer, value),
            SpamRule::Url(inner) => inner.patch(pointer, value),
            SpamRule::Domain(inner) => inner.patch(pointer, value),
            SpamRule::Email(inner) => inner.patch(pointer, value),
            SpamRule::Ip(inner) => inner.patch(pointer, value),
            SpamRule::Header(inner) => inner.patch(pointer, value),
            SpamRule::Body(inner) => inner.patch(pointer, value),
        }
    }
}

impl SpamRule {
    pub fn object_type(&self) -> SpamRuleType {
        match self {
            SpamRule::Any(_) => SpamRuleType::Any,
            SpamRule::Url(_) => SpamRuleType::Url,
            SpamRule::Domain(_) => SpamRuleType::Domain,
            SpamRule::Email(_) => SpamRuleType::Email,
            SpamRule::Ip(_) => SpamRuleType::Ip,
            SpamRule::Header(_) => SpamRuleType::Header,
            SpamRule::Body(_) => SpamRuleType::Body,
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        match self {
            SpamRule::Any(obj) => obj.expression_ctxs(),
            SpamRule::Url(obj) => obj.expression_ctxs(),
            SpamRule::Domain(obj) => obj.expression_ctxs(),
            SpamRule::Email(obj) => obj.expression_ctxs(),
            SpamRule::Ip(obj) => obj.expression_ctxs(),
            SpamRule::Header(obj) => obj.expression_ctxs(),
            SpamRule::Body(obj) => obj.expression_ctxs(),
        }
    }
}

impl SpamRuleAny {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleAny {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleAny {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleAny {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleAny {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleAny {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleBody {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleBody {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleBody {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleBody {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleBody {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleBody {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleDomain {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleDomain {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_GENERIC_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleDomain {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleDomain {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleDomain {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleDomain {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleEmail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleEmail {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_EMAIL_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleEmail {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleEmail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleEmail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleHeader {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleHeader {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_HEADER_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleHeader {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleHeader {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleHeader {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleHeader {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleIp {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleIp {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_IP_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleIp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleIp {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleIp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleIp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamRuleUrl {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.condition;
        value.validate(errors);
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.priority;
        if *value > (99999) {
            errors.push(ValidationError::max_value(Property::Priority, 99999));
        }
        if *value < (-99999) {
            errors.push(ValidationError::min_value(Property::Priority, -99999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Name, &self.name);
    }
}

impl SpamRuleUrl {
    pub fn ctx_condition(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.condition,
            default: None,
            property: Property::Condition,
            allowed_variables: SPAM_URL_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_condition()]
    }
}

impl Pickle for SpamRuleUrl {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.condition.pickle(out);
        self.name.pickle(out);
        self.description.pickle(out);
        self.enable.pickle(out);
        self.priority.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.condition = Pickle::unpickle(stream)?;
        this.name = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.priority = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamRuleUrl {
    fn default() -> Self {
        Self {
            condition: Default::default(),
            name: Default::default(),
            description: Default::default(),
            enable: true,
            priority: 500i64,
        }
    }
}

impl IntoValue for SpamRuleUrl {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Condition, self.condition.into_value());
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Priority, self.priority.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamRuleUrl {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Condition) => self.condition.patch(pointer, value),
            Some(Property::Name) => self.name.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Uppercase, StringValidator::RemoveSpaces]),
                value,
            ),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Priority) => self.priority.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.score_discard;
        if *value > Float::new(100.0) {
            errors.push(ValidationError::max_value(Property::ScoreDiscard, 100));
        }
        if *value < Float::new(-100.0) {
            errors.push(ValidationError::min_value(Property::ScoreDiscard, -100));
        }
        let value = &self.score_reject;
        if *value > Float::new(100.0) {
            errors.push(ValidationError::max_value(Property::ScoreReject, 100));
        }
        if *value < Float::new(-100.0) {
            errors.push(ValidationError::min_value(Property::ScoreReject, -100));
        }
        let value = &self.score_spam;
        if *value > Float::new(100.0) {
            errors.push(ValidationError::max_value(Property::ScoreSpam, 100));
        }
        if *value < Float::new(-100.0) {
            errors.push(ValidationError::min_value(Property::ScoreSpam, -100));
        }
        if let Some(value) = &self.spam_filter_rules_url {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::SpamFilterRulesUrl));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for SpamSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.trust_contacts.pickle(out);
        self.enable.pickle(out);
        self.greylist_for.pickle(out);
        self.score_discard.pickle(out);
        self.score_reject.pickle(out);
        self.score_spam.pickle(out);
        self.trust_replies.pickle(out);
        self.spam_filter_rules_url.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.trust_contacts = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.greylist_for = Pickle::unpickle(stream)?;
        this.score_discard = Pickle::unpickle(stream)?;
        this.score_reject = Pickle::unpickle(stream)?;
        this.score_spam = Pickle::unpickle(stream)?;
        this.trust_replies = Pickle::unpickle(stream)?;
        this.spam_filter_rules_url = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamSettings {
    fn default() -> Self {
        Self {
            trust_contacts: true,
            enable: true,
            greylist_for: Default::default(),
            score_discard: Float::new(0.0f64),
            score_reject: Float::new(0.0f64),
            score_spam: Float::new(5.0f64),
            trust_replies: true,
            spam_filter_rules_url: Some("https://github.com/stalwartlabs/spam-filter/releases/latest/download/spam-filter-rules.json.gz".to_string()),
        }
    }
}

impl IntoValue for SpamSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::TrustContacts, self.trust_contacts.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::GreylistFor, self.greylist_for.into_value());
        map.insert_unchecked(Property::ScoreDiscard, self.score_discard.into_value());
        map.insert_unchecked(Property::ScoreReject, self.score_reject.into_value());
        map.insert_unchecked(Property::ScoreSpam, self.score_spam.into_value());
        map.insert_unchecked(Property::TrustReplies, self.trust_replies.into_value());
        map.insert_unchecked(
            Property::SpamFilterRulesUrl,
            self.spam_filter_rules_url.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TrustContacts) => self.trust_contacts.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::GreylistFor) => self.greylist_for.patch(pointer, value),
            Some(Property::ScoreDiscard) => self.score_discard.patch(pointer, value),
            Some(Property::ScoreReject) => self.score_reject.patch(pointer, value),
            Some(Property::ScoreSpam) => self.score_spam.patch(pointer, value),
            Some(Property::TrustReplies) => self.trust_replies.patch(pointer, value),
            Some(Property::SpamFilterRulesUrl) => self
                .spam_filter_rules_url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamTag {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamTag;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SpamTag::Score(inner) => inner.validate(errors),
            SpamTag::Discard(inner) => inner.validate(errors),
            SpamTag::Reject(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            SpamTag::Score(object) => {
                object.index(i);
            }
            SpamTag::Discard(object) => {
                object.index(i);
            }
            SpamTag::Reject(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for SpamTag {
    fn default() -> Self {
        SpamTag::Score(Default::default())
    }
}

impl Pickle for SpamTag {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SpamTag::Score(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            SpamTag::Discard(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SpamTag::Reject(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(SpamTag::Score),
            1 => Pickle::unpickle(stream).map(SpamTag::Discard),
            2 => Pickle::unpickle(stream).map(SpamTag::Reject),
            _ => None,
        }
    }
}

impl IntoValue for SpamTag {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SpamTag::Score(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Score".into()));
                obj
            }
            SpamTag::Discard(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Discard".into()));
                obj
            }
            SpamTag::Reject(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Reject".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SpamTag {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SpamTagType::Score => *self = SpamTag::Score(Default::default()),
                SpamTagType::Discard => *self = SpamTag::Discard(Default::default()),
                SpamTagType::Reject => *self = SpamTag::Reject(Default::default()),
            }
        }
        match self {
            SpamTag::Score(inner) => inner.patch(pointer, value),
            SpamTag::Discard(inner) => inner.patch(pointer, value),
            SpamTag::Reject(inner) => inner.patch(pointer, value),
        }
    }
}

impl SpamTag {
    pub fn object_type(&self) -> SpamTagType {
        match self {
            SpamTag::Score(_) => SpamTagType::Score,
            SpamTag::Discard(_) => SpamTagType::Discard,
            SpamTag::Reject(_) => SpamTagType::Reject,
        }
    }
}

impl SpamTagAction {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Tag));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Tag, &self.tag);
    }
}

impl Pickle for SpamTagAction {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamTagAction {
    fn default() -> Self {
        Self {
            tag: Default::default(),
        }
    }
}

impl IntoValue for SpamTagAction {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamTagAction {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(
                pointer
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SpamTagScore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tag;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Tag));
        }
        let value = &self.score;
        if *value < Float::new(-999999.0) {
            errors.push(ValidationError::min_value(Property::Score, -999999));
        }
        if *value > Float::new(999999.0) {
            errors.push(ValidationError::max_value(Property::Score, 999999));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique(Property::Tag, &self.tag);
    }
}

impl Pickle for SpamTagScore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tag.pickle(out);
        self.score.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tag = Pickle::unpickle(stream)?;
        this.score = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamTagScore {
    fn default() -> Self {
        Self {
            tag: Default::default(),
            score: Float::new(0.0f64),
        }
    }
}

impl IntoValue for SpamTagScore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Tag, self.tag.into_value());
        map.insert_unchecked(Property::Score, self.score.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamTagScore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Tag) => self.tag.patch(
                pointer
                    .with_validators(&[StringValidator::RemoveSpaces, StringValidator::Uppercase]),
                value,
            ),
            Some(Property::Score) => self.score.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpamTrainingSample {
    const FLAGS: u64 = OBJ_FILTER_ACCOUNT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpamTrainingSample;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        if let Some(value) = &self.account_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::AccountId));
            }
        }
        let value = &self.expires_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ExpiresAt, value));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id, None);
        if let Some(value) = &self.account_id {
            i.search(Property::AccountId, value);
        }
    }
}

impl Pickle for SpamTrainingSample {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from.pickle(out);
        self.subject.pickle(out);
        self.blob_id.pickle(out);
        self.is_spam.pickle(out);
        self.account_id.pickle(out);
        self.expires_at.pickle(out);
        self.delete_after_use.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.blob_id = Pickle::unpickle(stream)?;
        this.is_spam = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.delete_after_use = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpamTrainingSample {
    fn default() -> Self {
        Self {
            from: Default::default(),
            subject: Default::default(),
            blob_id: Default::default(),
            is_spam: false,
            account_id: Default::default(),
            expires_at: Default::default(),
            delete_after_use: false,
        }
    }
}

impl IntoValue for SpamTrainingSample {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        map.insert_unchecked(Property::IsSpam, self.is_spam.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::DeleteAfterUse, self.delete_after_use.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpamTrainingSample {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::From) => pointer.assert_server_set(),
            Some(Property::Subject) => pointer.assert_server_set(),
            Some(Property::BlobId) => self.blob_id.patch(pointer.assert_read_only()?, value),
            Some(Property::IsSpam) => self.is_spam.patch(pointer.assert_read_only()?, value),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::ExpiresAt) => pointer.assert_server_set(),
            Some(Property::DeleteAfterUse) => self
                .delete_after_use
                .patch(pointer.assert_read_only()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SpfReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SpfReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from_address;
        value.validate(errors);
        let value = &self.from_name;
        value.validate(errors);
        let value = &self.send_frequency;
        value.validate(errors);
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        let value = &self.subject;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl SpfReportSettings {
    pub fn ctx_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_address,
            default: Some(Expression {
                else_: "'noreply-spf@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FromAddress,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_name,
            default: Some(Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::FromName,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_send_frequency(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.send_frequency,
            default: Some(Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            }),
            property: Property::SendFrequency,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_subject(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.subject,
            default: Some(Expression {
                else_: "'SPF Authentication Failure Report'".to_string(),
                ..Default::default()
            }),
            property: Property::Subject,
            allowed_variables: MTA_MAIL_FROM_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_from_address(),
            self.ctx_from_name(),
            self.ctx_send_frequency(),
            self.ctx_dkim_sign_domain(),
            self.ctx_subject(),
        ]
    }
}

impl Pickle for SpfReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from_address.pickle(out);
        self.from_name.pickle(out);
        self.send_frequency.pickle(out);
        self.dkim_sign_domain.pickle(out);
        self.subject.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from_address = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.send_frequency = Pickle::unpickle(stream)?;
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SpfReportSettings {
    fn default() -> Self {
        Self {
            from_address: Expression {
                else_: "'noreply-spf@' + system('domain')".to_string(),
                ..Default::default()
            },
            from_name: Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            },
            send_frequency: Expression {
                else_: "[1, 1d]".to_string(),
                ..Default::default()
            },
            dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            subject: Expression {
                else_: "'SPF Authentication Failure Report'".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for SpfReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::FromAddress, self.from_address.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(Property::SendFrequency, self.send_frequency.into_value());
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SpfReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::FromAddress) => self.from_address.patch(pointer, value),
            Some(Property::FromName) => self.from_name.patch(pointer, value),
            Some(Property::SendFrequency) => self.send_frequency.patch(pointer, value),
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SqlAuthStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SqlAuthStore::Default => true,
            SqlAuthStore::PostgreSql(inner) => inner.validate(errors),
            SqlAuthStore::MySql(inner) => inner.validate(errors),
            SqlAuthStore::Sqlite(inner) => inner.validate(errors),
        }
    }
}

impl Default for SqlAuthStore {
    fn default() -> Self {
        SqlAuthStore::Default
    }
}

impl Pickle for SqlAuthStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SqlAuthStore::Default => {
                0u16.pickle(out);
            }
            SqlAuthStore::PostgreSql(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SqlAuthStore::MySql(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            SqlAuthStore::Sqlite(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SqlAuthStore::Default),
            1 => Pickle::unpickle(stream).map(SqlAuthStore::PostgreSql),
            2 => Pickle::unpickle(stream).map(SqlAuthStore::MySql),
            3 => Pickle::unpickle(stream).map(SqlAuthStore::Sqlite),
            _ => None,
        }
    }
}

impl IntoValue for SqlAuthStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SqlAuthStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            SqlAuthStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            SqlAuthStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
            SqlAuthStore::Sqlite(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Sqlite".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for SqlAuthStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SqlAuthStoreType::Default => *self = SqlAuthStore::Default,
                SqlAuthStoreType::PostgreSql => {
                    *self = SqlAuthStore::PostgreSql(Default::default())
                }
                SqlAuthStoreType::MySql => *self = SqlAuthStore::MySql(Default::default()),
                SqlAuthStoreType::Sqlite => *self = SqlAuthStore::Sqlite(Default::default()),
            }
        }
        match self {
            SqlAuthStore::Default => pointer.assert_eof(),
            SqlAuthStore::PostgreSql(inner) => inner.patch(pointer, value),
            SqlAuthStore::MySql(inner) => inner.patch(pointer, value),
            SqlAuthStore::Sqlite(inner) => inner.patch(pointer, value),
        }
    }
}

impl SqlAuthStore {
    pub fn object_type(&self) -> SqlAuthStoreType {
        match self {
            SqlAuthStore::Default => SqlAuthStoreType::Default,
            SqlAuthStore::PostgreSql(_) => SqlAuthStoreType::PostgreSql,
            SqlAuthStore::MySql(_) => SqlAuthStoreType::MySql,
            SqlAuthStore::Sqlite(_) => SqlAuthStoreType::Sqlite,
        }
    }
}

impl SqlDirectory {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.description;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Description));
        }
        let value = &self.store;
        value.validate(errors);
        let value = &self.column_email;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ColumnEmail));
        }
        let value = &self.column_secret;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ColumnSecret));
        }
        if let Some(value) = &self.column_class {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ColumnClass));
            }
        }
        if let Some(value) = &self.column_description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ColumnDescription));
            }
        }
        let value = &self.query_login;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::QueryLogin));
        }
        let value = &self.query_recipient;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::QueryRecipient));
        }
        if let Some(value) = &self.query_member_of {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::QueryMemberOf));
            }
        }
        if let Some(value) = &self.query_email_aliases {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::QueryEmailAliases));
            }
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
    }
}

impl Pickle for SqlDirectory {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.description.pickle(out);
        self.store.pickle(out);
        self.column_email.pickle(out);
        self.column_secret.pickle(out);
        self.column_class.pickle(out);
        self.column_description.pickle(out);
        self.query_login.pickle(out);
        self.query_recipient.pickle(out);
        self.query_member_of.pickle(out);
        self.query_email_aliases.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.description = Pickle::unpickle(stream)?;
        this.store = Pickle::unpickle(stream)?;
        this.column_email = Pickle::unpickle(stream)?;
        this.column_secret = Pickle::unpickle(stream)?;
        this.column_class = Pickle::unpickle(stream)?;
        this.column_description = Pickle::unpickle(stream)?;
        this.query_login = Pickle::unpickle(stream)?;
        this.query_recipient = Pickle::unpickle(stream)?;
        this.query_member_of = Pickle::unpickle(stream)?;
        this.query_email_aliases = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SqlDirectory {
    fn default() -> Self {
        Self {
            description: Default::default(),
            store: Default::default(),
            column_email: "name".to_string(),
            column_secret: "secret".to_string(),
            column_class: Some("type".to_string()),
            column_description: Some("description".to_string()),
            query_login: "SELECT name, secret, description, type FROM accounts WHERE name = $1".to_string(),
            query_recipient: "SELECT name, secret, description, type FROM accounts WHERE name = $1 AND active = true".to_string(),
            query_member_of: Some("SELECT member_of FROM group_members WHERE name = $1".to_string()),
            query_email_aliases: Some("SELECT address FROM emails WHERE name = $1".to_string()),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for SqlDirectory {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(13);
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Store, self.store.into_value());
        map.insert_unchecked(Property::ColumnEmail, self.column_email.into_value());
        map.insert_unchecked(Property::ColumnSecret, self.column_secret.into_value());
        map.insert_unchecked(Property::ColumnClass, self.column_class.into_value());
        map.insert_unchecked(
            Property::ColumnDescription,
            self.column_description.into_value(),
        );
        map.insert_unchecked(Property::QueryLogin, self.query_login.into_value());
        map.insert_unchecked(Property::QueryRecipient, self.query_recipient.into_value());
        map.insert_unchecked(Property::QueryMemberOf, self.query_member_of.into_value());
        map.insert_unchecked(
            Property::QueryEmailAliases,
            self.query_email_aliases.into_value(),
        );
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SqlDirectory {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Description) => self
                .description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Store) => self.store.patch(pointer, value),
            Some(Property::ColumnEmail) => self
                .column_email
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ColumnSecret) => self
                .column_secret
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ColumnClass) => self
                .column_class
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::ColumnDescription) => self
                .column_description
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::QueryLogin) => self
                .query_login
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::QueryRecipient) => self
                .query_recipient
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::QueryMemberOf) => self
                .query_member_of
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::QueryEmailAliases) => self
                .query_email_aliases
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SqliteStore {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Path));
        }
        if let Some(value) = &self.pool_workers {
            if *value > 64 {
                errors.push(ValidationError::max_value(Property::PoolWorkers, 64));
            }
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::PoolWorkers, 1));
            }
        }
        let value = &self.pool_max_connections;
        if *value > 8192 {
            errors.push(ValidationError::max_value(
                Property::PoolMaxConnections,
                8192,
            ));
        }
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::PoolMaxConnections, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for SqliteStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.path.pickle(out);
        self.pool_workers.pickle(out);
        self.pool_max_connections.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.path = Pickle::unpickle(stream)?;
        this.pool_workers = Pickle::unpickle(stream)?;
        this.pool_max_connections = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SqliteStore {
    fn default() -> Self {
        Self {
            path: Default::default(),
            pool_workers: Default::default(),
            pool_max_connections: 10u64,
        }
    }
}

impl IntoValue for SqliteStore {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Path, self.path.into_value());
        map.insert_unchecked(Property::PoolWorkers, self.pool_workers.into_value());
        map.insert_unchecked(
            Property::PoolMaxConnections,
            self.pool_max_connections.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SqliteStore {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Path) => self
                .path
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::PoolWorkers) => self.pool_workers.patch(pointer, value),
            Some(Property::PoolMaxConnections) => self.pool_max_connections.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for StoreLookup {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::StoreLookup;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.namespace;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Namespace));
        }
        let value = &self.store;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global(Property::Namespace, &self.namespace);
    }
}

impl Pickle for StoreLookup {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.namespace.pickle(out);
        self.store.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.namespace = Pickle::unpickle(stream)?;
        this.store = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for StoreLookup {
    fn default() -> Self {
        Self {
            namespace: Default::default(),
            store: Default::default(),
        }
    }
}

impl IntoValue for StoreLookup {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Namespace, self.namespace.into_value());
        map.insert_unchecked(Property::Store, self.store.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for StoreLookup {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Namespace) => self.namespace.patch(
                pointer
                    .assert_read_only()?
                    .with_validators(&[StringValidator::Trim]),
                value,
            ),
            Some(Property::Store) => self.store.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl SubAddressing {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            SubAddressing::Enabled => true,
            SubAddressing::Custom(inner) => inner.validate(errors),
            SubAddressing::Disabled => true,
        }
    }
}

impl Default for SubAddressing {
    fn default() -> Self {
        SubAddressing::Enabled
    }
}

impl Pickle for SubAddressing {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            SubAddressing::Enabled => {
                0u16.pickle(out);
            }
            SubAddressing::Custom(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            SubAddressing::Disabled => {
                2u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(SubAddressing::Enabled),
            1 => Pickle::unpickle(stream).map(SubAddressing::Custom),
            2 => Some(SubAddressing::Disabled),
            _ => None,
        }
    }
}

impl IntoValue for SubAddressing {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            SubAddressing::Enabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Enabled".into()));
                JmapValue::Object(obj)
            }
            SubAddressing::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
            SubAddressing::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for SubAddressing {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                SubAddressingType::Enabled => *self = SubAddressing::Enabled,
                SubAddressingType::Custom => *self = SubAddressing::Custom(Default::default()),
                SubAddressingType::Disabled => *self = SubAddressing::Disabled,
            }
        }
        match self {
            SubAddressing::Enabled => pointer.assert_eof(),
            SubAddressing::Custom(inner) => inner.patch(pointer, value),
            SubAddressing::Disabled => pointer.assert_eof(),
        }
    }
}

impl SubAddressing {
    pub fn object_type(&self) -> SubAddressingType {
        match self {
            SubAddressing::Enabled => SubAddressingType::Enabled,
            SubAddressing::Custom(_) => SubAddressingType::Custom,
            SubAddressing::Disabled => SubAddressingType::Disabled,
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        match self {
            SubAddressing::Custom(obj) => obj.expression_ctxs(),
            _ => vec![],
        }
    }
}

impl SubAddressingCustom {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.custom_rule;
        value.validate(errors);
        errors.len() == neb
    }
}

impl SubAddressingCustom {
    pub fn ctx_custom_rule(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.custom_rule,
            default: None,
            property: Property::CustomRule,
            allowed_variables: MTA_RCPT_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![self.ctx_custom_rule()]
    }
}

impl Pickle for SubAddressingCustom {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.custom_rule.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.custom_rule = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SubAddressingCustom {
    fn default() -> Self {
        Self {
            custom_rule: Default::default(),
        }
    }
}

impl IntoValue for SubAddressingCustom {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::CustomRule, self.custom_rule.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SubAddressingCustom {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CustomRule) => self.custom_rule.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for SystemSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::SystemSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.default_hostname;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::DefaultHostname));
        }
        let value = &self.default_domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DefaultDomainId));
        }
        if let Some(value) = &self.default_certificate_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::DefaultCertificateId));
            }
        }
        if let Some(value) = &self.thread_pool_size {
            if *value < 1 {
                errors.push(ValidationError::min_value(Property::ThreadPoolSize, 1));
            }
        }
        let value = &self.max_connections;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxConnections, 1));
        }
        let value = &self.proxy_trusted_networks;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(
                    Property::ProxyTrustedNetworks,
                    value,
                ));
            }
        }
        let value = &self.mail_exchangers;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.services;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.provider_info;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ProviderInfo));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Domain, self.default_domain_id.into(), None);
        i.foreign_key(ObjectType::Certificate, self.default_certificate_id, None);
    }
}

impl Pickle for SystemSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.default_hostname.pickle(out);
        self.default_domain_id.pickle(out);
        self.default_certificate_id.pickle(out);
        self.thread_pool_size.pickle(out);
        self.max_connections.pickle(out);
        self.proxy_trusted_networks.pickle(out);
        self.mail_exchangers.pickle(out);
        self.services.pickle(out);
        self.provider_info.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.default_hostname = Pickle::unpickle(stream)?;
        this.default_domain_id = Pickle::unpickle(stream)?;
        this.default_certificate_id = Pickle::unpickle(stream)?;
        this.thread_pool_size = Pickle::unpickle(stream)?;
        this.max_connections = Pickle::unpickle(stream)?;
        this.proxy_trusted_networks = Pickle::unpickle(stream)?;
        this.mail_exchangers = Pickle::unpickle(stream)?;
        this.services = Pickle::unpickle(stream)?;
        this.provider_info = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for SystemSettings {
    fn default() -> Self {
        Self {
            default_hostname: Default::default(),
            default_domain_id: Default::default(),
            default_certificate_id: Default::default(),
            thread_pool_size: Default::default(),
            max_connections: 8192u64,
            proxy_trusted_networks: Default::default(),
            mail_exchangers: List::from_iter([MailExchanger {
                priority: 10u64,
                ..Default::default()
            }]),
            services: VecMap::from_iter([
                (
                    ServiceProtocol::Caldav,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Carddav,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Imap,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Jmap,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Managesieve,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Pop3,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Smtp,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
                (
                    ServiceProtocol::Webdav,
                    Service {
                        cleartext: false,
                        ..Default::default()
                    },
                ),
            ]),
            provider_info: Default::default(),
        }
    }
}

impl IntoValue for SystemSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(
            Property::DefaultHostname,
            self.default_hostname.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultDomainId,
            self.default_domain_id.into_value(),
        );
        map.insert_unchecked(
            Property::DefaultCertificateId,
            self.default_certificate_id.into_value(),
        );
        map.insert_unchecked(Property::ThreadPoolSize, self.thread_pool_size.into_value());
        map.insert_unchecked(Property::MaxConnections, self.max_connections.into_value());
        map.insert_unchecked(
            Property::ProxyTrustedNetworks,
            self.proxy_trusted_networks.into_value(),
        );
        map.insert_unchecked(Property::MailExchangers, self.mail_exchangers.into_value());
        map.insert_unchecked(Property::Services, self.services.into_value());
        map.insert_unchecked(Property::ProviderInfo, self.provider_info.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for SystemSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DefaultHostname) => self
                .default_hostname
                .patch(pointer.with_validators(&[StringValidator::Hostname]), value),
            Some(Property::DefaultDomainId) => self.default_domain_id.patch(pointer, value),
            Some(Property::DefaultCertificateId) => {
                self.default_certificate_id.patch(pointer, value)
            }
            Some(Property::ThreadPoolSize) => self.thread_pool_size.patch(pointer, value),
            Some(Property::MaxConnections) => self.max_connections.patch(pointer, value),
            Some(Property::ProxyTrustedNetworks) => self
                .proxy_trusted_networks
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::MailExchangers) => self.mail_exchangers.patch(pointer, value),
            Some(Property::Services) => self.services.patch(pointer, value),
            Some(Property::ProviderInfo) => self.provider_info.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Task {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Task;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Task::IndexDocument(inner) => inner.validate(errors),
            Task::UnindexDocument(inner) => inner.validate(errors),
            Task::IndexTrace(inner) => inner.validate(errors),
            Task::CalendarAlarmEmail(inner) => inner.validate(errors),
            Task::CalendarAlarmNotification(inner) => inner.validate(errors),
            Task::CalendarItipMessage(inner) => inner.validate(errors),
            Task::MergeThreads(inner) => inner.validate(errors),
            Task::DmarcReport(inner) => inner.validate(errors),
            Task::TlsReport(inner) => inner.validate(errors),
            Task::RestoreArchivedItem(inner) => inner.validate(errors),
            Task::DestroyAccount(inner) => inner.validate(errors),
            Task::AccountMaintenance(inner) => inner.validate(errors),
            Task::TenantMaintenance(inner) => inner.validate(errors),
            Task::StoreMaintenance(inner) => inner.validate(errors),
            Task::SpamFilterMaintenance(inner) => inner.validate(errors),
            Task::AcmeRenewal(inner) => inner.validate(errors),
            Task::DkimManagement(inner) => inner.validate(errors),
            Task::DnsManagement(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            Task::IndexDocument(object) => {
                object.index(i);
            }
            Task::UnindexDocument(object) => {
                object.index(i);
            }
            Task::IndexTrace(object) => {
                object.index(i);
            }
            Task::CalendarAlarmEmail(object) => {
                object.index(i);
            }
            Task::CalendarAlarmNotification(object) => {
                object.index(i);
            }
            Task::CalendarItipMessage(object) => {
                object.index(i);
            }
            Task::MergeThreads(object) => {
                object.index(i);
            }
            Task::DmarcReport(object) => {
                object.index(i);
            }
            Task::TlsReport(object) => {
                object.index(i);
            }
            Task::RestoreArchivedItem(object) => {
                object.index(i);
            }
            Task::DestroyAccount(object) => {
                object.index(i);
            }
            Task::AccountMaintenance(object) => {
                object.index(i);
            }
            Task::TenantMaintenance(object) => {
                object.index(i);
            }
            Task::StoreMaintenance(_) => {}
            Task::SpamFilterMaintenance(_) => {}
            Task::AcmeRenewal(object) => {
                object.index(i);
            }
            Task::DkimManagement(object) => {
                object.index(i);
            }
            Task::DnsManagement(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for Task {
    fn default() -> Self {
        Task::IndexDocument(Default::default())
    }
}

impl Pickle for Task {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Task::IndexDocument(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Task::UnindexDocument(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Task::IndexTrace(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            Task::CalendarAlarmEmail(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            Task::CalendarAlarmNotification(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            Task::CalendarItipMessage(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            Task::MergeThreads(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            Task::DmarcReport(inner) => {
                7u16.pickle(out);
                inner.pickle(out);
            }
            Task::TlsReport(inner) => {
                8u16.pickle(out);
                inner.pickle(out);
            }
            Task::RestoreArchivedItem(inner) => {
                9u16.pickle(out);
                inner.pickle(out);
            }
            Task::DestroyAccount(inner) => {
                10u16.pickle(out);
                inner.pickle(out);
            }
            Task::AccountMaintenance(inner) => {
                11u16.pickle(out);
                inner.pickle(out);
            }
            Task::TenantMaintenance(inner) => {
                12u16.pickle(out);
                inner.pickle(out);
            }
            Task::StoreMaintenance(inner) => {
                13u16.pickle(out);
                inner.pickle(out);
            }
            Task::SpamFilterMaintenance(inner) => {
                14u16.pickle(out);
                inner.pickle(out);
            }
            Task::AcmeRenewal(inner) => {
                15u16.pickle(out);
                inner.pickle(out);
            }
            Task::DkimManagement(inner) => {
                16u16.pickle(out);
                inner.pickle(out);
            }
            Task::DnsManagement(inner) => {
                17u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Task::IndexDocument),
            1 => Pickle::unpickle(stream).map(Task::UnindexDocument),
            2 => Pickle::unpickle(stream).map(Task::IndexTrace),
            3 => Pickle::unpickle(stream).map(Task::CalendarAlarmEmail),
            4 => Pickle::unpickle(stream).map(Task::CalendarAlarmNotification),
            5 => Pickle::unpickle(stream).map(Task::CalendarItipMessage),
            6 => Pickle::unpickle(stream).map(Task::MergeThreads),
            7 => Pickle::unpickle(stream).map(Task::DmarcReport),
            8 => Pickle::unpickle(stream).map(Task::TlsReport),
            9 => Pickle::unpickle(stream).map(Task::RestoreArchivedItem),
            10 => Pickle::unpickle(stream).map(Task::DestroyAccount),
            11 => Pickle::unpickle(stream).map(Task::AccountMaintenance),
            12 => Pickle::unpickle(stream).map(Task::TenantMaintenance),
            13 => Pickle::unpickle(stream).map(Task::StoreMaintenance),
            14 => Pickle::unpickle(stream).map(Task::SpamFilterMaintenance),
            15 => Pickle::unpickle(stream).map(Task::AcmeRenewal),
            16 => Pickle::unpickle(stream).map(Task::DkimManagement),
            17 => Pickle::unpickle(stream).map(Task::DnsManagement),
            _ => None,
        }
    }
}

impl IntoValue for Task {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Task::IndexDocument(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("IndexDocument".into()));
                obj
            }
            Task::UnindexDocument(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UnindexDocument".into()));
                obj
            }
            Task::IndexTrace(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("IndexTrace".into()));
                obj
            }
            Task::CalendarAlarmEmail(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("CalendarAlarmEmail".into()));
                obj
            }
            Task::CalendarAlarmNotification(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut().unwrap().insert_unchecked(
                    Property::Type,
                    JmapValue::Str("CalendarAlarmNotification".into()),
                );
                obj
            }
            Task::CalendarItipMessage(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("CalendarItipMessage".into()));
                obj
            }
            Task::MergeThreads(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MergeThreads".into()));
                obj
            }
            Task::DmarcReport(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DmarcReport".into()));
                obj
            }
            Task::TlsReport(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TlsReport".into()));
                obj
            }
            Task::RestoreArchivedItem(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("RestoreArchivedItem".into()));
                obj
            }
            Task::DestroyAccount(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DestroyAccount".into()));
                obj
            }
            Task::AccountMaintenance(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("AccountMaintenance".into()));
                obj
            }
            Task::TenantMaintenance(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("TenantMaintenance".into()));
                obj
            }
            Task::StoreMaintenance(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("StoreMaintenance".into()));
                obj
            }
            Task::SpamFilterMaintenance(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut().unwrap().insert_unchecked(
                    Property::Type,
                    JmapValue::Str("SpamFilterMaintenance".into()),
                );
                obj
            }
            Task::AcmeRenewal(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("AcmeRenewal".into()));
                obj
            }
            Task::DkimManagement(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DkimManagement".into()));
                obj
            }
            Task::DnsManagement(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("DnsManagement".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Task {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TaskType::IndexDocument => *self = Task::IndexDocument(Default::default()),
                TaskType::UnindexDocument => *self = Task::UnindexDocument(Default::default()),
                TaskType::IndexTrace => *self = Task::IndexTrace(Default::default()),
                TaskType::CalendarAlarmEmail => {
                    *self = Task::CalendarAlarmEmail(Default::default())
                }
                TaskType::CalendarAlarmNotification => {
                    *self = Task::CalendarAlarmNotification(Default::default())
                }
                TaskType::CalendarItipMessage => {
                    *self = Task::CalendarItipMessage(Default::default())
                }
                TaskType::MergeThreads => *self = Task::MergeThreads(Default::default()),
                TaskType::DmarcReport => *self = Task::DmarcReport(Default::default()),
                TaskType::TlsReport => *self = Task::TlsReport(Default::default()),
                TaskType::RestoreArchivedItem => {
                    *self = Task::RestoreArchivedItem(Default::default())
                }
                TaskType::DestroyAccount => *self = Task::DestroyAccount(Default::default()),
                TaskType::AccountMaintenance => {
                    *self = Task::AccountMaintenance(Default::default())
                }
                TaskType::TenantMaintenance => *self = Task::TenantMaintenance(Default::default()),
                TaskType::StoreMaintenance => *self = Task::StoreMaintenance(Default::default()),
                TaskType::SpamFilterMaintenance => {
                    *self = Task::SpamFilterMaintenance(Default::default())
                }
                TaskType::AcmeRenewal => *self = Task::AcmeRenewal(Default::default()),
                TaskType::DkimManagement => *self = Task::DkimManagement(Default::default()),
                TaskType::DnsManagement => *self = Task::DnsManagement(Default::default()),
            }
        }
        match self {
            Task::IndexDocument(inner) => inner.patch(pointer, value),
            Task::UnindexDocument(inner) => inner.patch(pointer, value),
            Task::IndexTrace(inner) => inner.patch(pointer, value),
            Task::CalendarAlarmEmail(inner) => inner.patch(pointer, value),
            Task::CalendarAlarmNotification(inner) => inner.patch(pointer, value),
            Task::CalendarItipMessage(inner) => inner.patch(pointer, value),
            Task::MergeThreads(inner) => inner.patch(pointer, value),
            Task::DmarcReport(inner) => inner.patch(pointer, value),
            Task::TlsReport(inner) => inner.patch(pointer, value),
            Task::RestoreArchivedItem(inner) => inner.patch(pointer, value),
            Task::DestroyAccount(inner) => inner.patch(pointer, value),
            Task::AccountMaintenance(inner) => inner.patch(pointer, value),
            Task::TenantMaintenance(inner) => inner.patch(pointer, value),
            Task::StoreMaintenance(inner) => inner.patch(pointer, value),
            Task::SpamFilterMaintenance(inner) => inner.patch(pointer, value),
            Task::AcmeRenewal(inner) => inner.patch(pointer, value),
            Task::DkimManagement(inner) => inner.patch(pointer, value),
            Task::DnsManagement(inner) => inner.patch(pointer, value),
        }
    }
}

impl Task {
    pub fn object_type(&self) -> TaskType {
        match self {
            Task::IndexDocument(_) => TaskType::IndexDocument,
            Task::UnindexDocument(_) => TaskType::UnindexDocument,
            Task::IndexTrace(_) => TaskType::IndexTrace,
            Task::CalendarAlarmEmail(_) => TaskType::CalendarAlarmEmail,
            Task::CalendarAlarmNotification(_) => TaskType::CalendarAlarmNotification,
            Task::CalendarItipMessage(_) => TaskType::CalendarItipMessage,
            Task::MergeThreads(_) => TaskType::MergeThreads,
            Task::DmarcReport(_) => TaskType::DmarcReport,
            Task::TlsReport(_) => TaskType::TlsReport,
            Task::RestoreArchivedItem(_) => TaskType::RestoreArchivedItem,
            Task::DestroyAccount(_) => TaskType::DestroyAccount,
            Task::AccountMaintenance(_) => TaskType::AccountMaintenance,
            Task::TenantMaintenance(_) => TaskType::TenantMaintenance,
            Task::StoreMaintenance(_) => TaskType::StoreMaintenance,
            Task::SpamFilterMaintenance(_) => TaskType::SpamFilterMaintenance,
            Task::AcmeRenewal(_) => TaskType::AcmeRenewal,
            Task::DkimManagement(_) => TaskType::DkimManagement,
            Task::DnsManagement(_) => TaskType::DnsManagement,
        }
    }
}

impl TaskAccountMaintenance {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskAccountMaintenance {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.account_id.pickle(out);
        self.maintenance_type.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.account_id = Pickle::unpickle(stream)?;
        this.maintenance_type = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskAccountMaintenance {
    fn default() -> Self {
        Self {
            account_id: Default::default(),
            maintenance_type: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskAccountMaintenance {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(
            Property::MaintenanceType,
            self.maintenance_type.into_value(),
        );
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskAccountMaintenance {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::MaintenanceType) => self
                .maintenance_type
                .patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskCalendarAlarmEmail {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.event_start;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::EventStart, value));
        }
        let value = &self.event_end;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::EventEnd, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.document_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DocumentId, value));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskCalendarAlarmEmail {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.alarm_id.pickle(out);
        self.event_id.pickle(out);
        self.event_start.pickle(out);
        self.event_end.pickle(out);
        self.event_start_tz.pickle(out);
        self.event_end_tz.pickle(out);
        self.account_id.pickle(out);
        self.document_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.alarm_id = Pickle::unpickle(stream)?;
        this.event_id = Pickle::unpickle(stream)?;
        this.event_start = Pickle::unpickle(stream)?;
        this.event_end = Pickle::unpickle(stream)?;
        this.event_start_tz = Pickle::unpickle(stream)?;
        this.event_end_tz = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.document_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskCalendarAlarmEmail {
    fn default() -> Self {
        Self {
            alarm_id: 0u64,
            event_id: 0u64,
            event_start: Default::default(),
            event_end: Default::default(),
            event_start_tz: 0u64,
            event_end_tz: 0u64,
            account_id: Default::default(),
            document_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskCalendarAlarmEmail {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(11);
        map.insert_unchecked(Property::AlarmId, self.alarm_id.into_value());
        map.insert_unchecked(Property::EventId, self.event_id.into_value());
        map.insert_unchecked(Property::EventStart, self.event_start.into_value());
        map.insert_unchecked(Property::EventEnd, self.event_end.into_value());
        map.insert_unchecked(Property::EventStartTz, self.event_start_tz.into_value());
        map.insert_unchecked(Property::EventEndTz, self.event_end_tz.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::DocumentId, self.document_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskCalendarAlarmEmail {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AlarmId) => pointer.assert_server_set(),
            Some(Property::EventId) => pointer.assert_server_set(),
            Some(Property::EventStart) => pointer.assert_server_set(),
            Some(Property::EventEnd) => pointer.assert_server_set(),
            Some(Property::EventStartTz) => pointer.assert_server_set(),
            Some(Property::EventEndTz) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::DocumentId) => {
                self.document_id.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskCalendarAlarmNotification {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.document_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DocumentId, value));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskCalendarAlarmNotification {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.alarm_id.pickle(out);
        self.event_id.pickle(out);
        self.recurrence_id.pickle(out);
        self.account_id.pickle(out);
        self.document_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.alarm_id = Pickle::unpickle(stream)?;
        this.event_id = Pickle::unpickle(stream)?;
        this.recurrence_id = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.document_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskCalendarAlarmNotification {
    fn default() -> Self {
        Self {
            alarm_id: 0u64,
            event_id: 0u64,
            recurrence_id: Default::default(),
            account_id: Default::default(),
            document_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskCalendarAlarmNotification {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::AlarmId, self.alarm_id.into_value());
        map.insert_unchecked(Property::EventId, self.event_id.into_value());
        map.insert_unchecked(Property::RecurrenceId, self.recurrence_id.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::DocumentId, self.document_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskCalendarAlarmNotification {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AlarmId) => pointer.assert_server_set(),
            Some(Property::EventId) => pointer.assert_server_set(),
            Some(Property::RecurrenceId) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::DocumentId) => {
                self.document_id.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskCalendarItipContents {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::To));
            }
        }
        let value = &self.i_calendar_data;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ICalendarData));
        }
        let value = &self.summary;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Summary));
        }
        errors.len() == neb
    }
}

impl Pickle for TaskCalendarItipContents {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.from.pickle(out);
        self.to.pickle(out);
        self.is_from_organizer.pickle(out);
        self.i_calendar_data.pickle(out);
        self.summary.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.from = Pickle::unpickle(stream)?;
        this.to = Pickle::unpickle(stream)?;
        this.is_from_organizer = Pickle::unpickle(stream)?;
        this.i_calendar_data = Pickle::unpickle(stream)?;
        this.summary = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskCalendarItipContents {
    fn default() -> Self {
        Self {
            from: Default::default(),
            to: Default::default(),
            is_from_organizer: false,
            i_calendar_data: Default::default(),
            summary: Default::default(),
        }
    }
}

impl IntoValue for TaskCalendarItipContents {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::To, self.to.into_value());
        map.insert_unchecked(
            Property::IsFromOrganizer,
            self.is_from_organizer.into_value(),
        );
        map.insert_unchecked(Property::ICalendarData, self.i_calendar_data.into_value());
        map.insert_unchecked(Property::Summary, self.summary.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskCalendarItipContents {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::From) => pointer.assert_server_set(),
            Some(Property::To) => pointer.assert_server_set(),
            Some(Property::IsFromOrganizer) => pointer.assert_server_set(),
            Some(Property::ICalendarData) => pointer.assert_server_set(),
            Some(Property::Summary) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskCalendarItipMessage {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.messages;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.document_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DocumentId, value));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskCalendarItipMessage {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.messages.pickle(out);
        self.account_id.pickle(out);
        self.document_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.messages = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.document_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskCalendarItipMessage {
    fn default() -> Self {
        Self {
            messages: Default::default(),
            account_id: Default::default(),
            document_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskCalendarItipMessage {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Messages, self.messages.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::DocumentId, self.document_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskCalendarItipMessage {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Messages) => pointer.assert_server_set(),
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::DocumentId) => {
                self.document_id.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskDestroyAccount {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.account_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::AccountName));
        }
        let value = &self.account_domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountDomainId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
        i.foreign_key(ObjectType::Domain, self.account_domain_id.into(), None);
    }
}

impl Pickle for TaskDestroyAccount {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.account_id.pickle(out);
        self.account_name.pickle(out);
        self.account_domain_id.pickle(out);
        self.account_type.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.account_id = Pickle::unpickle(stream)?;
        this.account_name = Pickle::unpickle(stream)?;
        this.account_domain_id = Pickle::unpickle(stream)?;
        this.account_type = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskDestroyAccount {
    fn default() -> Self {
        Self {
            account_id: Default::default(),
            account_name: Default::default(),
            account_domain_id: Default::default(),
            account_type: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskDestroyAccount {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::AccountName, self.account_name.into_value());
        map.insert_unchecked(
            Property::AccountDomainId,
            self.account_domain_id.into_value(),
        );
        map.insert_unchecked(Property::AccountType, self.account_type.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskDestroyAccount {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccountId) => pointer.assert_server_set(),
            Some(Property::AccountName) => self.account_name.patch(pointer, value),
            Some(Property::AccountDomainId) => self.account_domain_id.patch(pointer, value),
            Some(Property::AccountType) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskDmarcReport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.report_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::ReportId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::DmarcInternalReport, self.report_id.into(), None);
    }
}

impl Pickle for TaskDmarcReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.report_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.report_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskDmarcReport {
    fn default() -> Self {
        Self {
            report_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskDmarcReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::ReportId, self.report_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskDmarcReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ReportId) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskDnsManagement {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
    }
}

impl Pickle for TaskDnsManagement {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.update_records.pickle(out);
        self.on_success_renew_certificate.pickle(out);
        self.domain_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.update_records = Pickle::unpickle(stream)?;
        this.on_success_renew_certificate = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskDnsManagement {
    fn default() -> Self {
        Self {
            update_records: Default::default(),
            on_success_renew_certificate: false,
            domain_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskDnsManagement {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::UpdateRecords, self.update_records.into_value());
        map.insert_unchecked(
            Property::OnSuccessRenewCertificate,
            self.on_success_renew_certificate.into_value(),
        );
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskDnsManagement {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::UpdateRecords) => self.update_records.patch(pointer, value),
            Some(Property::OnSuccessRenewCertificate) => {
                self.on_success_renew_certificate.patch(pointer, value)
            }
            Some(Property::DomainId) => self.domain_id.patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskDomainManagement {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
    }
}

impl Pickle for TaskDomainManagement {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.domain_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.domain_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskDomainManagement {
    fn default() -> Self {
        Self {
            domain_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskDomainManagement {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskDomainManagement {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DomainId) => self.domain_id.patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskIndexDocument {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.document_id;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DocumentId, value));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskIndexDocument {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.document_type.pickle(out);
        self.account_id.pickle(out);
        self.document_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.document_type = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.document_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskIndexDocument {
    fn default() -> Self {
        Self {
            document_type: Default::default(),
            account_id: Default::default(),
            document_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskIndexDocument {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::DocumentType, self.document_type.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::DocumentId, self.document_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskIndexDocument {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::DocumentType) => {
                self.document_type.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::AccountId) => self
                .account_id
                .patch(pointer.assert_read_only()?.assert_can_set_account()?, value),
            Some(Property::DocumentId) => {
                self.document_id.patch(pointer.assert_read_only()?, value)
            }
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskIndexTrace {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.trace_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::TraceId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Trace, self.trace_id.into(), None);
    }
}

impl Pickle for TaskIndexTrace {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.trace_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.trace_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskIndexTrace {
    fn default() -> Self {
        Self {
            trace_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskIndexTrace {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::TraceId, self.trace_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskIndexTrace {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TraceId) => self.trace_id.patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for TaskManager {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::TaskManager;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.max_attempts;
        if *value < 1 {
            errors.push(ValidationError::min_value(Property::MaxAttempts, 1));
        }
        let value = &self.strategy;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for TaskManager {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.max_attempts.pickle(out);
        self.strategy.pickle(out);
        self.total_deadline.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.max_attempts = Pickle::unpickle(stream)?;
        this.strategy = Pickle::unpickle(stream)?;
        this.total_deadline = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskManager {
    fn default() -> Self {
        Self {
            max_attempts: 3u64,
            strategy: Default::default(),
            total_deadline: Duration::from_millis(21600000),
        }
    }
}

impl IntoValue for TaskManager {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::MaxAttempts, self.max_attempts.into_value());
        map.insert_unchecked(Property::Strategy, self.strategy.into_value());
        map.insert_unchecked(Property::TotalDeadline, self.total_deadline.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskManager {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaxAttempts) => self.max_attempts.patch(pointer, value),
            Some(Property::Strategy) => self.strategy.patch(pointer, value),
            Some(Property::TotalDeadline) => self.total_deadline.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskMergeThreads {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.thread_name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ThreadName));
        }
        let value = &self.message_ids;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MessageIds));
            }
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskMergeThreads {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.account_id.pickle(out);
        self.thread_name.pickle(out);
        self.message_ids.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.account_id = Pickle::unpickle(stream)?;
        this.thread_name = Pickle::unpickle(stream)?;
        this.message_ids = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskMergeThreads {
    fn default() -> Self {
        Self {
            account_id: Default::default(),
            thread_name: Default::default(),
            message_ids: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskMergeThreads {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::ThreadName, self.thread_name.into_value());
        map.insert_unchecked(Property::MessageIds, self.message_ids.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskMergeThreads {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AccountId) => pointer.assert_server_set(),
            Some(Property::ThreadName) => pointer.assert_server_set(),
            Some(Property::MessageIds) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskRestoreArchivedItem {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.blob_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::BlobId));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.archived_until;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ArchivedUntil, value));
        }
        let value = &self.account_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::AccountId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Account, self.account_id.into(), None);
    }
}

impl Pickle for TaskRestoreArchivedItem {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.blob_id.pickle(out);
        self.archived_item_type.pickle(out);
        self.created_at.pickle(out);
        self.archived_until.pickle(out);
        self.account_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.blob_id = Pickle::unpickle(stream)?;
        this.archived_item_type = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.archived_until = Pickle::unpickle(stream)?;
        this.account_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskRestoreArchivedItem {
    fn default() -> Self {
        Self {
            blob_id: Default::default(),
            archived_item_type: Default::default(),
            created_at: Default::default(),
            archived_until: Default::default(),
            account_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskRestoreArchivedItem {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::BlobId, self.blob_id.into_value());
        map.insert_unchecked(
            Property::ArchivedItemType,
            self.archived_item_type.into_value(),
        );
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::ArchivedUntil, self.archived_until.into_value());
        map.insert_unchecked(Property::AccountId, self.account_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskRestoreArchivedItem {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::BlobId) => pointer.assert_server_set(),
            Some(Property::ArchivedItemType) => pointer.assert_server_set(),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::ArchivedUntil) => pointer.assert_server_set(),
            Some(Property::AccountId) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskRetryStrategy {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            TaskRetryStrategy::ExponentialBackoff(inner) => inner.validate(errors),
            TaskRetryStrategy::FixedDelay(inner) => inner.validate(errors),
        }
    }
}

impl Default for TaskRetryStrategy {
    fn default() -> Self {
        TaskRetryStrategy::ExponentialBackoff(Default::default())
    }
}

impl Pickle for TaskRetryStrategy {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            TaskRetryStrategy::ExponentialBackoff(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            TaskRetryStrategy::FixedDelay(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(TaskRetryStrategy::ExponentialBackoff),
            1 => Pickle::unpickle(stream).map(TaskRetryStrategy::FixedDelay),
            _ => None,
        }
    }
}

impl IntoValue for TaskRetryStrategy {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            TaskRetryStrategy::ExponentialBackoff(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("ExponentialBackoff".into()));
                obj
            }
            TaskRetryStrategy::FixedDelay(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FixedDelay".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for TaskRetryStrategy {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TaskRetryStrategyType::ExponentialBackoff => {
                    *self = TaskRetryStrategy::ExponentialBackoff(Default::default())
                }
                TaskRetryStrategyType::FixedDelay => {
                    *self = TaskRetryStrategy::FixedDelay(Default::default())
                }
            }
        }
        match self {
            TaskRetryStrategy::ExponentialBackoff(inner) => inner.patch(pointer, value),
            TaskRetryStrategy::FixedDelay(inner) => inner.patch(pointer, value),
        }
    }
}

impl TaskRetryStrategy {
    pub fn object_type(&self) -> TaskRetryStrategyType {
        match self {
            TaskRetryStrategy::ExponentialBackoff(_) => TaskRetryStrategyType::ExponentialBackoff,
            TaskRetryStrategy::FixedDelay(_) => TaskRetryStrategyType::FixedDelay,
        }
    }
}

impl TaskRetryStrategyBackoff {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.factor;
        if *value < Float::new(1.0) {
            errors.push(ValidationError::min_value(Property::Factor, 1));
        }
        errors.len() == neb
    }
}

impl Pickle for TaskRetryStrategyBackoff {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.factor.pickle(out);
        self.initial_delay.pickle(out);
        self.max_delay.pickle(out);
        self.jitter.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.factor = Pickle::unpickle(stream)?;
        this.initial_delay = Pickle::unpickle(stream)?;
        this.max_delay = Pickle::unpickle(stream)?;
        this.jitter = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskRetryStrategyBackoff {
    fn default() -> Self {
        Self {
            factor: Float::new(2.0f64),
            initial_delay: Duration::from_millis(60000),
            max_delay: Duration::from_millis(1800000),
            jitter: true,
        }
    }
}

impl IntoValue for TaskRetryStrategyBackoff {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::Factor, self.factor.into_value());
        map.insert_unchecked(Property::InitialDelay, self.initial_delay.into_value());
        map.insert_unchecked(Property::MaxDelay, self.max_delay.into_value());
        map.insert_unchecked(Property::Jitter, self.jitter.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskRetryStrategyBackoff {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Factor) => self.factor.patch(pointer, value),
            Some(Property::InitialDelay) => self.initial_delay.patch(pointer, value),
            Some(Property::MaxDelay) => self.max_delay.patch(pointer, value),
            Some(Property::Jitter) => self.jitter.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskRetryStrategyFixed {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TaskRetryStrategyFixed {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.delay.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.delay = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskRetryStrategyFixed {
    fn default() -> Self {
        Self {
            delay: Duration::from_millis(300000),
        }
    }
}

impl IntoValue for TaskRetryStrategyFixed {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Delay, self.delay.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskRetryStrategyFixed {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Delay) => self.delay.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskSpamFilterMaintenance {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for TaskSpamFilterMaintenance {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.maintenance_type.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.maintenance_type = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskSpamFilterMaintenance {
    fn default() -> Self {
        Self {
            maintenance_type: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskSpamFilterMaintenance {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(
            Property::MaintenanceType,
            self.maintenance_type.into_value(),
        );
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskSpamFilterMaintenance {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaintenanceType) => self
                .maintenance_type
                .patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskStatus {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            TaskStatus::Pending(inner) => inner.validate(errors),
            TaskStatus::Retry(inner) => inner.validate(errors),
            TaskStatus::Failed(inner) => inner.validate(errors),
        }
    }
}

impl Default for TaskStatus {
    fn default() -> Self {
        TaskStatus::Pending(Default::default())
    }
}

impl Pickle for TaskStatus {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            TaskStatus::Pending(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            TaskStatus::Retry(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            TaskStatus::Failed(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(TaskStatus::Pending),
            1 => Pickle::unpickle(stream).map(TaskStatus::Retry),
            2 => Pickle::unpickle(stream).map(TaskStatus::Failed),
            _ => None,
        }
    }
}

impl IntoValue for TaskStatus {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            TaskStatus::Pending(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Pending".into()));
                obj
            }
            TaskStatus::Retry(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Retry".into()));
                obj
            }
            TaskStatus::Failed(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Failed".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for TaskStatus {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TaskStatusType::Pending => *self = TaskStatus::Pending(Default::default()),
                TaskStatusType::Retry => *self = TaskStatus::Retry(Default::default()),
                TaskStatusType::Failed => *self = TaskStatus::Failed(Default::default()),
            }
        }
        match self {
            TaskStatus::Pending(inner) => inner.patch(pointer, value),
            TaskStatus::Retry(inner) => inner.patch(pointer, value),
            TaskStatus::Failed(inner) => inner.patch(pointer, value),
        }
    }
}

impl TaskStatus {
    pub fn object_type(&self) -> TaskStatusType {
        match self {
            TaskStatus::Pending(_) => TaskStatusType::Pending,
            TaskStatus::Retry(_) => TaskStatusType::Retry,
            TaskStatus::Failed(_) => TaskStatusType::Failed,
        }
    }
}

impl TaskStatusFailed {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.failed_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::FailedAt, value));
        }
        let value = &self.failure_reason;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FailureReason));
        }
        errors.len() == neb
    }
}

impl Pickle for TaskStatusFailed {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.created_at.pickle(out);
        self.failed_at.pickle(out);
        self.failed_attempt_number.pickle(out);
        self.failure_reason.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.created_at = Pickle::unpickle(stream)?;
        this.failed_at = Pickle::unpickle(stream)?;
        this.failed_attempt_number = Pickle::unpickle(stream)?;
        this.failure_reason = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskStatusFailed {
    fn default() -> Self {
        Self {
            created_at: Default::default(),
            failed_at: Default::default(),
            failed_attempt_number: 0u64,
            failure_reason: Default::default(),
        }
    }
}

impl IntoValue for TaskStatusFailed {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::FailedAt, self.failed_at.into_value());
        map.insert_unchecked(
            Property::FailedAttemptNumber,
            self.failed_attempt_number.into_value(),
        );
        map.insert_unchecked(Property::FailureReason, self.failure_reason.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskStatusFailed {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::FailedAt) => self.failed_at.patch(pointer, value),
            Some(Property::FailedAttemptNumber) => self.failed_attempt_number.patch(pointer, value),
            Some(Property::FailureReason) => self.failure_reason.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskStatusPending {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.due;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Due, value));
        }
        errors.len() == neb
    }
}

impl Pickle for TaskStatusPending {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.created_at.pickle(out);
        self.due.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.created_at = Pickle::unpickle(stream)?;
        this.due = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskStatusPending {
    fn default() -> Self {
        Self {
            created_at: Default::default(),
            due: Default::default(),
        }
    }
}

impl IntoValue for TaskStatusPending {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::Due, self.due.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskStatusPending {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::Due) => self.due.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskStatusRetry {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.due;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Due, value));
        }
        let value = &self.failure_reason;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::FailureReason));
        }
        errors.len() == neb
    }
}

impl Pickle for TaskStatusRetry {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.created_at.pickle(out);
        self.due.pickle(out);
        self.attempt_number.pickle(out);
        self.failure_reason.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.created_at = Pickle::unpickle(stream)?;
        this.due = Pickle::unpickle(stream)?;
        this.attempt_number = Pickle::unpickle(stream)?;
        this.failure_reason = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskStatusRetry {
    fn default() -> Self {
        Self {
            created_at: Default::default(),
            due: Default::default(),
            attempt_number: 1u64,
            failure_reason: Default::default(),
        }
    }
}

impl IntoValue for TaskStatusRetry {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(6);
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::Due, self.due.into_value());
        map.insert_unchecked(Property::AttemptNumber, self.attempt_number.into_value());
        map.insert_unchecked(Property::FailureReason, self.failure_reason.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskStatusRetry {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::Due) => self.due.patch(pointer, value),
            Some(Property::AttemptNumber) => self.attempt_number.patch(pointer, value),
            Some(Property::FailureReason) => self.failure_reason.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskStoreMaintenance {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for TaskStoreMaintenance {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.maintenance_type.pickle(out);
        self.shard_index.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.maintenance_type = Pickle::unpickle(stream)?;
        this.shard_index = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskStoreMaintenance {
    fn default() -> Self {
        Self {
            maintenance_type: Default::default(),
            shard_index: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskStoreMaintenance {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(
            Property::MaintenanceType,
            self.maintenance_type.into_value(),
        );
        map.insert_unchecked(Property::ShardIndex, self.shard_index.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskStoreMaintenance {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::MaintenanceType) => self
                .maintenance_type
                .patch(pointer.assert_read_only()?, value),
            Some(Property::ShardIndex) => self.shard_index.patch(pointer, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskTenantMaintenance {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.tenant_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::TenantId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.tenant_id.into(), None);
    }
}

impl Pickle for TaskTenantMaintenance {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.tenant_id.pickle(out);
        self.maintenance_type.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.tenant_id = Pickle::unpickle(stream)?;
        this.maintenance_type = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskTenantMaintenance {
    fn default() -> Self {
        Self {
            tenant_id: Default::default(),
            maintenance_type: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskTenantMaintenance {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::TenantId, self.tenant_id.into_value());
        map.insert_unchecked(
            Property::MaintenanceType,
            self.maintenance_type.into_value(),
        );
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskTenantMaintenance {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::TenantId) => self.tenant_id.patch(pointer.assert_read_only()?, value),
            Some(Property::MaintenanceType) => self
                .maintenance_type
                .patch(pointer.assert_read_only()?, value),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TaskTlsReport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.report_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::ReportId));
        }
        let value = &self.status;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::TlsInternalReport, self.report_id.into(), None);
    }
}

impl Pickle for TaskTlsReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.report_id.pickle(out);
        self.status.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.report_id = Pickle::unpickle(stream)?;
        this.status = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TaskTlsReport {
    fn default() -> Self {
        Self {
            report_id: Default::default(),
            status: Default::default(),
        }
    }
}

impl IntoValue for TaskTlsReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::ReportId, self.report_id.into_value());
        map.insert_unchecked(Property::Status, self.status.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TaskTlsReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ReportId) => pointer.assert_server_set(),
            Some(Property::Status) => self.status.patch(pointer, value),
            Some(Property::Due) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Tenant {
    const FLAGS: u64 = OBJ_SEQ_ID;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Tenant;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        if let Some(value) = &self.logo {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Logo));
            }
        }
        let value = &self.roles;
        value.validate(errors);
        let value = &self.permissions;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.text(Property::Text, &self.name);
        self.roles.index(i);
    }
}

impl Pickle for Tenant {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.created_at.pickle(out);
        self.logo.pickle(out);
        self.roles.pickle(out);
        self.permissions.pickle(out);
        self.quotas.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.logo = Pickle::unpickle(stream)?;
        this.roles = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.quotas = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Tenant {
    fn default() -> Self {
        Self {
            name: Default::default(),
            created_at: Default::default(),
            logo: Default::default(),
            roles: Default::default(),
            permissions: Default::default(),
            quotas: Default::default(),
        }
    }
}

impl IntoValue for Tenant {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::Logo, self.logo.into_value());
        map.insert_unchecked(Property::Roles, self.roles.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::Quotas, self.quotas.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Tenant {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::Logo) => self.logo.patch(pointer, value),
            Some(Property::Roles) => self.roles.patch(pointer, value),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::Quotas) => self.quotas.patch(pointer, value),
            Some(Property::UsedDiskQuota) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for TlsExternalReport {
    const FLAGS: u64 = OBJ_FILTER_TENANT;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::TlsExternalReport;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.report;
        value.validate(errors);
        let value = &self.from;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::From));
        }
        let value = &self.subject;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Subject));
        }
        let value = &self.to;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::To));
            }
        }
        let value = &self.received_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ReceivedAt, value));
        }
        let value = &self.expires_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::ExpiresAt, value));
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
    }
}

impl Pickle for TlsExternalReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.report.pickle(out);
        self.from.pickle(out);
        self.subject.pickle(out);
        self.to.pickle(out);
        self.received_at.pickle(out);
        self.expires_at.pickle(out);
        self.member_tenant_id.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.report = Pickle::unpickle(stream)?;
        this.from = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        this.to = Pickle::unpickle(stream)?;
        this.received_at = Pickle::unpickle(stream)?;
        this.expires_at = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsExternalReport {
    fn default() -> Self {
        Self {
            report: Default::default(),
            from: Default::default(),
            subject: Default::default(),
            to: Default::default(),
            received_at: Default::default(),
            expires_at: Default::default(),
            member_tenant_id: Default::default(),
        }
    }
}

impl IntoValue for TlsExternalReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::From, self.from.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        map.insert_unchecked(Property::To, self.to.into_value());
        map.insert_unchecked(Property::ReceivedAt, self.received_at.into_value());
        map.insert_unchecked(Property::ExpiresAt, self.expires_at.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsExternalReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::From) => self
                .from
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::To) => self
                .to
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::ReceivedAt) => self.received_at.patch(pointer, value),
            Some(Property::ExpiresAt) => self.expires_at.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TlsFailureDetails {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.sending_mta_ip {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::SendingMtaIp, value));
            }
        }
        if let Some(value) = &self.receiving_mx_hostname {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReceivingMxHostname));
            }
        }
        if let Some(value) = &self.receiving_mx_helo {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ReceivingMxHelo));
            }
        }
        if let Some(value) = &self.receiving_ip {
            if !value.is_valid() {
                errors.push(ValidationError::invalid(Property::ReceivingIp, value));
            }
        }
        if let Some(value) = &self.additional_information {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::AdditionalInformation));
            }
        }
        if let Some(value) = &self.failure_reason_code {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::FailureReasonCode));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for TlsFailureDetails {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.result_type.pickle(out);
        self.sending_mta_ip.pickle(out);
        self.receiving_mx_hostname.pickle(out);
        self.receiving_mx_helo.pickle(out);
        self.receiving_ip.pickle(out);
        self.failed_session_count.pickle(out);
        self.additional_information.pickle(out);
        self.failure_reason_code.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.result_type = Pickle::unpickle(stream)?;
        this.sending_mta_ip = Pickle::unpickle(stream)?;
        this.receiving_mx_hostname = Pickle::unpickle(stream)?;
        this.receiving_mx_helo = Pickle::unpickle(stream)?;
        this.receiving_ip = Pickle::unpickle(stream)?;
        this.failed_session_count = Pickle::unpickle(stream)?;
        this.additional_information = Pickle::unpickle(stream)?;
        this.failure_reason_code = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsFailureDetails {
    fn default() -> Self {
        Self {
            result_type: Default::default(),
            sending_mta_ip: Default::default(),
            receiving_mx_hostname: Default::default(),
            receiving_mx_helo: Default::default(),
            receiving_ip: Default::default(),
            failed_session_count: 0u64,
            additional_information: Default::default(),
            failure_reason_code: Default::default(),
        }
    }
}

impl IntoValue for TlsFailureDetails {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::ResultType, self.result_type.into_value());
        map.insert_unchecked(Property::SendingMtaIp, self.sending_mta_ip.into_value());
        map.insert_unchecked(
            Property::ReceivingMxHostname,
            self.receiving_mx_hostname.into_value(),
        );
        map.insert_unchecked(
            Property::ReceivingMxHelo,
            self.receiving_mx_helo.into_value(),
        );
        map.insert_unchecked(Property::ReceivingIp, self.receiving_ip.into_value());
        map.insert_unchecked(
            Property::FailedSessionCount,
            self.failed_session_count.into_value(),
        );
        map.insert_unchecked(
            Property::AdditionalInformation,
            self.additional_information.into_value(),
        );
        map.insert_unchecked(
            Property::FailureReasonCode,
            self.failure_reason_code.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsFailureDetails {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ResultType) => self.result_type.patch(pointer, value),
            Some(Property::SendingMtaIp) => self.sending_mta_ip.patch(pointer, value),
            Some(Property::ReceivingMxHostname) => self.receiving_mx_hostname.patch(pointer, value),
            Some(Property::ReceivingMxHelo) => self.receiving_mx_helo.patch(pointer, value),
            Some(Property::ReceivingIp) => self.receiving_ip.patch(pointer, value),
            Some(Property::FailedSessionCount) => self.failed_session_count.patch(pointer, value),
            Some(Property::AdditionalInformation) => {
                self.additional_information.patch(pointer, value)
            }
            Some(Property::FailureReasonCode) => self.failure_reason_code.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for TlsInternalReport {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::TlsInternalReport;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.mail_rua;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MailRua));
            }
        }
        let value = &self.http_rua;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpRua));
            }
        }
        let value = &self.report;
        value.validate(errors);
        let value = &self.domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Domain));
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.deliver_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DeliverAt, value));
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for TlsInternalReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.policy_identifiers.pickle(out);
        self.mail_rua.pickle(out);
        self.http_rua.pickle(out);
        self.report.pickle(out);
        self.domain.pickle(out);
        self.created_at.pickle(out);
        self.deliver_at.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.policy_identifiers = Pickle::unpickle(stream)?;
        this.mail_rua = Pickle::unpickle(stream)?;
        this.http_rua = Pickle::unpickle(stream)?;
        this.report = Pickle::unpickle(stream)?;
        this.domain = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.deliver_at = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsInternalReport {
    fn default() -> Self {
        Self {
            policy_identifiers: Default::default(),
            mail_rua: Default::default(),
            http_rua: Default::default(),
            report: Default::default(),
            domain: Default::default(),
            created_at: Default::default(),
            deliver_at: Default::default(),
        }
    }
}

impl IntoValue for TlsInternalReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(
            Property::PolicyIdentifiers,
            self.policy_identifiers.into_value(),
        );
        map.insert_unchecked(Property::MailRua, self.mail_rua.into_value());
        map.insert_unchecked(Property::HttpRua, self.http_rua.into_value());
        map.insert_unchecked(Property::Report, self.report.into_value());
        map.insert_unchecked(Property::Domain, self.domain.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::DeliverAt, self.deliver_at.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsInternalReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::PolicyIdentifiers) => self.policy_identifiers.patch(pointer, value),
            Some(Property::MailRua) => self
                .mail_rua
                .patch(pointer.with_validators(&[StringValidator::Email]), value),
            Some(Property::HttpRua) => self.http_rua.patch(pointer, value),
            Some(Property::Report) => self.report.patch(pointer, value),
            Some(Property::Domain) => self
                .domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::CreatedAt) => self.created_at.patch(pointer, value),
            Some(Property::DeliverAt) => self.deliver_at.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TlsReport {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.organization_name {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::OrganizationName));
            }
        }
        if let Some(value) = &self.contact_info {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::ContactInfo));
            }
        }
        let value = &self.report_id;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::ReportId));
        }
        let value = &self.date_range_start;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DateRangeStart, value));
        }
        let value = &self.date_range_end;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::DateRangeEnd, value));
        }
        let value = &self.policies;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for TlsReport {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.organization_name.pickle(out);
        self.contact_info.pickle(out);
        self.report_id.pickle(out);
        self.date_range_start.pickle(out);
        self.date_range_end.pickle(out);
        self.policies.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.organization_name = Pickle::unpickle(stream)?;
        this.contact_info = Pickle::unpickle(stream)?;
        this.report_id = Pickle::unpickle(stream)?;
        this.date_range_start = Pickle::unpickle(stream)?;
        this.date_range_end = Pickle::unpickle(stream)?;
        this.policies = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsReport {
    fn default() -> Self {
        Self {
            organization_name: Default::default(),
            contact_info: Default::default(),
            report_id: Default::default(),
            date_range_start: Default::default(),
            date_range_end: Default::default(),
            policies: Default::default(),
        }
    }
}

impl IntoValue for TlsReport {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(8);
        map.insert_unchecked(
            Property::OrganizationName,
            self.organization_name.into_value(),
        );
        map.insert_unchecked(Property::ContactInfo, self.contact_info.into_value());
        map.insert_unchecked(Property::ReportId, self.report_id.into_value());
        map.insert_unchecked(Property::DateRangeStart, self.date_range_start.into_value());
        map.insert_unchecked(Property::DateRangeEnd, self.date_range_end.into_value());
        map.insert_unchecked(Property::Policies, self.policies.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsReport {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::OrganizationName) => self.organization_name.patch(pointer, value),
            Some(Property::ContactInfo) => self.contact_info.patch(pointer, value),
            Some(Property::ReportId) => self.report_id.patch(pointer, value),
            Some(Property::DateRangeStart) => self.date_range_start.patch(pointer, value),
            Some(Property::DateRangeEnd) => self.date_range_end.patch(pointer, value),
            Some(Property::Policies) => self.policies.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TlsReportPolicy {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.policy_strings;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::PolicyStrings));
            }
        }
        let value = &self.policy_domain;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::PolicyDomain));
        }
        let value = &self.mx_hosts;
        for value in value.iter() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::MxHosts));
            }
        }
        let value = &self.failure_details;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for TlsReportPolicy {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.policy_type.pickle(out);
        self.policy_strings.pickle(out);
        self.policy_domain.pickle(out);
        self.mx_hosts.pickle(out);
        self.total_successful_sessions.pickle(out);
        self.total_failed_sessions.pickle(out);
        self.failure_details.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.policy_type = Pickle::unpickle(stream)?;
        this.policy_strings = Pickle::unpickle(stream)?;
        this.policy_domain = Pickle::unpickle(stream)?;
        this.mx_hosts = Pickle::unpickle(stream)?;
        this.total_successful_sessions = Pickle::unpickle(stream)?;
        this.total_failed_sessions = Pickle::unpickle(stream)?;
        this.failure_details = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsReportPolicy {
    fn default() -> Self {
        Self {
            policy_type: Default::default(),
            policy_strings: Default::default(),
            policy_domain: Default::default(),
            mx_hosts: Default::default(),
            total_successful_sessions: 0u64,
            total_failed_sessions: 0u64,
            failure_details: Default::default(),
        }
    }
}

impl IntoValue for TlsReportPolicy {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(Property::PolicyType, self.policy_type.into_value());
        map.insert_unchecked(Property::PolicyStrings, self.policy_strings.into_value());
        map.insert_unchecked(Property::PolicyDomain, self.policy_domain.into_value());
        map.insert_unchecked(Property::MxHosts, self.mx_hosts.into_value());
        map.insert_unchecked(
            Property::TotalSuccessfulSessions,
            self.total_successful_sessions.into_value(),
        );
        map.insert_unchecked(
            Property::TotalFailedSessions,
            self.total_failed_sessions.into_value(),
        );
        map.insert_unchecked(Property::FailureDetails, self.failure_details.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsReportPolicy {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::PolicyType) => self.policy_type.patch(pointer, value),
            Some(Property::PolicyStrings) => self.policy_strings.patch(pointer, value),
            Some(Property::PolicyDomain) => self
                .policy_domain
                .patch(pointer.with_validators(&[StringValidator::Domain]), value),
            Some(Property::MxHosts) => self.mx_hosts.patch(pointer, value),
            Some(Property::TotalSuccessfulSessions) => {
                self.total_successful_sessions.patch(pointer, value)
            }
            Some(Property::TotalFailedSessions) => self.total_failed_sessions.patch(pointer, value),
            Some(Property::FailureDetails) => self.failure_details.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for TlsReportSettings {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::TlsReportSettings;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.contact_info;
        value.validate(errors);
        let value = &self.from_address;
        value.validate(errors);
        let value = &self.from_name;
        value.validate(errors);
        let value = &self.max_report_size;
        value.validate(errors);
        let value = &self.org_name;
        value.validate(errors);
        let value = &self.send_frequency;
        value.validate(errors);
        let value = &self.dkim_sign_domain;
        value.validate(errors);
        let value = &self.subject;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl TlsReportSettings {
    pub fn ctx_contact_info(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.contact_info,
            default: Some(Expression {
                else_: "false".to_string(),
                ..Default::default()
            }),
            property: Property::ContactInfo,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_from_address(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_address,
            default: Some(Expression {
                else_: "'noreply-tls@' + system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::FromAddress,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_from_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.from_name,
            default: Some(Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            }),
            property: Property::FromName,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_max_report_size(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.max_report_size,
            default: Some(Expression {
                else_: "5242880".to_string(),
                ..Default::default()
            }),
            property: Property::MaxReportSize,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_org_name(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.org_name,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::OrgName,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_send_frequency(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.send_frequency,
            default: Some(Expression {
                else_: "daily".to_string(),
                ..Default::default()
            }),
            property: Property::SendFrequency,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: MTA_AGGREGATE_CONSTANT,
        }
    }

    pub fn ctx_dkim_sign_domain(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.dkim_sign_domain,
            default: Some(Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            }),
            property: Property::DkimSignDomain,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn ctx_subject(&self) -> ExpressionContext<'_> {
        ExpressionContext {
            expr: &self.subject,
            default: Some(Expression {
                else_: "'TLS Aggregate Report'".to_string(),
                ..Default::default()
            }),
            property: Property::Subject,
            allowed_variables: MTA_QUEUE_HOST_VARIABLE,
            allowed_constants: &[],
        }
    }

    pub fn expression_ctxs(&self) -> Vec<ExpressionContext<'_>> {
        vec![
            self.ctx_contact_info(),
            self.ctx_from_address(),
            self.ctx_from_name(),
            self.ctx_max_report_size(),
            self.ctx_org_name(),
            self.ctx_send_frequency(),
            self.ctx_dkim_sign_domain(),
            self.ctx_subject(),
        ]
    }
}

impl Pickle for TlsReportSettings {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.contact_info.pickle(out);
        self.from_address.pickle(out);
        self.from_name.pickle(out);
        self.max_report_size.pickle(out);
        self.org_name.pickle(out);
        self.send_frequency.pickle(out);
        self.dkim_sign_domain.pickle(out);
        self.subject.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.contact_info = Pickle::unpickle(stream)?;
        this.from_address = Pickle::unpickle(stream)?;
        this.from_name = Pickle::unpickle(stream)?;
        this.max_report_size = Pickle::unpickle(stream)?;
        this.org_name = Pickle::unpickle(stream)?;
        this.send_frequency = Pickle::unpickle(stream)?;
        this.dkim_sign_domain = Pickle::unpickle(stream)?;
        this.subject = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TlsReportSettings {
    fn default() -> Self {
        Self {
            contact_info: Expression {
                else_: "false".to_string(),
                ..Default::default()
            },
            from_address: Expression {
                else_: "'noreply-tls@' + system('domain')".to_string(),
                ..Default::default()
            },
            from_name: Expression {
                else_: "'Report Subsystem'".to_string(),
                ..Default::default()
            },
            max_report_size: Expression {
                else_: "5242880".to_string(),
                ..Default::default()
            },
            org_name: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            send_frequency: Expression {
                else_: "daily".to_string(),
                ..Default::default()
            },
            dkim_sign_domain: Expression {
                else_: "system('domain')".to_string(),
                ..Default::default()
            },
            subject: Expression {
                else_: "'TLS Aggregate Report'".to_string(),
                ..Default::default()
            },
        }
    }
}

impl IntoValue for TlsReportSettings {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::ContactInfo, self.contact_info.into_value());
        map.insert_unchecked(Property::FromAddress, self.from_address.into_value());
        map.insert_unchecked(Property::FromName, self.from_name.into_value());
        map.insert_unchecked(Property::MaxReportSize, self.max_report_size.into_value());
        map.insert_unchecked(Property::OrgName, self.org_name.into_value());
        map.insert_unchecked(Property::SendFrequency, self.send_frequency.into_value());
        map.insert_unchecked(Property::DkimSignDomain, self.dkim_sign_domain.into_value());
        map.insert_unchecked(Property::Subject, self.subject.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TlsReportSettings {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::ContactInfo) => self.contact_info.patch(pointer, value),
            Some(Property::FromAddress) => self.from_address.patch(pointer, value),
            Some(Property::FromName) => self.from_name.patch(pointer, value),
            Some(Property::MaxReportSize) => self.max_report_size.patch(pointer, value),
            Some(Property::OrgName) => self.org_name.patch(pointer, value),
            Some(Property::SendFrequency) => self.send_frequency.patch(pointer, value),
            Some(Property::DkimSignDomain) => self.dkim_sign_domain.patch(pointer, value),
            Some(Property::Subject) => self.subject.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Trace {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Trace;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.events;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for Trace {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.events.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.events = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for Trace {
    fn default() -> Self {
        Self {
            events: Default::default(),
        }
    }
}

impl IntoValue for Trace {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Events, self.events.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for Trace {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::Timestamp) => pointer.assert_server_set(),
            Some(Property::From) => pointer.assert_server_set(),
            Some(Property::To) => pointer.assert_server_set(),
            Some(Property::Size) => pointer.assert_server_set(),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceEvent {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.timestamp;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Timestamp, value));
        }
        let value = &self.key_values;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for TraceEvent {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.event.pickle(out);
        self.timestamp.pickle(out);
        self.key_values.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.event = Pickle::unpickle(stream)?;
        this.timestamp = Pickle::unpickle(stream)?;
        this.key_values = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceEvent {
    fn default() -> Self {
        Self {
            event: Default::default(),
            timestamp: Default::default(),
            key_values: Default::default(),
        }
    }
}

impl IntoValue for TraceEvent {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(5);
        map.insert_unchecked(Property::Event, self.event.into_value());
        map.insert_unchecked(Property::Timestamp, self.timestamp.into_value());
        map.insert_unchecked(Property::KeyValues, self.key_values.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceEvent {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Event) => self.event.patch(pointer, value),
            Some(Property::Timestamp) => self.timestamp.patch(pointer, value),
            Some(Property::KeyValues) => self.key_values.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceKeyValue {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        value.validate(errors);
        errors.len() == neb
    }
}

impl Pickle for TraceKeyValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.key.pickle(out);
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.key = Pickle::unpickle(stream)?;
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceKeyValue {
    fn default() -> Self {
        Self {
            key: Default::default(),
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceKeyValue {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Key, self.key.into_value());
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceKeyValue {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Key) => self.key.patch(pointer, value),
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValue {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            TraceValue::String(inner) => inner.validate(errors),
            TraceValue::UnsignedInt(inner) => inner.validate(errors),
            TraceValue::Integer(inner) => inner.validate(errors),
            TraceValue::Boolean(inner) => inner.validate(errors),
            TraceValue::Float(inner) => inner.validate(errors),
            TraceValue::UTCDateTime(inner) => inner.validate(errors),
            TraceValue::Duration(inner) => inner.validate(errors),
            TraceValue::IpAddr(inner) => inner.validate(errors),
            TraceValue::List(inner) => inner.validate(errors),
            TraceValue::Event(inner) => inner.validate(errors),
            TraceValue::Null => true,
        }
    }
}

impl Default for TraceValue {
    fn default() -> Self {
        TraceValue::String(Default::default())
    }
}

impl Pickle for TraceValue {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            TraceValue::String(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::UnsignedInt(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Integer(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Boolean(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Float(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::UTCDateTime(inner) => {
                5u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Duration(inner) => {
                6u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::IpAddr(inner) => {
                7u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::List(inner) => {
                8u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Event(inner) => {
                9u16.pickle(out);
                inner.pickle(out);
            }
            TraceValue::Null => {
                10u16.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(TraceValue::String),
            1 => Pickle::unpickle(stream).map(TraceValue::UnsignedInt),
            2 => Pickle::unpickle(stream).map(TraceValue::Integer),
            3 => Pickle::unpickle(stream).map(TraceValue::Boolean),
            4 => Pickle::unpickle(stream).map(TraceValue::Float),
            5 => Pickle::unpickle(stream).map(TraceValue::UTCDateTime),
            6 => Pickle::unpickle(stream).map(TraceValue::Duration),
            7 => Pickle::unpickle(stream).map(TraceValue::IpAddr),
            8 => Pickle::unpickle(stream).map(TraceValue::List),
            9 => Pickle::unpickle(stream).map(TraceValue::Event),
            10 => Some(TraceValue::Null),
            _ => None,
        }
    }
}

impl IntoValue for TraceValue {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            TraceValue::String(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("String".into()));
                obj
            }
            TraceValue::UnsignedInt(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UnsignedInt".into()));
                obj
            }
            TraceValue::Integer(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Integer".into()));
                obj
            }
            TraceValue::Boolean(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Boolean".into()));
                obj
            }
            TraceValue::Float(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Float".into()));
                obj
            }
            TraceValue::UTCDateTime(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("UTCDateTime".into()));
                obj
            }
            TraceValue::Duration(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Duration".into()));
                obj
            }
            TraceValue::IpAddr(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("IpAddr".into()));
                obj
            }
            TraceValue::List(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("List".into()));
                obj
            }
            TraceValue::Event(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Event".into()));
                obj
            }
            TraceValue::Null => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Null".into()));
                JmapValue::Object(obj)
            }
        }
    }
}

impl RegistryJsonPatch for TraceValue {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TraceValueType::String => *self = TraceValue::String(Default::default()),
                TraceValueType::UnsignedInt => *self = TraceValue::UnsignedInt(Default::default()),
                TraceValueType::Integer => *self = TraceValue::Integer(Default::default()),
                TraceValueType::Boolean => *self = TraceValue::Boolean(Default::default()),
                TraceValueType::Float => *self = TraceValue::Float(Default::default()),
                TraceValueType::UTCDateTime => *self = TraceValue::UTCDateTime(Default::default()),
                TraceValueType::Duration => *self = TraceValue::Duration(Default::default()),
                TraceValueType::IpAddr => *self = TraceValue::IpAddr(Default::default()),
                TraceValueType::List => *self = TraceValue::List(Default::default()),
                TraceValueType::Event => *self = TraceValue::Event(Default::default()),
                TraceValueType::Null => *self = TraceValue::Null,
            }
        }
        match self {
            TraceValue::String(inner) => inner.patch(pointer, value),
            TraceValue::UnsignedInt(inner) => inner.patch(pointer, value),
            TraceValue::Integer(inner) => inner.patch(pointer, value),
            TraceValue::Boolean(inner) => inner.patch(pointer, value),
            TraceValue::Float(inner) => inner.patch(pointer, value),
            TraceValue::UTCDateTime(inner) => inner.patch(pointer, value),
            TraceValue::Duration(inner) => inner.patch(pointer, value),
            TraceValue::IpAddr(inner) => inner.patch(pointer, value),
            TraceValue::List(inner) => inner.patch(pointer, value),
            TraceValue::Event(inner) => inner.patch(pointer, value),
            TraceValue::Null => pointer.assert_eof(),
        }
    }
}

impl TraceValue {
    pub fn object_type(&self) -> TraceValueType {
        match self {
            TraceValue::String(_) => TraceValueType::String,
            TraceValue::UnsignedInt(_) => TraceValueType::UnsignedInt,
            TraceValue::Integer(_) => TraceValueType::Integer,
            TraceValue::Boolean(_) => TraceValueType::Boolean,
            TraceValue::Float(_) => TraceValueType::Float,
            TraceValue::UTCDateTime(_) => TraceValueType::UTCDateTime,
            TraceValue::Duration(_) => TraceValueType::Duration,
            TraceValue::IpAddr(_) => TraceValueType::IpAddr,
            TraceValue::List(_) => TraceValueType::List,
            TraceValue::Event(_) => TraceValueType::Event,
            TraceValue::Null => TraceValueType::Null,
        }
    }
}

impl TraceValueBoolean {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TraceValueBoolean {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueBoolean {
    fn default() -> Self {
        Self { value: false }
    }
}

impl IntoValue for TraceValueBoolean {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueBoolean {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueDuration {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TraceValueDuration {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueDuration {
    fn default() -> Self {
        Self { value: 0u64 }
    }
}

impl IntoValue for TraceValueDuration {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueDuration {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueEvent {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for TraceValueEvent {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.event.pickle(out);
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.event = Pickle::unpickle(stream)?;
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueEvent {
    fn default() -> Self {
        Self {
            event: Default::default(),
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceValueEvent {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(4);
        map.insert_unchecked(Property::Event, self.event.into_value());
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueEvent {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Event) => self.event.patch(pointer, value),
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueFloat {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TraceValueFloat {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueFloat {
    fn default() -> Self {
        Self {
            value: Float::new(0.0f64),
        }
    }
}

impl IntoValue for TraceValueFloat {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueFloat {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueInteger {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TraceValueInteger {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueInteger {
    fn default() -> Self {
        Self { value: 0i64 }
    }
}

impl IntoValue for TraceValueInteger {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueInteger {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueIpAddr {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Value, value));
        }
        errors.len() == neb
    }
}

impl Pickle for TraceValueIpAddr {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueIpAddr {
    fn default() -> Self {
        Self {
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceValueIpAddr {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueIpAddr {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueList {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        for value in value.values() {
            value.validate(errors);
        }
        errors.len() == neb
    }
}

impl Pickle for TraceValueList {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueList {
    fn default() -> Self {
        Self {
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceValueList {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueList {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueString {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Value));
        }
        errors.len() == neb
    }
}

impl Pickle for TraceValueString {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueString {
    fn default() -> Self {
        Self {
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceValueString {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueString {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueUTCDateTime {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.value;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::Value, value));
        }
        errors.len() == neb
    }
}

impl Pickle for TraceValueUTCDateTime {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueUTCDateTime {
    fn default() -> Self {
        Self {
            value: Default::default(),
        }
    }
}

impl IntoValue for TraceValueUTCDateTime {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueUTCDateTime {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TraceValueUnsignedInt {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TraceValueUnsignedInt {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.value.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.value = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TraceValueUnsignedInt {
    fn default() -> Self {
        Self { value: 0u64 }
    }
}

impl IntoValue for TraceValueUnsignedInt {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Value, self.value.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TraceValueUnsignedInt {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Value) => self.value.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for Tracer {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::Tracer;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            Tracer::Log(inner) => inner.validate(errors),
            Tracer::Stdout(inner) => inner.validate(errors),
            Tracer::Journal(inner) => inner.validate(errors),
            Tracer::OtelHttp(inner) => inner.validate(errors),
            Tracer::OtelGrpc(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for Tracer {
    fn default() -> Self {
        Tracer::Log(Default::default())
    }
}

impl Pickle for Tracer {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            Tracer::Log(inner) => {
                0u16.pickle(out);
                inner.pickle(out);
            }
            Tracer::Stdout(inner) => {
                1u16.pickle(out);
                inner.pickle(out);
            }
            Tracer::Journal(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            Tracer::OtelHttp(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            Tracer::OtelGrpc(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Pickle::unpickle(stream).map(Tracer::Log),
            1 => Pickle::unpickle(stream).map(Tracer::Stdout),
            2 => Pickle::unpickle(stream).map(Tracer::Journal),
            3 => Pickle::unpickle(stream).map(Tracer::OtelHttp),
            4 => Pickle::unpickle(stream).map(Tracer::OtelGrpc),
            _ => None,
        }
    }
}

impl IntoValue for Tracer {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            Tracer::Log(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Log".into()));
                obj
            }
            Tracer::Stdout(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Stdout".into()));
                obj
            }
            Tracer::Journal(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Journal".into()));
                obj
            }
            Tracer::OtelHttp(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("OtelHttp".into()));
                obj
            }
            Tracer::OtelGrpc(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("OtelGrpc".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for Tracer {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TracerType::Log => *self = Tracer::Log(Default::default()),
                TracerType::Stdout => *self = Tracer::Stdout(Default::default()),
                TracerType::Journal => *self = Tracer::Journal(Default::default()),
                TracerType::OtelHttp => *self = Tracer::OtelHttp(Default::default()),
                TracerType::OtelGrpc => *self = Tracer::OtelGrpc(Default::default()),
            }
        }
        match self {
            Tracer::Log(inner) => inner.patch(pointer, value),
            Tracer::Stdout(inner) => inner.patch(pointer, value),
            Tracer::Journal(inner) => inner.patch(pointer, value),
            Tracer::OtelHttp(inner) => inner.patch(pointer, value),
            Tracer::OtelGrpc(inner) => inner.patch(pointer, value),
        }
    }
}

impl Tracer {
    pub fn object_type(&self) -> TracerType {
        match self {
            Tracer::Log(_) => TracerType::Log,
            Tracer::Stdout(_) => TracerType::Stdout,
            Tracer::Journal(_) => TracerType::Journal,
            Tracer::OtelHttp(_) => TracerType::OtelHttp,
            Tracer::OtelGrpc(_) => TracerType::OtelGrpc,
        }
    }
}

impl TracerCommon {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TracerCommon {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TracerCommon {
    fn default() -> Self {
        Self {
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for TracerCommon {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(7);
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TracerCommon {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TracerLog {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.path;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Path));
        }
        let value = &self.prefix;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Prefix));
        }
        errors.len() == neb
    }
}

impl Pickle for TracerLog {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.path.pickle(out);
        self.prefix.pickle(out);
        self.rotate.pickle(out);
        self.ansi.pickle(out);
        self.multiline.pickle(out);
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.path = Pickle::unpickle(stream)?;
        this.prefix = Pickle::unpickle(stream)?;
        this.rotate = Pickle::unpickle(stream)?;
        this.ansi = Pickle::unpickle(stream)?;
        this.multiline = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TracerLog {
    fn default() -> Self {
        Self {
            path: Default::default(),
            prefix: "stalwart".to_string(),
            rotate: LogRotateFrequency::Daily,
            ansi: true,
            multiline: false,
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for TracerLog {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(12);
        map.insert_unchecked(Property::Path, self.path.into_value());
        map.insert_unchecked(Property::Prefix, self.prefix.into_value());
        map.insert_unchecked(Property::Rotate, self.rotate.into_value());
        map.insert_unchecked(Property::Ansi, self.ansi.into_value());
        map.insert_unchecked(Property::Multiline, self.multiline.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TracerLog {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Path) => self
                .path
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Prefix) => self
                .prefix
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Rotate) => self.rotate.patch(pointer, value),
            Some(Property::Ansi) => self.ansi.patch(pointer, value),
            Some(Property::Multiline) => self.multiline.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TracerOtelGrpc {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        if let Some(value) = &self.endpoint {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Endpoint));
            }
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for TracerOtelGrpc {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.endpoint.pickle(out);
        self.enable_log_exporter.pickle(out);
        self.enable_span_exporter.pickle(out);
        self.throttle.pickle(out);
        self.timeout.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.endpoint = Pickle::unpickle(stream)?;
        this.enable_log_exporter = Pickle::unpickle(stream)?;
        this.enable_span_exporter = Pickle::unpickle(stream)?;
        this.throttle = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TracerOtelGrpc {
    fn default() -> Self {
        Self {
            endpoint: Default::default(),
            enable_log_exporter: true,
            enable_span_exporter: true,
            throttle: Duration::from_millis(1000),
            timeout: Duration::from_millis(10000),
            http_auth: Default::default(),
            http_headers: Default::default(),
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for TracerOtelGrpc {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Endpoint, self.endpoint.into_value());
        map.insert_unchecked(
            Property::EnableLogExporter,
            self.enable_log_exporter.into_value(),
        );
        map.insert_unchecked(
            Property::EnableSpanExporter,
            self.enable_span_exporter.into_value(),
        );
        map.insert_unchecked(Property::Throttle, self.throttle.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TracerOtelGrpc {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Endpoint) => self
                .endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::EnableLogExporter) => self.enable_log_exporter.patch(pointer, value),
            Some(Property::EnableSpanExporter) => self.enable_span_exporter.patch(pointer, value),
            Some(Property::Throttle) => self.throttle.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TracerOtelHttp {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.endpoint;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Endpoint));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }
}

impl Pickle for TracerOtelHttp {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.endpoint.pickle(out);
        self.enable_log_exporter.pickle(out);
        self.enable_span_exporter.pickle(out);
        self.throttle.pickle(out);
        self.timeout.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.endpoint = Pickle::unpickle(stream)?;
        this.enable_log_exporter = Pickle::unpickle(stream)?;
        this.enable_span_exporter = Pickle::unpickle(stream)?;
        this.throttle = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TracerOtelHttp {
    fn default() -> Self {
        Self {
            endpoint: Default::default(),
            enable_log_exporter: true,
            enable_span_exporter: true,
            throttle: Duration::from_millis(1000),
            timeout: Duration::from_millis(10000),
            http_auth: Default::default(),
            http_headers: Default::default(),
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for TracerOtelHttp {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(14);
        map.insert_unchecked(Property::Endpoint, self.endpoint.into_value());
        map.insert_unchecked(
            Property::EnableLogExporter,
            self.enable_log_exporter.into_value(),
        );
        map.insert_unchecked(
            Property::EnableSpanExporter,
            self.enable_span_exporter.into_value(),
        );
        map.insert_unchecked(Property::Throttle, self.throttle.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TracerOtelHttp {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Endpoint) => self
                .endpoint
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::EnableLogExporter) => self.enable_log_exporter.patch(pointer, value),
            Some(Property::EnableSpanExporter) => self.enable_span_exporter.patch(pointer, value),
            Some(Property::Throttle) => self.throttle.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl TracerStdout {
    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }
}

impl Pickle for TracerStdout {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.buffered.pickle(out);
        self.ansi.pickle(out);
        self.multiline.pickle(out);
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.buffered = Pickle::unpickle(stream)?;
        this.ansi = Pickle::unpickle(stream)?;
        this.multiline = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for TracerStdout {
    fn default() -> Self {
        Self {
            buffered: true,
            ansi: false,
            multiline: false,
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for TracerStdout {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(10);
        map.insert_unchecked(Property::Buffered, self.buffered.into_value());
        map.insert_unchecked(Property::Ansi, self.ansi.into_value());
        map.insert_unchecked(Property::Multiline, self.multiline.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for TracerStdout {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Buffered) => self.buffered.patch(pointer, value),
            Some(Property::Ansi) => self.ansi.patch(pointer, value),
            Some(Property::Multiline) => self.multiline.patch(pointer, value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for TracingStore {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::TracingStore;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            TracingStore::Disabled => true,
            TracingStore::Default => true,
            TracingStore::FoundationDb(inner) => inner.validate(errors),
            TracingStore::PostgreSql(inner) => inner.validate(errors),
            TracingStore::MySql(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Default for TracingStore {
    fn default() -> Self {
        TracingStore::Disabled
    }
}

impl Pickle for TracingStore {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            TracingStore::Disabled => {
                0u16.pickle(out);
            }
            TracingStore::Default => {
                1u16.pickle(out);
            }
            TracingStore::FoundationDb(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
            TracingStore::PostgreSql(inner) => {
                3u16.pickle(out);
                inner.pickle(out);
            }
            TracingStore::MySql(inner) => {
                4u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(TracingStore::Disabled),
            1 => Some(TracingStore::Default),
            2 => Pickle::unpickle(stream).map(TracingStore::FoundationDb),
            3 => Pickle::unpickle(stream).map(TracingStore::PostgreSql),
            4 => Pickle::unpickle(stream).map(TracingStore::MySql),
            _ => None,
        }
    }
}

impl IntoValue for TracingStore {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            TracingStore::Disabled => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Disabled".into()));
                JmapValue::Object(obj)
            }
            TracingStore::Default => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Default".into()));
                JmapValue::Object(obj)
            }
            TracingStore::FoundationDb(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("FoundationDb".into()));
                obj
            }
            TracingStore::PostgreSql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("PostgreSql".into()));
                obj
            }
            TracingStore::MySql(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("MySql".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for TracingStore {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                TracingStoreType::Disabled => *self = TracingStore::Disabled,
                TracingStoreType::Default => *self = TracingStore::Default,
                TracingStoreType::FoundationDb => {
                    *self = TracingStore::FoundationDb(Default::default())
                }
                TracingStoreType::PostgreSql => {
                    *self = TracingStore::PostgreSql(Default::default())
                }
                TracingStoreType::MySql => *self = TracingStore::MySql(Default::default()),
            }
        }
        match self {
            TracingStore::Disabled => pointer.assert_eof(),
            TracingStore::Default => pointer.assert_eof(),
            TracingStore::FoundationDb(inner) => inner.patch(pointer, value),
            TracingStore::PostgreSql(inner) => inner.patch(pointer, value),
            TracingStore::MySql(inner) => inner.patch(pointer, value),
        }
    }
}

impl TracingStore {
    pub fn object_type(&self) -> TracingStoreType {
        match self {
            TracingStore::Disabled => TracingStoreType::Disabled,
            TracingStore::Default => TracingStoreType::Default,
            TracingStore::FoundationDb(_) => TracingStoreType::FoundationDb,
            TracingStore::PostgreSql(_) => TracingStoreType::PostgreSql,
            TracingStore::MySql(_) => TracingStoreType::MySql,
        }
    }
}

impl UserAccount {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.name;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Name));
        }
        let value = &self.domain_id;
        if !value.is_valid() {
            errors.push(ValidationError::required(Property::DomainId));
        }
        let value = &self.credentials;
        for value in value.values() {
            value.validate(errors);
        }
        let value = &self.created_at;
        if !value.is_valid() {
            errors.push(ValidationError::invalid(Property::CreatedAt, value));
        }
        let value = &self.member_group_ids;
        for value in value.iter() {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberGroupIds));
            }
        }
        if let Some(value) = &self.member_tenant_id {
            if !value.is_valid() {
                errors.push(ValidationError::required(Property::MemberTenantId));
            }
        }
        let value = &self.roles;
        value.validate(errors);
        let value = &self.permissions;
        value.validate(errors);
        let value = &self.aliases;
        for value in value.values() {
            value.validate(errors);
        }
        if let Some(value) = &self.description {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::Description));
            }
        }
        let value = &self.encryption_at_rest;
        value.validate(errors);
        errors.len() == neb
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        i.unique_global_composite(Property::Email, &self.name, &self.domain_id);
        i.text(Property::Text, &self.name);
        i.search(Property::Name, &self.name);
        i.foreign_key(ObjectType::Domain, self.domain_id.into(), None);
        i.search(Property::DomainId, &self.domain_id);
        for id in self.member_group_ids.iter() {
            i.foreign_key(
                ObjectType::Account,
                Some(*id),
                Some(AccountType::Group.to_id()),
            );
        }
        for value in self.member_group_ids.iter() {
            i.search(Property::MemberGroupIds, value);
        }
        i.foreign_key(ObjectType::Tenant, self.member_tenant_id, None);
        if let Some(value) = &self.member_tenant_id {
            i.search(Property::MemberTenantId, value);
        }
        self.roles.index(i);
        for item in self.aliases.values() {
            item.index(i);
        }
        if let Some(value) = &self.description {
            i.text(Property::Text, value);
        }
        self.encryption_at_rest.index(i);
    }
}

impl Pickle for UserAccount {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.name.pickle(out);
        self.domain_id.pickle(out);
        self.credentials.pickle(out);
        self.created_at.pickle(out);
        self.member_group_ids.pickle(out);
        self.member_tenant_id.pickle(out);
        self.roles.pickle(out);
        self.permissions.pickle(out);
        self.quotas.pickle(out);
        self.aliases.pickle(out);
        self.description.pickle(out);
        self.locale.pickle(out);
        self.time_zone.pickle(out);
        self.encryption_at_rest.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.name = Pickle::unpickle(stream)?;
        this.domain_id = Pickle::unpickle(stream)?;
        this.credentials = Pickle::unpickle(stream)?;
        this.created_at = Pickle::unpickle(stream)?;
        this.member_group_ids = Pickle::unpickle(stream)?;
        this.member_tenant_id = Pickle::unpickle(stream)?;
        this.roles = Pickle::unpickle(stream)?;
        this.permissions = Pickle::unpickle(stream)?;
        this.quotas = Pickle::unpickle(stream)?;
        this.aliases = Pickle::unpickle(stream)?;
        this.description = Pickle::unpickle(stream)?;
        this.locale = Pickle::unpickle(stream)?;
        this.time_zone = Pickle::unpickle(stream)?;
        this.encryption_at_rest = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for UserAccount {
    fn default() -> Self {
        Self {
            name: Default::default(),
            domain_id: Default::default(),
            credentials: Default::default(),
            created_at: Default::default(),
            member_group_ids: Default::default(),
            member_tenant_id: Default::default(),
            roles: Default::default(),
            permissions: Default::default(),
            quotas: Default::default(),
            aliases: Default::default(),
            description: Default::default(),
            locale: Locale::EnUS,
            time_zone: Default::default(),
            encryption_at_rest: Default::default(),
        }
    }
}

impl IntoValue for UserAccount {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(16);
        map.insert_unchecked(Property::Name, self.name.into_value());
        map.insert_unchecked(Property::DomainId, self.domain_id.into_value());
        map.insert_unchecked(Property::Credentials, self.credentials.into_value());
        map.insert_unchecked(Property::CreatedAt, self.created_at.into_value());
        map.insert_unchecked(Property::MemberGroupIds, self.member_group_ids.into_value());
        map.insert_unchecked(Property::MemberTenantId, self.member_tenant_id.into_value());
        map.insert_unchecked(Property::Roles, self.roles.into_value());
        map.insert_unchecked(Property::Permissions, self.permissions.into_value());
        map.insert_unchecked(Property::Quotas, self.quotas.into_value());
        map.insert_unchecked(Property::Aliases, self.aliases.into_value());
        map.insert_unchecked(Property::Description, self.description.into_value());
        map.insert_unchecked(Property::Locale, self.locale.into_value());
        map.insert_unchecked(Property::TimeZone, self.time_zone.into_value());
        map.insert_unchecked(
            Property::EncryptionAtRest,
            self.encryption_at_rest.into_value(),
        );
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for UserAccount {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Name) => self.name.patch(
                pointer.with_validators(&[StringValidator::EmailLocalPart]),
                value,
            ),
            Some(Property::DomainId) => self.domain_id.patch(pointer, value),
            Some(Property::EmailAddress) => pointer.assert_server_set(),
            Some(Property::Credentials) => self.credentials.patch(pointer, value),
            Some(Property::CreatedAt) => pointer.assert_server_set(),
            Some(Property::MemberGroupIds) => self.member_group_ids.patch(pointer, value),
            Some(Property::MemberTenantId) => self
                .member_tenant_id
                .patch(pointer.assert_can_set_tenant()?, value),
            Some(Property::Roles) => self.roles.patch(pointer, value),
            Some(Property::Permissions) => self.permissions.patch(pointer, value),
            Some(Property::Quotas) => self.quotas.patch(pointer, value),
            Some(Property::UsedDiskQuota) => pointer.assert_server_set(),
            Some(Property::Aliases) => self.aliases.patch(pointer, value),
            Some(Property::Description) => self.description.patch(pointer, value),
            Some(Property::Locale) => self.locale.patch(pointer, value),
            Some(Property::TimeZone) => self.time_zone.patch(pointer, value),
            Some(Property::EncryptionAtRest) => self.encryption_at_rest.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl UserRoles {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        match self {
            UserRoles::User => true,
            UserRoles::Admin => true,
            UserRoles::Custom(inner) => inner.validate(errors),
        }
    }

    fn index<'x>(&'x self, i: &mut IndexBuilder<'x>) {
        match self {
            UserRoles::User => {}
            UserRoles::Admin => {}
            UserRoles::Custom(object) => {
                object.index(i);
            }
        }
    }
}

impl Default for UserRoles {
    fn default() -> Self {
        UserRoles::User
    }
}

impl Pickle for UserRoles {
    fn pickle(&self, out: &mut Vec<u8>) {
        match self {
            UserRoles::User => {
                0u16.pickle(out);
            }
            UserRoles::Admin => {
                1u16.pickle(out);
            }
            UserRoles::Custom(inner) => {
                2u16.pickle(out);
                inner.pickle(out);
            }
        }
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        match u16::unpickle(stream)? {
            0 => Some(UserRoles::User),
            1 => Some(UserRoles::Admin),
            2 => Pickle::unpickle(stream).map(UserRoles::Custom),
            _ => None,
        }
    }
}

impl IntoValue for UserRoles {
    fn into_value(self) -> JmapValue<'static> {
        match self {
            UserRoles::User => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("User".into()));
                JmapValue::Object(obj)
            }
            UserRoles::Admin => {
                let mut obj = jmap_tools::Map::new();
                obj.insert_unchecked(Property::Type, JmapValue::Str("Admin".into()));
                JmapValue::Object(obj)
            }
            UserRoles::Custom(obj) => {
                let mut obj = obj.into_value();
                obj.as_object_mut()
                    .unwrap()
                    .insert_unchecked(Property::Type, JmapValue::Str("Custom".into()));
                obj
            }
        }
    }
}

impl RegistryJsonPatch for UserRoles {
    fn patch<'x>(
        &mut self,
        pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        if !pointer.has_next() {
            match object_type(&pointer, &value)? {
                UserRolesType::User => *self = UserRoles::User,
                UserRolesType::Admin => *self = UserRoles::Admin,
                UserRolesType::Custom => *self = UserRoles::Custom(Default::default()),
            }
        }
        match self {
            UserRoles::User => pointer.assert_eof(),
            UserRoles::Admin => pointer.assert_eof(),
            UserRoles::Custom(inner) => inner.patch(pointer, value),
        }
    }
}

impl UserRoles {
    pub fn object_type(&self) -> UserRolesType {
        match self {
            UserRoles::User => UserRolesType::User,
            UserRoles::Admin => UserRolesType::Admin,
            UserRoles::Custom(_) => UserRolesType::Custom,
        }
    }
}

impl ObjectImpl for WebDav {
    const FLAGS: u64 = OBJ_SINGLETON;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::WebDav;

    fn validate(&self, _: &mut Vec<ValidationError>) -> bool {
        true
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for WebDav {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.enable_assisted_discovery.pickle(out);
        self.max_lock_timeout.pickle(out);
        self.max_locks.pickle(out);
        self.dead_property_max_size.pickle(out);
        self.live_property_max_size.pickle(out);
        self.request_max_size.pickle(out);
        self.max_results.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.enable_assisted_discovery = Pickle::unpickle(stream)?;
        this.max_lock_timeout = Pickle::unpickle(stream)?;
        this.max_locks = Pickle::unpickle(stream)?;
        this.dead_property_max_size = Pickle::unpickle(stream)?;
        this.live_property_max_size = Pickle::unpickle(stream)?;
        this.request_max_size = Pickle::unpickle(stream)?;
        this.max_results = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for WebDav {
    fn default() -> Self {
        Self {
            enable_assisted_discovery: true,
            max_lock_timeout: Duration::from_millis(3600000),
            max_locks: 10u64,
            dead_property_max_size: Some(1024u64),
            live_property_max_size: 250u64,
            request_max_size: 26214400,
            max_results: 2000u64,
        }
    }
}

impl IntoValue for WebDav {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(9);
        map.insert_unchecked(
            Property::EnableAssistedDiscovery,
            self.enable_assisted_discovery.into_value(),
        );
        map.insert_unchecked(Property::MaxLockTimeout, self.max_lock_timeout.into_value());
        map.insert_unchecked(Property::MaxLocks, self.max_locks.into_value());
        map.insert_unchecked(
            Property::DeadPropertyMaxSize,
            self.dead_property_max_size.into_value(),
        );
        map.insert_unchecked(
            Property::LivePropertyMaxSize,
            self.live_property_max_size.into_value(),
        );
        map.insert_unchecked(Property::RequestMaxSize, self.request_max_size.into_value());
        map.insert_unchecked(Property::MaxResults, self.max_results.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for WebDav {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::EnableAssistedDiscovery) => {
                self.enable_assisted_discovery.patch(pointer, value)
            }
            Some(Property::MaxLockTimeout) => self.max_lock_timeout.patch(pointer, value),
            Some(Property::MaxLocks) => self.max_locks.patch(pointer, value),
            Some(Property::DeadPropertyMaxSize) => {
                self.dead_property_max_size.patch(pointer, value)
            }
            Some(Property::LivePropertyMaxSize) => {
                self.live_property_max_size.patch(pointer, value)
            }
            Some(Property::RequestMaxSize) => self.request_max_size.patch(pointer, value),
            Some(Property::MaxResults) => self.max_results.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ObjectImpl for WebHook {
    const FLAGS: u64 = 0;
    const VERSION: u8 = 0;
    const OBJECT: ObjectType = ObjectType::WebHook;

    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.signature_key;
        value.validate(errors);
        let value = &self.url;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Url));
        }
        let value = &self.http_auth;
        value.validate(errors);
        let value = &self.http_headers;
        for value in value.values() {
            if value.is_empty() {
                errors.push(ValidationError::required(Property::HttpHeaders));
            }
        }
        errors.len() == neb
    }

    fn index<'x>(&'x self, _: &mut IndexBuilder<'x>) {}
}

impl Pickle for WebHook {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.allow_invalid_certs.pickle(out);
        self.signature_key.pickle(out);
        self.throttle.pickle(out);
        self.timeout.pickle(out);
        self.discard_after.pickle(out);
        self.url.pickle(out);
        self.http_auth.pickle(out);
        self.http_headers.pickle(out);
        self.enable.pickle(out);
        self.level.pickle(out);
        self.lossy.pickle(out);
        self.events.pickle(out);
        self.events_policy.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.allow_invalid_certs = Pickle::unpickle(stream)?;
        this.signature_key = Pickle::unpickle(stream)?;
        this.throttle = Pickle::unpickle(stream)?;
        this.timeout = Pickle::unpickle(stream)?;
        this.discard_after = Pickle::unpickle(stream)?;
        this.url = Pickle::unpickle(stream)?;
        this.http_auth = Pickle::unpickle(stream)?;
        this.http_headers = Pickle::unpickle(stream)?;
        this.enable = Pickle::unpickle(stream)?;
        this.level = Pickle::unpickle(stream)?;
        this.lossy = Pickle::unpickle(stream)?;
        this.events = Pickle::unpickle(stream)?;
        this.events_policy = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for WebHook {
    fn default() -> Self {
        Self {
            allow_invalid_certs: false,
            signature_key: Default::default(),
            throttle: Duration::from_millis(1000),
            timeout: Duration::from_millis(30000),
            discard_after: Duration::from_millis(300000),
            url: Default::default(),
            http_auth: Default::default(),
            http_headers: Default::default(),
            enable: true,
            level: TracingLevel::Info,
            lossy: false,
            events: Default::default(),
            events_policy: EventPolicy::Exclude,
        }
    }
}

impl IntoValue for WebHook {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(15);
        map.insert_unchecked(
            Property::AllowInvalidCerts,
            self.allow_invalid_certs.into_value(),
        );
        map.insert_unchecked(Property::SignatureKey, self.signature_key.into_value());
        map.insert_unchecked(Property::Throttle, self.throttle.into_value());
        map.insert_unchecked(Property::Timeout, self.timeout.into_value());
        map.insert_unchecked(Property::DiscardAfter, self.discard_after.into_value());
        map.insert_unchecked(Property::Url, self.url.into_value());
        map.insert_unchecked(Property::HttpAuth, self.http_auth.into_value());
        map.insert_unchecked(Property::HttpHeaders, self.http_headers.into_value());
        map.insert_unchecked(Property::Enable, self.enable.into_value());
        map.insert_unchecked(Property::Level, self.level.into_value());
        map.insert_unchecked(Property::Lossy, self.lossy.into_value());
        map.insert_unchecked(Property::Events, self.events.into_value());
        map.insert_unchecked(Property::EventsPolicy, self.events_policy.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for WebHook {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::AllowInvalidCerts) => self.allow_invalid_certs.patch(pointer, value),
            Some(Property::SignatureKey) => self.signature_key.patch(pointer, value),
            Some(Property::Throttle) => self.throttle.patch(pointer, value),
            Some(Property::Timeout) => self.timeout.patch(pointer, value),
            Some(Property::DiscardAfter) => self.discard_after.patch(pointer, value),
            Some(Property::Url) => self
                .url
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::HttpAuth) => self.http_auth.patch(pointer, value),
            Some(Property::HttpHeaders) => self
                .http_headers
                .patch(pointer.with_validators(&[StringValidator::Trim]), value),
            Some(Property::Enable) => self.enable.patch(pointer, value),
            Some(Property::Level) => self.level.patch(pointer, value),
            Some(Property::Lossy) => self.lossy.patch(pointer, value),
            Some(Property::Events) => self.events.patch(pointer, value),
            Some(Property::EventsPolicy) => self.events_policy.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}

impl ZenohCoordinator {
    fn validate(&self, errors: &mut Vec<ValidationError>) -> bool {
        let neb = errors.len();
        let value = &self.config;
        if value.is_empty() {
            errors.push(ValidationError::required(Property::Config));
        }
        errors.len() == neb
    }
}

impl Pickle for ZenohCoordinator {
    fn pickle(&self, out: &mut Vec<u8>) {
        self.config.pickle(out);
    }

    fn unpickle(stream: &mut crate::pickle::PickledStream<'_>) -> Option<Self> {
        let mut this = Self::default();
        this.config = Pickle::unpickle(stream)?;
        Some(this)
    }
}

impl Default for ZenohCoordinator {
    fn default() -> Self {
        Self {
            config: Default::default(),
        }
    }
}

impl IntoValue for ZenohCoordinator {
    fn into_value(self) -> JmapValue<'static> {
        let mut map = jmap_tools::Map::with_capacity(3);
        map.insert_unchecked(Property::Config, self.config.into_value());
        JmapValue::Object(map)
    }
}

impl RegistryJsonPropertyPatch for ZenohCoordinator {
    fn patch_property<'x>(
        &mut self,
        mut pointer: JsonPointerPatch<'_>,
        value: JmapValue<'x>,
    ) -> PatchResult<'x> {
        match pointer.next_property() {
            Some(Property::Config) => self.config.patch(pointer, value),
            Some(Property::Type) => Ok(MaybeUnpatched::Unpatched {
                property: Property::Type,
                value,
            }),
            _ => Err(PatchError::new(pointer, "Invalid property")),
        }
    }
}
