<commit_before>//! Common types for [encryption] related tasks.
//!
//! [encryption]: https://matrix.org/docs/spec/client_server/r0.6.1#id76

use std::collections::BTreeMap;

use ruma_identifiers::{DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId};
use ruma_serde::Base64;
use serde::{Deserialize, Serialize};

/// Identity keys for a device.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct DeviceKeys {
    /// The ID of the user the device belongs to.
    ///
    /// Must match the user ID used when logging in.
    pub user_id: Box<UserId>,

    /// The ID of the device these keys belong to.
    ///
    /// Must match the device ID used when logging in.
    pub device_id: Box<DeviceId>,

    /// The encryption algorithms supported by this device.
    pub algorithms: Vec<EventEncryptionAlgorithm>,

    /// Public identity keys.
    pub keys: BTreeMap<Box<DeviceKeyId>, String>,

    /// Signatures for the device key object.
    pub signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,

    /// Additional data added to the device key information by intermediate servers, and
    /// not covered by the signatures.
    #[serde(default, skip_serializing_if = "UnsignedDeviceInfo::is_empty")]
    pub unsigned: UnsignedDeviceInfo,
}

impl DeviceKeys {
    /// Creates a new `DeviceKeys` from the given user id, device id, algorithms, keys and
    /// signatures.
    pub fn new(
        user_id: Box<UserId>,
        device_id: Box<DeviceId>,
        algorithms: Vec<EventEncryptionAlgorithm>,
        keys: BTreeMap<Box<DeviceKeyId>, String>,
        signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
    ) -> Self {
        Self { user_id, device_id, algorithms, keys, signatures, unsigned: Default::default() }
    }
}

/// Additional data added to device key information by intermediate servers.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct UnsignedDeviceInfo {
    /// The display name which the user set on the device.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub device_display_name: Option<String>,
}

impl UnsignedDeviceInfo {
    /// Creates an empty `UnsignedDeviceInfo`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Checks whether all fields are empty / `None`.
    pub fn is_empty(&self) -> bool {
        self.device_display_name.is_none()
    }
}

/// Signatures for a `SignedKey` object.
pub type SignedKeySignatures = BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>;

/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SignedKey {
    /// Base64-encoded 32-byte Curve25519 public key.
    pub key: Base64,

    /// Signatures for the key object.
    pub signatures: SignedKeySignatures,

    /// Is this key considered to be a fallback key, defaults to false.
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    pub fallback: bool,
}

impl SignedKey {
    /// Creates a new `SignedKey` with the given key and signatures.
    pub fn new(key: Base64, signatures: SignedKeySignatures) -> Self {
        Self {
            key,
            signatures,
            #[cfg(feature = "unstable-pre-spec")]
            fallback: false,
        }
    }

    /// Creates a new fallback `SignedKey` with the given key and signatures.
    #[cfg(feature = "unstable-pre-spec")]
    pub fn new_fallback(key: Base64, signatures: SignedKeySignatures) -> Self {
        Self { key, signatures, fallback: true }
    }
}

/// A one-time public key for "pre-key" messages.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum OneTimeKey {
    /// A key containing signatures, for the SignedCurve25519 algorithm.
    SignedKey(SignedKey),

    /// A string-valued key, for the Ed25519 and Curve25519 algorithms.
    Key(String),
}

/// Signatures for a `CrossSigningKey` object.
pub type CrossSigningKeySignatures = BTreeMap<Box<UserId>, BTreeMap<String, String>>;

/// A cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CrossSigningKey {
    /// The ID of the user the key belongs to.
    pub user_id: Box<UserId>,

    /// What the key is used for.
    pub usage: Vec<KeyUsage>,

    /// The public key.
    ///
    /// The object must have exactly one property.
    pub keys: BTreeMap<String, String>,

    /// Signatures of the key.
    ///
    /// Only optional for master key.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub signatures: CrossSigningKeySignatures,
}

impl CrossSigningKey {
    /// Creates a new `CrossSigningKey` with the given user ID, usage, keys and signatures.
    pub fn new(
        user_id: Box<UserId>,
        usage: Vec<KeyUsage>,
        keys: BTreeMap<String, String>,
        signatures: CrossSigningKeySignatures,
    ) -> Self {
        Self { user_id, usage, keys, signatures }
    }
}

/// The usage of a cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
    /// Master key.
    Master,

    /// Self-signing key.
    SelfSigning,

    /// User-signing key.
    UserSigning,
}
<commit_msg>common: Remove leftover feature gate<commit_after>//! Common types for [encryption] related tasks.
//!
//! [encryption]: https://matrix.org/docs/spec/client_server/r0.6.1#id76

use std::collections::BTreeMap;

use ruma_identifiers::{DeviceId, DeviceKeyId, EventEncryptionAlgorithm, UserId};
use ruma_serde::Base64;
use serde::{Deserialize, Serialize};

/// Identity keys for a device.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct DeviceKeys {
    /// The ID of the user the device belongs to.
    ///
    /// Must match the user ID used when logging in.
    pub user_id: Box<UserId>,

    /// The ID of the device these keys belong to.
    ///
    /// Must match the device ID used when logging in.
    pub device_id: Box<DeviceId>,

    /// The encryption algorithms supported by this device.
    pub algorithms: Vec<EventEncryptionAlgorithm>,

    /// Public identity keys.
    pub keys: BTreeMap<Box<DeviceKeyId>, String>,

    /// Signatures for the device key object.
    pub signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,

    /// Additional data added to the device key information by intermediate servers, and
    /// not covered by the signatures.
    #[serde(default, skip_serializing_if = "UnsignedDeviceInfo::is_empty")]
    pub unsigned: UnsignedDeviceInfo,
}

impl DeviceKeys {
    /// Creates a new `DeviceKeys` from the given user id, device id, algorithms, keys and
    /// signatures.
    pub fn new(
        user_id: Box<UserId>,
        device_id: Box<DeviceId>,
        algorithms: Vec<EventEncryptionAlgorithm>,
        keys: BTreeMap<Box<DeviceKeyId>, String>,
        signatures: BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>,
    ) -> Self {
        Self { user_id, device_id, algorithms, keys, signatures, unsigned: Default::default() }
    }
}

/// Additional data added to device key information by intermediate servers.
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct UnsignedDeviceInfo {
    /// The display name which the user set on the device.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub device_display_name: Option<String>,
}

impl UnsignedDeviceInfo {
    /// Creates an empty `UnsignedDeviceInfo`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Checks whether all fields are empty / `None`.
    pub fn is_empty(&self) -> bool {
        self.device_display_name.is_none()
    }
}

/// Signatures for a `SignedKey` object.
pub type SignedKeySignatures = BTreeMap<Box<UserId>, BTreeMap<Box<DeviceKeyId>, String>>;

/// A key for the SignedCurve25519 algorithm
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct SignedKey {
    /// Base64-encoded 32-byte Curve25519 public key.
    pub key: Base64,

    /// Signatures for the key object.
    pub signatures: SignedKeySignatures,

    /// Is this key considered to be a fallback key, defaults to false.
    #[serde(default, skip_serializing_if = "ruma_serde::is_default")]
    pub fallback: bool,
}

impl SignedKey {
    /// Creates a new `SignedKey` with the given key and signatures.
    pub fn new(key: Base64, signatures: SignedKeySignatures) -> Self {
        Self { key, signatures, fallback: false }
    }

    /// Creates a new fallback `SignedKey` with the given key and signatures.
    #[cfg(feature = "unstable-pre-spec")]
    pub fn new_fallback(key: Base64, signatures: SignedKeySignatures) -> Self {
        Self { key, signatures, fallback: true }
    }
}

/// A one-time public key for "pre-key" messages.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(untagged)]
pub enum OneTimeKey {
    /// A key containing signatures, for the SignedCurve25519 algorithm.
    SignedKey(SignedKey),

    /// A string-valued key, for the Ed25519 and Curve25519 algorithms.
    Key(String),
}

/// Signatures for a `CrossSigningKey` object.
pub type CrossSigningKeySignatures = BTreeMap<Box<UserId>, BTreeMap<String, String>>;

/// A cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct CrossSigningKey {
    /// The ID of the user the key belongs to.
    pub user_id: Box<UserId>,

    /// What the key is used for.
    pub usage: Vec<KeyUsage>,

    /// The public key.
    ///
    /// The object must have exactly one property.
    pub keys: BTreeMap<String, String>,

    /// Signatures of the key.
    ///
    /// Only optional for master key.
    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
    pub signatures: CrossSigningKeySignatures,
}

impl CrossSigningKey {
    /// Creates a new `CrossSigningKey` with the given user ID, usage, keys and signatures.
    pub fn new(
        user_id: Box<UserId>,
        usage: Vec<KeyUsage>,
        keys: BTreeMap<String, String>,
        signatures: CrossSigningKeySignatures,
    ) -> Self {
        Self { user_id, usage, keys, signatures }
    }
}

/// The usage of a cross signing key.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[serde(rename_all = "snake_case")]
pub enum KeyUsage {
    /// Master key.
    Master,

    /// Self-signing key.
    SelfSigning,

    /// User-signing key.
    UserSigning,
}
<|endoftext|>


<commit_before>//! Common types for the [third party networks module][thirdparty].
//!
//! [thirdparty]: https://matrix.org/docs/spec/client_server/r0.6.1#id153

use std::collections::BTreeMap;

use ruma_identifiers::{RoomAliasId, UserId};
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};

use crate::{MilliSecondsSinceUnixEpoch, PrivOwnedStr};

/// Metadata about a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInit` and convert it via
/// `Protocol::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Protocol {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    ///
    /// If you activate the `compat` feature, this field being absent in JSON will result in an
    /// empty string here during deserialization.
    #[cfg_attr(feature = "compat", serde(default))]
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ProtocolInit {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

impl From<ProtocolInit> for Protocol {
    fn from(init: ProtocolInit) -> Self {
        let ProtocolInit { user_fields, location_fields, icon, field_types, instances } = init;
        Self { user_fields, location_fields, icon, field_types, instances }
    }
}

/// Metadata about an instance of a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInstanceInit` and convert it via
/// `ProtocolInstance::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ProtocolInstance {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// An optional content URI representing the protocol.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icon: Option<String>,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,

    /// A unique identifier across all instances.
    #[cfg(feature = "unstable-pre-spec")]
    pub instance_id: String,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ProtocolInstanceInit {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,

    /// A unique identifier across all instances.
    #[cfg(feature = "unstable-pre-spec")]
    pub instance_id: String,
}

impl From<ProtocolInstanceInit> for ProtocolInstance {
    fn from(init: ProtocolInstanceInit) -> Self {
        let ProtocolInstanceInit {
            desc,
            fields,
            network_id,
            #[cfg(feature = "unstable-pre-spec")]
            instance_id,
        } = init;
        Self {
            desc,
            icon: None,
            fields,
            network_id,
            #[cfg(feature = "unstable-pre-spec")]
            instance_id,
        }
    }
}

/// A type definition for a field used to identify third party users or locations.
///
/// To create an instance of this type, first create a `FieldTypeInit` and convert it via
/// `FieldType::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct FieldType {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

/// Initial set of fields of `FieldType`.
///
/// This struct will not be updated even if additional fields are added to `FieldType` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct FieldTypeInit {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

impl From<FieldTypeInit> for FieldType {
    fn from(init: FieldTypeInit) -> Self {
        let FieldTypeInit { regexp, placeholder } = init;
        Self { regexp, placeholder }
    }
}

/// A third party network location.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Location {
    /// An alias for a matrix room.
    pub alias: Box<RoomAliasId>,

    /// The protocol ID that the third party location is a part of.
    pub protocol: String,

    /// Information used to identify this third party location.
    pub fields: BTreeMap<String, String>,
}

impl Location {
    /// Creates a new `Location` with the given alias, protocol and fields.
    pub fn new(
        alias: Box<RoomAliasId>,
        protocol: String,
        fields: BTreeMap<String, String>,
    ) -> Self {
        Self { alias, protocol, fields }
    }
}

/// A third party network user.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct User {
    /// A matrix user ID representing a third party user.
    pub userid: Box<UserId>,

    /// The protocol ID that the third party user is a part of.
    pub protocol: String,

    /// Information used to identify this third party user.
    pub fields: BTreeMap<String, String>,
}

impl User {
    /// Creates a new `User` with the given userid, protocol and fields.
    pub fn new(userid: Box<UserId>, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { userid, protocol, fields }
    }
}

/// The medium of a third party identifier.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Medium {
    /// Email address identifier
    Email,

    /// Phone number identifier
    Msisdn,

    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl Medium {
    /// Creates a string slice from this `Medium`.
    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

/// An identifier external to Matrix.
///
/// To create an instance of this type, first create a `ThirdPartyIdentifierInit` and convert it to
/// this type using `ThirdPartyIdentifier::Init` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ThirdPartyIdentifier {
    /// The third party identifier address.
    pub address: String,

    /// The medium of third party identifier.
    pub medium: Medium,

    /// The time when the identifier was validated by the identity server.
    pub validated_at: MilliSecondsSinceUnixEpoch,

    /// The time when the homeserver associated the third party identifier with the user.
    pub added_at: MilliSecondsSinceUnixEpoch,
}

/// Initial set of fields of `ThirdPartyIdentifier`.
///
/// This struct will not be updated even if additional fields are added to `ThirdPartyIdentifier`
/// in a new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ThirdPartyIdentifierInit {
    /// The third party identifier address.
    pub address: String,

    /// The medium of third party identifier.
    pub medium: Medium,

    /// The time when the identifier was validated by the identity server.
    pub validated_at: MilliSecondsSinceUnixEpoch,

    /// The time when the homeserver associated the third party identifier with the user.
    pub added_at: MilliSecondsSinceUnixEpoch,
}

impl From<ThirdPartyIdentifierInit> for ThirdPartyIdentifier {
    fn from(init: ThirdPartyIdentifierInit) -> Self {
        let ThirdPartyIdentifierInit { address, medium, validated_at, added_at } = init;
        ThirdPartyIdentifier { address, medium, validated_at, added_at }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{Medium, ThirdPartyIdentifier};
    use crate::MilliSecondsSinceUnixEpoch;

    #[test]
    fn third_party_identifier_serde() {
        let third_party_id = ThirdPartyIdentifier {
            address: "monkey@banana.island".into(),
            medium: Medium::Email,
            validated_at: MilliSecondsSinceUnixEpoch(1_535_176_800_000_u64.try_into().unwrap()),
            added_at: MilliSecondsSinceUnixEpoch(1_535_336_848_756_u64.try_into().unwrap()),
        };

        let third_party_id_serialized = json!({
            "medium": "email",
            "address": "monkey@banana.island",
            "validated_at": 1_535_176_800_000_u64,
            "added_at": 1_535_336_848_756_u64
        });

        assert_eq!(to_json_value(third_party_id.clone()).unwrap(), third_party_id_serialized);
        assert_eq!(third_party_id, from_json_value(third_party_id_serialized).unwrap());
    }
}
<commit_msg>common: Add link to matrix-doc issue for ProtocolInstance's instance_id field<commit_after>//! Common types for the [third party networks module][thirdparty].
//!
//! [thirdparty]: https://matrix.org/docs/spec/client_server/r0.6.1#id153

use std::collections::BTreeMap;

use ruma_identifiers::{RoomAliasId, UserId};
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};

use crate::{MilliSecondsSinceUnixEpoch, PrivOwnedStr};

/// Metadata about a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInit` and convert it via
/// `Protocol::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Protocol {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    ///
    /// If you activate the `compat` feature, this field being absent in JSON will result in an
    /// empty string here during deserialization.
    #[cfg_attr(feature = "compat", serde(default))]
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ProtocolInit {
    /// Fields which may be used to identify a third party user.
    pub user_fields: Vec<String>,

    /// Fields which may be used to identify a third party location.
    pub location_fields: Vec<String>,

    /// A content URI representing an icon for the third party protocol.
    pub icon: String,

    /// The type definitions for the fields defined in `user_fields` and `location_fields`.
    pub field_types: BTreeMap<String, FieldType>,

    /// A list of objects representing independent instances of configuration.
    pub instances: Vec<ProtocolInstance>,
}

impl From<ProtocolInit> for Protocol {
    fn from(init: ProtocolInit) -> Self {
        let ProtocolInit { user_fields, location_fields, icon, field_types, instances } = init;
        Self { user_fields, location_fields, icon, field_types, instances }
    }
}

/// Metadata about an instance of a third party protocol.
///
/// To create an instance of this type, first create a `ProtocolInstanceInit` and convert it via
/// `ProtocolInstance::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct ProtocolInstance {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// An optional content URI representing the protocol.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub icon: Option<String>,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,

    /// A unique identifier across all instances.
    ///
    /// See [matrix-doc#3203](https://github.com/matrix-org/matrix-doc/issues/3203).
    #[cfg(feature = "unstable-pre-spec")]
    pub instance_id: String,
}

/// Initial set of fields of `Protocol`.
///
/// This struct will not be updated even if additional fields are added to `Prococol` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ProtocolInstanceInit {
    /// A human-readable description for the protocol, such as the name.
    pub desc: String,

    /// Preset values for `fields` the client may use to search by.
    pub fields: BTreeMap<String, String>,

    /// A unique identifier across all instances.
    pub network_id: String,

    /// A unique identifier across all instances.
    ///
    /// See [matrix-doc#3203](https://github.com/matrix-org/matrix-doc/issues/3203).
    #[cfg(feature = "unstable-pre-spec")]
    pub instance_id: String,
}

impl From<ProtocolInstanceInit> for ProtocolInstance {
    fn from(init: ProtocolInstanceInit) -> Self {
        let ProtocolInstanceInit {
            desc,
            fields,
            network_id,
            #[cfg(feature = "unstable-pre-spec")]
            instance_id,
        } = init;
        Self {
            desc,
            icon: None,
            fields,
            network_id,
            #[cfg(feature = "unstable-pre-spec")]
            instance_id,
        }
    }
}

/// A type definition for a field used to identify third party users or locations.
///
/// To create an instance of this type, first create a `FieldTypeInit` and convert it via
/// `FieldType::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct FieldType {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

/// Initial set of fields of `FieldType`.
///
/// This struct will not be updated even if additional fields are added to `FieldType` in a new
/// (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct FieldTypeInit {
    /// A regular expression for validation of a field's value.
    pub regexp: String,

    /// A placeholder serving as a valid example of the field value.
    pub placeholder: String,
}

impl From<FieldTypeInit> for FieldType {
    fn from(init: FieldTypeInit) -> Self {
        let FieldTypeInit { regexp, placeholder } = init;
        Self { regexp, placeholder }
    }
}

/// A third party network location.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Location {
    /// An alias for a matrix room.
    pub alias: Box<RoomAliasId>,

    /// The protocol ID that the third party location is a part of.
    pub protocol: String,

    /// Information used to identify this third party location.
    pub fields: BTreeMap<String, String>,
}

impl Location {
    /// Creates a new `Location` with the given alias, protocol and fields.
    pub fn new(
        alias: Box<RoomAliasId>,
        protocol: String,
        fields: BTreeMap<String, String>,
    ) -> Self {
        Self { alias, protocol, fields }
    }
}

/// A third party network user.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct User {
    /// A matrix user ID representing a third party user.
    pub userid: Box<UserId>,

    /// The protocol ID that the third party user is a part of.
    pub protocol: String,

    /// Information used to identify this third party user.
    pub fields: BTreeMap<String, String>,
}

impl User {
    /// Creates a new `User` with the given userid, protocol and fields.
    pub fn new(userid: Box<UserId>, protocol: String, fields: BTreeMap<String, String>) -> Self {
        Self { userid, protocol, fields }
    }
}

/// The medium of a third party identifier.
///
/// This type can hold an arbitrary string. To check for formats that are not available as a
/// documented variant here, use its string representation, obtained through `.as_str()`.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "lowercase")]
#[non_exhaustive]
pub enum Medium {
    /// Email address identifier
    Email,

    /// Phone number identifier
    Msisdn,

    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl Medium {
    /// Creates a string slice from this `Medium`.
    pub fn as_str(&self) -> &str {
        self.as_ref()
    }
}

/// An identifier external to Matrix.
///
/// To create an instance of this type, first create a `ThirdPartyIdentifierInit` and convert it to
/// this type using `ThirdPartyIdentifier::Init` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[cfg_attr(test, derive(PartialEq))]
pub struct ThirdPartyIdentifier {
    /// The third party identifier address.
    pub address: String,

    /// The medium of third party identifier.
    pub medium: Medium,

    /// The time when the identifier was validated by the identity server.
    pub validated_at: MilliSecondsSinceUnixEpoch,

    /// The time when the homeserver associated the third party identifier with the user.
    pub added_at: MilliSecondsSinceUnixEpoch,
}

/// Initial set of fields of `ThirdPartyIdentifier`.
///
/// This struct will not be updated even if additional fields are added to `ThirdPartyIdentifier`
/// in a new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct ThirdPartyIdentifierInit {
    /// The third party identifier address.
    pub address: String,

    /// The medium of third party identifier.
    pub medium: Medium,

    /// The time when the identifier was validated by the identity server.
    pub validated_at: MilliSecondsSinceUnixEpoch,

    /// The time when the homeserver associated the third party identifier with the user.
    pub added_at: MilliSecondsSinceUnixEpoch,
}

impl From<ThirdPartyIdentifierInit> for ThirdPartyIdentifier {
    fn from(init: ThirdPartyIdentifierInit) -> Self {
        let ThirdPartyIdentifierInit { address, medium, validated_at, added_at } = init;
        ThirdPartyIdentifier { address, medium, validated_at, added_at }
    }
}

#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{Medium, ThirdPartyIdentifier};
    use crate::MilliSecondsSinceUnixEpoch;

    #[test]
    fn third_party_identifier_serde() {
        let third_party_id = ThirdPartyIdentifier {
            address: "monkey@banana.island".into(),
            medium: Medium::Email,
            validated_at: MilliSecondsSinceUnixEpoch(1_535_176_800_000_u64.try_into().unwrap()),
            added_at: MilliSecondsSinceUnixEpoch(1_535_336_848_756_u64.try_into().unwrap()),
        };

        let third_party_id_serialized = json!({
            "medium": "email",
            "address": "monkey@banana.island",
            "validated_at": 1_535_176_800_000_u64,
            "added_at": 1_535_336_848_756_u64
        });

        assert_eq!(to_json_value(third_party_id.clone()).unwrap(), third_party_id_serialized);
        assert_eq!(third_party_id, from_json_value(third_party_id_serialized).unwrap());
    }
}
<|endoftext|>


<commit_before><commit_msg>Add `draw::mesh::vertex::IntoPoint` trait with many impls<commit_after><|endoftext|>


<commit_before>trait IsUnit {
    fn is_unit() -> bool;
}

impl<T> IsUnit for T {
    default fn is_unit() -> bool { false }
}

impl IsUnit for () {
    fn is_unit() -> bool { true }
}

fn specialization() -> (bool, bool) {
    (i32::is_unit(), <()>::is_unit())
}

fn main() {
    assert_eq!(specialization(), (false, true));
}
<commit_msg>fix master<commit_after>#![feature(specialization)]

trait IsUnit {
    fn is_unit() -> bool;
}

impl<T> IsUnit for T {
    default fn is_unit() -> bool { false }
}

impl IsUnit for () {
    fn is_unit() -> bool { true }
}

fn specialization() -> (bool, bool) {
    (i32::is_unit(), <()>::is_unit())
}

fn main() {
    assert_eq!(specialization(), (false, true));
}
<|endoftext|>


<commit_before>/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9));
    /// ```
    pub fn inverse(&self, n: f64) -> i32 {
        ((n - self.offset) / self.scale).round() as i32
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 1.,
            offset: 0.,
        }
    }
}
<commit_msg>Set default scale to 0.01 (1cm)<commit_after>/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
    /// The scale.
    pub scale: f64,
    /// The offset.
    pub offset: f64,
}

impl Transform {
    /// Applies this transform to an i32, returning a float.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(3., transform.direct(1));
    /// ```
    pub fn direct(&self, n: i32) -> f64 {
        self.scale * n as f64 + self.offset
    }

    /// Applies the inverse transform, and rounds the result.
    ///
    /// # Examples
    ///
    /// ```
    /// # use las::Transform;
    /// let transform = Transform { scale: 2., offset: 1. };
    /// assert_eq!(1, transform.inverse(2.9));
    /// ```
    pub fn inverse(&self, n: f64) -> i32 {
        ((n - self.offset) / self.scale).round() as i32
    }
}

impl Default for Transform {
    fn default() -> Transform {
        Transform {
            scale: 0.01,
            offset: 0.,
        }
    }
}
<|endoftext|>


<commit_before>use serde_derive::{Deserialize, Serialize};
use std::slice;
use vitral::SRgba;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_regular: bool,
    /// 4-bit components, R << 8 + G << 4 + B.
    color: u16,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_regular: true,  color: 0xF0F },
    Exit:        TerrainData { name: "exit",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_regular: true,  color: 0x0EE },
    Entrance:    TerrainData { name: "entrance",  kind: Kind::Ground, form: Form::Gate,  map_chars: "<",   is_regular: true,  color: 0x0FF },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ".,_", is_regular: true,  color: 0x111 },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x231 },
    Sand:        TerrainData { name: "sand",      kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x650 },
    Snow:        TerrainData { name: "snow",      kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x788 },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_regular: true,  color: 0x058 },
    Shallows:    TerrainData { name: "shallows",  kind: Kind::Ground, form: Form::Floor, map_chars: "~=",  is_regular: true,  color: 0x08B },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_regular: true,  color: 0xF22 },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_regular: true,  color: 0x8B1 },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "#*",  is_regular: true,  color: 0xBBB },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "*#",  is_regular: true,  color: 0xB84 },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_regular: true,  color: 0x842 },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_regular: false, color: 0xFAF },
    Window:      TerrainData { name: "window",    kind: Kind::Window, form: Form::Wall,  map_chars: "+",   is_regular: true,  color: 0xBFF },
    Pillar:      TerrainData { name: "pillar",    kind: Kind::Block,  form: Form::Prop,  map_chars: "I",   is_regular: true,  color: 0xCCD },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_regular: false, color: 0x230 },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> { TERRAIN_ENUM.iter() }

    pub fn from_color(color: SRgba) -> Option<Terrain> {
        let key =
            (((color.r >> 4) as u16) << 8) + (((color.g >> 4) as u16) << 4) + (color.b >> 4) as u16;
        Self::iter()
            .filter(|t| t.is_regular())
            .find(|t| TERRAIN_DATA[**t as usize].color == key)
            .cloned()
    }

    #[inline(always)]
    pub fn kind(self) -> Kind { TERRAIN_DATA[self as usize].kind }

    #[inline(always)]
    pub fn form(self) -> Form { TERRAIN_DATA[self as usize].form }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_regular(self) -> bool { TERRAIN_DATA[self as usize].is_regular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str { TERRAIN_DATA[self as usize].map_chars }

    /// Terrain is a narrow object that blocks movement.
    ///
    /// Prop obstacles might not be distinguishable from floors if you only see a corner of the
    /// terrain tile. Use this if there's need to highlight partially visible terrain as obstacles.
    pub fn is_narrow_obstacle(self) -> bool { self.blocks_walk() && self.form() == Form::Prop }

    pub fn color(self) -> SRgba {
        let col = TERRAIN_DATA[self as usize].color;
        let r = ((col >> 8) & 0xf) as u8;
        let g = ((col >> 4) & 0xf) as u8;
        let b = (col & 0xf) as u8;

        SRgba::new(r << 4, g << 4, b << 4, 0xff)
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use calx::SRgba;

    #[test]
    fn test_colors_are_unique() {
        use std::collections::HashSet;

        let terrains: HashSet<Terrain> = Terrain::iter()
            .filter(|t| t.is_regular())
            .cloned()
            .collect();
        let colors: HashSet<SRgba> = terrains.iter().map(|t| t.color()).collect();

        assert_eq!(colors.len(), terrains.len());
    }

    #[test]
    fn test_from_color() {
        assert_eq!(
            Terrain::from_color(SRgba::new(0xff, 0x88, 0xff, 0xff)),
            None
        );
        assert_eq!(
            Terrain::from_color(SRgba::new(0x22, 0x30, 0x1f, 0xff)),
            Some(Terrain::Grass)
        );
    }
}
<commit_msg>Fix tests<commit_after>use serde_derive::{Deserialize, Serialize};
use std::slice;
use vitral::SRgba;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_regular: bool,
    /// 4-bit components, R << 8 + G << 4 + B.
    color: u16,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_regular: true,  color: 0xF0F },
    Exit:        TerrainData { name: "exit",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_regular: true,  color: 0x0EE },
    Entrance:    TerrainData { name: "entrance",  kind: Kind::Ground, form: Form::Gate,  map_chars: "<",   is_regular: true,  color: 0x0FF },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ".,_", is_regular: true,  color: 0x111 },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x231 },
    Sand:        TerrainData { name: "sand",      kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x650 },
    Snow:        TerrainData { name: "snow",      kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_regular: true,  color: 0x788 },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_regular: true,  color: 0x058 },
    Shallows:    TerrainData { name: "shallows",  kind: Kind::Ground, form: Form::Floor, map_chars: "~=",  is_regular: true,  color: 0x08B },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_regular: true,  color: 0xF22 },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_regular: true,  color: 0x8B1 },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "#*",  is_regular: true,  color: 0xBBB },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "*#",  is_regular: true,  color: 0xB84 },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_regular: true,  color: 0x842 },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_regular: false, color: 0xFAF },
    Window:      TerrainData { name: "window",    kind: Kind::Window, form: Form::Wall,  map_chars: "+",   is_regular: true,  color: 0xBFF },
    Pillar:      TerrainData { name: "pillar",    kind: Kind::Block,  form: Form::Prop,  map_chars: "I",   is_regular: true,  color: 0xCCD },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_regular: false, color: 0x230 },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> { TERRAIN_ENUM.iter() }

    pub fn from_color(color: SRgba) -> Option<Terrain> {
        let key =
            (((color.r >> 4) as u16) << 8) + (((color.g >> 4) as u16) << 4) + (color.b >> 4) as u16;
        Self::iter()
            .filter(|t| t.is_regular())
            .find(|t| TERRAIN_DATA[**t as usize].color == key)
            .cloned()
    }

    #[inline(always)]
    pub fn kind(self) -> Kind { TERRAIN_DATA[self as usize].kind }

    #[inline(always)]
    pub fn form(self) -> Form { TERRAIN_DATA[self as usize].form }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_regular(self) -> bool { TERRAIN_DATA[self as usize].is_regular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str { TERRAIN_DATA[self as usize].map_chars }

    /// Terrain is a narrow object that blocks movement.
    ///
    /// Prop obstacles might not be distinguishable from floors if you only see a corner of the
    /// terrain tile. Use this if there's need to highlight partially visible terrain as obstacles.
    pub fn is_narrow_obstacle(self) -> bool { self.blocks_walk() && self.form() == Form::Prop }

    pub fn color(self) -> SRgba {
        let col = TERRAIN_DATA[self as usize].color;
        let r = ((col >> 8) & 0xf) as u8;
        let g = ((col >> 4) & 0xf) as u8;
        let b = (col & 0xf) as u8;

        SRgba::new(r << 4, g << 4, b << 4, 0xff)
    }
}

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

#[cfg(test)]
mod test {
    use super::*;
    use vitral::SRgba;

    #[test]
    fn test_colors_are_unique() {
        use std::collections::HashSet;

        let terrains: HashSet<Terrain> = Terrain::iter()
            .filter(|t| t.is_regular())
            .cloned()
            .collect();
        let colors: HashSet<SRgba> = terrains.iter().map(|t| t.color()).collect();

        assert_eq!(colors.len(), terrains.len());
    }

    #[test]
    fn test_from_color() {
        assert_eq!(
            Terrain::from_color(SRgba::new(0xff, 0x88, 0xff, 0xff)),
            None
        );
        assert_eq!(
            Terrain::from_color(SRgba::new(0x22, 0x30, 0x1f, 0xff)),
            Some(Terrain::Grass)
        );
    }
}
<|endoftext|>


<commit_before>use adivon::queue::Queue;

pub struct Node<V> {
    c: char,
    left:  Option<Box<Node<V>>>,
    mid:   Option<Box<Node<V>>>,
    right: Option<Box<Node<V>>>,
    val: Option<V>,
}

impl<V> Node<V> {
    fn new(c: char) -> Node<V> {
        Node {
            c: c,
            left: None,
            mid: None,
            right: None,
            val: None
        }
    }

    fn put(mut x: Option<Box<Node<V>>>, key: &str, val: Option<V>, d: usize) -> (Option<Box<Node<V>>>, Option<V>) {
        let replaced;
        let c = key.char_at(d);
        if x.is_none() {
            if val.is_none() {  // no need to call put further
                return (x, None);
            }
            x = Some(Box::new(Node::new(c)));
        }
        let xc = x.as_ref().unwrap().c;
        if c < xc {
            let (left, repl) = Node::put(x.as_mut().unwrap().left.take(), key, val, d);
            x.as_mut().map(|n| n.left = left);
            replaced = repl;
        } else if c > xc {
            let (right, repl) = Node::put(x.as_mut().unwrap().right.take(), key, val, d);
            x.as_mut().map(|n| n.right = right);
            replaced = repl;
        } else if d < key.len()-1 {
            let (mid, repl) = Node::put(x.as_mut().unwrap().mid.take(), key, val, d+1);
            x.as_mut().map(|n| n.mid = mid);
            replaced = repl;
        } else {
            replaced = x.as_mut().unwrap().val.take();
            x.as_mut().map(|n| n.val = val);
        }
        (x, replaced)
    }

    fn get<'a>(x: Option<&'a Box<Node<V>>>, key: &str, d: usize) -> Option<&'a Box<Node<V>>> {
        if x.is_none() {
            return None;
        }
        let c = key.char_at(d);
        let xc = x.unwrap().c;
        if c < xc {
            Node::get(x.unwrap().left.as_ref(), key, d)
        } else if c > xc {
            Node::get(x.unwrap().right.as_ref(), key, d)
        } else if d < key.len()-1 {
            Node::get(x.unwrap().mid.as_ref(), key, d+1)
        } else {
            x
        }
    }

    fn collect(x: Option<&Box<Node<V>>>, mut prefix: String, queue: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        Node::collect(x.unwrap().left.as_ref(), prefix.clone(), queue);
        let xc = x.unwrap().c;
        prefix.push(xc);
        if x.unwrap().val.is_some() {
            queue.enqueue(prefix.clone());
        }
        Node::collect(x.unwrap().mid.as_ref(), prefix.clone(), queue);
        prefix.pop();
        Node::collect(x.unwrap().right.as_ref(), prefix, queue);
    }
}

/// Symbol table with string keys, implemented using a ternary search trie (TST).
pub struct TernarySearchTrie<V> {
    root: Option<Box<Node<V>>>,
    n: usize
}

impl<V> TernarySearchTrie<V>  {
    pub fn new() -> TernarySearchTrie<V> {
        TernarySearchTrie { root: None, n: 0 }
    }

    pub fn put(&mut self, key: &str, val: V) {
        let (root, replaced) = Node::put(self.root.take(), key, Some(val), 0);
        self.root = root;
        // replace old val? or insert new?
        if replaced.is_none() {
            self.n += 1;
        }
    }

    pub fn get(&self, key: &str) -> Option<&V> {
        assert!(key.len() > 0, "key must have length >= 1");
        Node::get(self.root.as_ref(), key, 0).map_or(None, |n| n.val.as_ref())
    }

    pub fn delete(&mut self, key: &str) {
        let (root, replaced) = Node::put(self.root.take(), key, None, 0);
        self.root = root;
        // deleted?
        if replaced.is_some() {
            self.n -= 1;
        }
    }

    pub fn size(&self) -> usize {
        self.n
    }

    pub fn is_empty(&self) -> bool {
        self.n == 0
    }

    pub fn contains(&self, key: &str) -> bool {
        self.get(key).is_some()
    }

    pub fn keys_with_prefix(&self, prefix: &str) -> Vec<String> {
        let mut queue = Queue::new();
        let x = Node::get(self.root.as_ref(), prefix, 0);
        if x.is_some() {
            if x.unwrap().val.is_some() {
                queue.enqueue(prefix.into());
            }
            Node::collect(x.unwrap().mid.as_ref(), prefix.into(), &mut queue);
        }
        queue.into_iter().collect()
    }

    pub fn keys(&self) -> Vec<String> {
        let mut queue = Queue::new();
        Node::collect(self.root.as_ref(), "".into(), &mut queue);
        queue.into_iter().collect()
    }
}

#[test]
fn test_tst() {
    let mut t = TernarySearchTrie::new();
    assert_eq!(t.size(), 0);
    t.put("name", "Andelf");
    assert_eq!(t.size(), 1);
    assert!(t.contains("name"));
    t.put("name", "Fledna");
    assert_eq!(t.size(), 1);
    t.put("language", "Rust");
    assert_eq!(t.size(), 2);

    assert_eq!(t.get("name"), Some(&"Fledna"));
    assert_eq!(t.get("whatever"), None);

    t.delete("name");
    assert_eq!(t.size(), 1);
    assert_eq!(t.get("name"), None);

    t.put("name", "Lednaf");
    assert!(t.keys().contains(&"name".into()));
    assert!(t.keys().contains(&"language".into()));
    assert!(t.keys_with_prefix("lang").contains(&"language".into()));
}
<commit_msg>tries/tst: implement longest_prefix_of() for TernarySearchTrie<commit_after>use adivon::queue::Queue;

pub struct Node<V> {
    c: char,
    left:  Option<Box<Node<V>>>,
    mid:   Option<Box<Node<V>>>,
    right: Option<Box<Node<V>>>,
    val: Option<V>,
}

impl<V> Node<V> {
    fn new(c: char) -> Node<V> {
        Node {
            c: c,
            left: None,
            mid: None,
            right: None,
            val: None
        }
    }

    fn put(mut x: Option<Box<Node<V>>>, key: &str, val: Option<V>, d: usize) -> (Option<Box<Node<V>>>, Option<V>) {
        let replaced;
        let c = key.char_at(d);
        if x.is_none() {
            if val.is_none() {  // no need to call put further
                return (x, None);
            }
            x = Some(Box::new(Node::new(c)));
        }
        let xc = x.as_ref().unwrap().c;
        if c < xc {
            let (left, repl) = Node::put(x.as_mut().unwrap().left.take(), key, val, d);
            x.as_mut().map(|n| n.left = left);
            replaced = repl;
        } else if c > xc {
            let (right, repl) = Node::put(x.as_mut().unwrap().right.take(), key, val, d);
            x.as_mut().map(|n| n.right = right);
            replaced = repl;
        } else if d < key.len()-1 {
            let (mid, repl) = Node::put(x.as_mut().unwrap().mid.take(), key, val, d+1);
            x.as_mut().map(|n| n.mid = mid);
            replaced = repl;
        } else {
            replaced = x.as_mut().unwrap().val.take();
            x.as_mut().map(|n| n.val = val);
        }
        (x, replaced)
    }

    fn get<'a>(x: Option<&'a Box<Node<V>>>, key: &str, d: usize) -> Option<&'a Box<Node<V>>> {
        if x.is_none() {
            return None;
        }
        let c = key.char_at(d);
        let xc = x.unwrap().c;
        if c < xc {
            Node::get(x.unwrap().left.as_ref(), key, d)
        } else if c > xc {
            Node::get(x.unwrap().right.as_ref(), key, d)
        } else if d < key.len()-1 {
            Node::get(x.unwrap().mid.as_ref(), key, d+1)
        } else {
            x
        }
    }

    fn collect(x: Option<&Box<Node<V>>>, mut prefix: String, queue: &mut Queue<String>) {
        if x.is_none() {
            return;
        }
        Node::collect(x.unwrap().left.as_ref(), prefix.clone(), queue);
        let xc = x.unwrap().c;
        prefix.push(xc);
        if x.unwrap().val.is_some() {
            queue.enqueue(prefix.clone());
        }
        Node::collect(x.unwrap().mid.as_ref(), prefix.clone(), queue);
        prefix.pop();
        Node::collect(x.unwrap().right.as_ref(), prefix, queue);
    }

    fn longest_prefix_of<'a>(mut x: Option<&Box<Node<V>>>, query: &'a str) -> Option<&'a str> {
        let mut length = 0;
        let mut i = 0;
        while x.is_some() && i < query.len() {
            let c = query.char_at(i);
            let xc = x.unwrap().c;
            if c < xc {
                x = x.unwrap().left.as_ref();
            } else if c > xc {
                x = x.unwrap().right.as_ref();
            } else {
                i += 1;
                if x.unwrap().val.is_some() {
                    length = i;
                }
                x = x.unwrap().mid.as_ref();
            }
        }
        if length == 0 {
            None
        } else {
            Some(&query[..length])
        }
    }
}

/// Symbol table with string keys, implemented using a ternary search trie (TST).
pub struct TernarySearchTrie<V> {
    root: Option<Box<Node<V>>>,
    n: usize
}

impl<V> TernarySearchTrie<V>  {
    pub fn new() -> TernarySearchTrie<V> {
        TernarySearchTrie { root: None, n: 0 }
    }

    pub fn put(&mut self, key: &str, val: V) {
        let (root, replaced) = Node::put(self.root.take(), key, Some(val), 0);
        self.root = root;
        // replace old val? or insert new?
        if replaced.is_none() {
            self.n += 1;
        }
    }

    pub fn get(&self, key: &str) -> Option<&V> {
        assert!(key.len() > 0, "key must have length >= 1");
        Node::get(self.root.as_ref(), key, 0).map_or(None, |n| n.val.as_ref())
    }

    pub fn delete(&mut self, key: &str) {
        let (root, replaced) = Node::put(self.root.take(), key, None, 0);
        self.root = root;
        // deleted?
        if replaced.is_some() {
            self.n -= 1;
        }
    }

    pub fn size(&self) -> usize {
        self.n
    }

    pub fn is_empty(&self) -> bool {
        self.n == 0
    }

    pub fn contains(&self, key: &str) -> bool {
        self.get(key).is_some()
    }

    pub fn longest_prefix_of<'a>(&self, query: &'a str) -> Option<&'a str> {
        Node::longest_prefix_of(self.root.as_ref(), query)
    }

    pub fn keys_with_prefix(&self, prefix: &str) -> Vec<String> {
        let mut queue = Queue::new();
        let x = Node::get(self.root.as_ref(), prefix, 0);
        if x.is_some() {
            if x.unwrap().val.is_some() {
                queue.enqueue(prefix.into());
            }
            Node::collect(x.unwrap().mid.as_ref(), prefix.into(), &mut queue);
        }
        queue.into_iter().collect()
    }

    pub fn keys(&self) -> Vec<String> {
        let mut queue = Queue::new();
        Node::collect(self.root.as_ref(), "".into(), &mut queue);
        queue.into_iter().collect()
    }
}

#[test]
fn test_tst() {
    let mut t = TernarySearchTrie::new();
    assert_eq!(t.size(), 0);
    t.put("name", "Andelf");
    assert_eq!(t.size(), 1);
    assert!(t.contains("name"));
    t.put("name", "Fledna");
    assert_eq!(t.size(), 1);
    t.put("language", "Rust");
    assert_eq!(t.size(), 2);

    assert_eq!(t.get("name"), Some(&"Fledna"));
    assert_eq!(t.get("whatever"), None);

    t.delete("name");
    assert_eq!(t.size(), 1);
    assert_eq!(t.get("name"), None);

    t.put("name", "Lednaf");
    assert!(t.keys().contains(&"name".into()));
    assert!(t.keys().contains(&"language".into()));
    assert!(t.keys_with_prefix("lang").contains(&"language".into()));

    t.put("ban", "2333");
    t.put("banana", "2333");
    assert_eq!(t.longest_prefix_of("bananananana"), Some("banana"));
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]
use query_source::Table;
#[cfg(feature = "postgres")]
use expression::SelectableExpression;

/// Adds the `DISTINCT` keyword to a query.
///
/// # Example
///
/// ```rust
///
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("DELETE FROM users").unwrap();
/// connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Sean'), ('Sean')")
///     .unwrap();
/// let names = users.select(name).load(&connection);
/// let distinct_names = users.select(name).distinct().load(&connection);
///
/// let sean = String::from("Sean");
/// assert_eq!(Ok(vec![sean.clone(), sean.clone(), sean.clone()]), names);
/// assert_eq!(Ok(vec![sean.clone()]), distinct_names);
/// # }
/// ```
pub trait DistinctDsl {
    /// Query with DISTINCT added
    type Output;

    /// Should return query with DISTINCT added
    fn distinct(self) -> Self::Output;
}

impl<T> DistinctDsl for T
where
    T: Table,
    T::Query: DistinctDsl,
{
    type Output = <T::Query as DistinctDsl>::Output;

    /// Returns query with DISTINCT added
    fn distinct(self) -> Self::Output {
        self.as_query().distinct()
    }
}

/// Adds the `DISTINCT ON` clause to a query.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("../doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[derive(Queryable, Debug, PartialEq)]
/// # struct Animal {
/// #     species: String,
/// #     name: Option<String>,
/// #     legs: i32,
/// # }
/// #
/// # impl Animal {
/// #     fn new<S: Into<String>>(species: S, name: Option<&str>, legs: i32) -> Self {
/// #         Animal {
/// #             species: species.into(),
/// #             name: name.map(Into::into),
/// #             legs
/// #         }
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::animals::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("DELETE FROM animals").unwrap();
/// connection.execute("INSERT INTO animals (species, name, legs)
///                     VALUES ('dog', 'Jack', 4), ('dog', Null, 4),
///                            ('spider', Null, 8)")
///     .unwrap();
/// let all_animals = animals.select((species, name, legs)).load(&connection);
/// let distinct_animals = animals.select((species, name, legs)).distinct_on(species).load(&connection);
///
/// assert_eq!(Ok(vec![Animal::new("dog", Some("Jack"), 4),
///                    Animal::new("dog", None, 4),
///                    Animal::new("spider", None, 8)]), all_animals);
/// assert_eq!(Ok(vec![Animal::new("dog", Some("Jack"), 4),
///                    Animal::new("spider", None, 8)]), distinct_animals);
/// # }
/// ```
#[cfg(feature = "postgres")]
pub trait DistinctOnDsl<Selection: SelectableExpression<T>, T> {
    type Output;
    fn distinct_on(self, selection: Selection) -> Self::Output;
}

#[cfg(feature = "postgres")]
impl<T, Selection> DistinctOnDsl<Selection, T> for T
where
    Selection: SelectableExpression<T>,
    T: Table,
    T::Query: DistinctOnDsl<Selection, T>,
{
    type Output = <T::Query as DistinctOnDsl<Selection, T>>::Output;

    fn distinct_on(self, selection: Selection) -> Self::Output {
        self.as_query().distinct_on(selection)
    }
}
<commit_msg>Add some documentation for DistinctOnDsl<commit_after>#![deny(missing_docs)]
use query_source::Table;
#[cfg(feature = "postgres")]
use expression::SelectableExpression;

/// Adds the `DISTINCT` keyword to a query.
///
/// # Example
///
/// ```rust
///
/// # #[macro_use] extern crate diesel;
/// # include!("../doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::users::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("DELETE FROM users").unwrap();
/// connection.execute("INSERT INTO users (name) VALUES ('Sean'), ('Sean'), ('Sean')")
///     .unwrap();
/// let names = users.select(name).load(&connection);
/// let distinct_names = users.select(name).distinct().load(&connection);
///
/// let sean = String::from("Sean");
/// assert_eq!(Ok(vec![sean.clone(), sean.clone(), sean.clone()]), names);
/// assert_eq!(Ok(vec![sean.clone()]), distinct_names);
/// # }
/// ```
pub trait DistinctDsl {
    /// Query with DISTINCT added
    type Output;

    /// Should return query with DISTINCT added
    fn distinct(self) -> Self::Output;
}

impl<T> DistinctDsl for T
where
    T: Table,
    T::Query: DistinctDsl,
{
    type Output = <T::Query as DistinctDsl>::Output;

    /// Returns query with DISTINCT added
    fn distinct(self) -> Self::Output {
        self.as_query().distinct()
    }
}

/// Adds the `DISTINCT ON` clause to a query.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("../doctest_setup.rs");
/// #
/// # table! {
/// #     users {
/// #         id -> Integer,
/// #         name -> VarChar,
/// #     }
/// # }
/// #
/// # #[derive(Queryable, Debug, PartialEq)]
/// # struct Animal {
/// #     species: String,
/// #     name: Option<String>,
/// #     legs: i32,
/// # }
/// #
/// # impl Animal {
/// #     fn new<S: Into<String>>(species: S, name: Option<&str>, legs: i32) -> Self {
/// #         Animal {
/// #             species: species.into(),
/// #             name: name.map(Into::into),
/// #             legs
/// #         }
/// #     }
/// # }
/// #
/// # fn main() {
/// #     use self::animals::dsl::*;
/// #     let connection = establish_connection();
/// #     connection.execute("DELETE FROM animals").unwrap();
/// connection.execute("INSERT INTO animals (species, name, legs)
///                     VALUES ('dog', 'Jack', 4), ('dog', Null, 4),
///                            ('spider', Null, 8)")
///     .unwrap();
/// let all_animals = animals.select((species, name, legs)).load(&connection);
/// let distinct_animals = animals.select((species, name, legs)).distinct_on(species).load(&connection);
///
/// assert_eq!(Ok(vec![Animal::new("dog", Some("Jack"), 4),
///                    Animal::new("dog", None, 4),
///                    Animal::new("spider", None, 8)]), all_animals);
/// assert_eq!(Ok(vec![Animal::new("dog", Some("Jack"), 4),
///                    Animal::new("spider", None, 8)]), distinct_animals);
/// # }
/// ```
#[cfg(feature = "postgres")]
pub trait DistinctOnDsl<Selection: SelectableExpression<T>, T> {
    /// Query with `DISTINCT ON()` added
    type Output;

    /// Should return query with `DISTINCT ON` added
    fn distinct_on(self, selection: Selection) -> Self::Output;
}

#[cfg(feature = "postgres")]
impl<T, Selection> DistinctOnDsl<Selection, T> for T
where
    Selection: SelectableExpression<T>,
    T: Table,
    T::Query: DistinctOnDsl<Selection, T>,
{
    type Output = <T::Query as DistinctOnDsl<Selection, T>>::Output;

    fn distinct_on(self, selection: Selection) -> Self::Output {
        self.as_query().distinct_on(selection)
    }
}
<|endoftext|>


<commit_before>use expression::{nullable, AsExpression, Expression};
use expression::array_comparison::{AsInExpression, In, NotIn};
use expression::operators::*;
use types::SingleValue;

pub trait ExpressionMethods: Expression + Sized {
    /// Creates a SQL `=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.eq("Sean"));
    /// assert_eq!(Ok(1), data.first(&connection));
    /// # }
    /// ```
    fn eq<T: AsExpression<Self::SqlType>>(self, other: T) -> Eq<Self, T::Expression> {
        Eq::new(self, other.as_expression())
    }

    /// Creates a SQL `!=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.ne("Sean"));
    /// assert_eq!(Ok(2), data.first(&connection));
    /// # }
    /// ```
    fn ne<T: AsExpression<Self::SqlType>>(self, other: T) -> NotEq<Self, T::Expression> {
        NotEq::new(self, other.as_expression())
    }

    /// Creates a SQL `IN` statement. Queries using this method will not be
    /// placed in the prepared statement cache. On PostgreSQL, you should use
    /// `eq(any())` instead. This method may change in the future to
    /// automatically perform `= ANY` on PostgreSQL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// #     connection.execute("INSERT INTO users (name) VALUES
    /// #         ('Jim')").unwrap();
    /// let data = users.select(id).filter(name.eq_any(vec!["Sean", "Jim"]));
    /// assert_eq!(Ok(vec![1, 3]), data.load(&connection));
    ///
    /// // Calling `eq_any` with an empty array is the same as doing `WHERE 1=0`
    /// let data = users.select(id).filter(name.eq_any(Vec::<String>::new()));
    /// assert_eq!(Ok(vec![]), data.load::<i32>(&connection));
    /// # }
    /// ```
    fn eq_any<T>(self, values: T) -> In<Self, T::InExpression>
    where
        T: AsInExpression<Self::SqlType>,
    {
        In::new(self, values.as_in_expression())
    }

    /// Creates a SQL `NOT IN` statement. Queries using this method will not be
    /// placed in the prepared statement cache. On PostgreSQL, you should use
    /// `ne(any())` instead. This method may change in the future to
    /// automatically perform `!= ANY` on PostgreSQL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// #     connection.execute("INSERT INTO users (name) VALUES
    /// #         ('Jim')").unwrap();
    /// let data = users.select(id).filter(name.ne_any(vec!["Sean", "Jim"]));
    /// assert_eq!(Ok(vec![2]), data.load(&connection));
    ///
    /// let data = users.select(id).filter(name.ne_any(vec!["Tess"]));
    /// assert_eq!(Ok(vec![1, 3]), data.load(&connection));
    ///
    /// // Calling `ne_any` with an empty array is the same as doing `WHERE 1=1`
    /// let data = users.select(id).filter(name.ne_any(Vec::<String>::new()));
    /// assert_eq!(Ok(vec![1, 2, 3]), data.load(&connection));
    /// # }
    /// ```
    fn ne_any<T>(self, values: T) -> NotIn<Self, T::InExpression>
    where
        T: AsInExpression<Self::SqlType>,
    {
        NotIn::new(self, values.as_in_expression())
    }

    /// Creates a SQL `IS NULL` expression.
    fn is_null(self) -> IsNull<Self> {
        IsNull::new(self)
    }

    /// Creates a SQL `IS NOT NULL` expression.
    fn is_not_null(self) -> IsNotNull<Self> {
        IsNotNull::new(self)
    }

    /// Creates a SQL `>` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.gt(1));
    /// assert_eq!(Ok("Tess".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn gt<T: AsExpression<Self::SqlType>>(self, other: T) -> Gt<Self, T::Expression> {
        Gt::new(self, other.as_expression())
    }

    /// Creates a SQL `>=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.ge(2));
    /// assert_eq!(Ok("Tess".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn ge<T: AsExpression<Self::SqlType>>(self, other: T) -> GtEq<Self, T::Expression> {
        GtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `<` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.lt(2));
    /// assert_eq!(Ok("Sean".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn lt<T: AsExpression<Self::SqlType>>(self, other: T) -> Lt<Self, T::Expression> {
        Lt::new(self, other.as_expression())
    }

    /// Creates a SQL `<=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.le(2));
    /// assert_eq!(Ok("Sean".to_string()), data.first(&connection));
    /// # }
    fn le<T: AsExpression<Self::SqlType>>(self, other: T) -> LtEq<Self, T::Expression> {
        LtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `BETWEEN` expression using the given range.
    fn between<T: AsExpression<Self::SqlType>>(
        self,
        other: ::std::ops::Range<T>,
    ) -> Between<Self, And<T::Expression, T::Expression>> {
        Between::new(
            self,
            And::new(other.start.as_expression(), other.end.as_expression()),
        )
    }

    /// Creates a SQL `NOT BETWEEN` expression using the given range.
    fn not_between<T: AsExpression<Self::SqlType>>(
        self,
        other: ::std::ops::Range<T>,
    ) -> NotBetween<Self, And<T::Expression, T::Expression>> {
        NotBetween::new(
            self,
            And::new(other.start.as_expression(), other.end.as_expression()),
        )
    }

    /// Creates a SQL `DESC` expression, representing this expression in
    /// descending order.
    fn desc(self) -> Desc<Self> {
        Desc::new(self)
    }

    /// Creates a SQL `ASC` expression, representing this expression in
    /// ascending order.
    ///
    /// This is the same as leaving the direction unspecified. It is useful if
    /// you need to provide an unknown ordering, and need to box the return
    /// value of a function.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let order = "name";
    /// let ordering: Box<BoxableExpression<users, DB, SqlType=()>> =
    ///     if order == "name" {
    ///         Box::new(name.desc())
    ///     } else {
    ///         Box::new(id.asc())
    ///     };
    /// # }
    /// ```
    fn asc(self) -> Asc<Self> {
        Asc::new(self)
    }
}

impl<T> ExpressionMethods for T
where
    T: Expression,
    T::SqlType: SingleValue,
{
}

pub trait NullableExpressionMethods: Expression + Sized {
    /// Converts this potentially non-null expression into one which is treated
    /// as nullable. This method has no impact on the generated SQL, and is only
    /// used to allow certain comparisons that would otherwise fail to compile.
    ///
    /// # Example
    /// ```no_run
    /// # #![allow(dead_code)]
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use diesel::types::*;
    /// #
    /// table! {
    ///     users {
    ///         id -> Integer,
    ///         name -> VarChar,
    ///     }
    /// }
    ///
    /// table! {
    ///     posts {
    ///         id -> Integer,
    ///         user_id -> Integer,
    ///         author_name -> Nullable<VarChar>,
    ///     }
    /// }
    /// #
    /// #  pub struct User {
    /// #      id: i32,
    /// #      name: VarChar,
    /// #  }
    /// #
    /// #  pub struct Post {
    /// #      id: i32,
    /// #      user_id: i32,
    /// #      author_name: Option<VarChar>,
    /// #  }
    /// #
    /// #  joinable!(posts -> users (user_id));
    ///
    /// fn main() {
    ///     use users::dsl::*;
    ///     use posts::dsl::{posts, author_name};
    ///     let connection = establish_connection();
    ///
    ///     let data = users.inner_join(posts)
    ///         .filter(name.nullable().eq(author_name))
    ///         .select(name)
    ///         .load::<String>(&connection);
    ///     println!("{:?}", data);
    /// }
    fn nullable(self) -> nullable::Nullable<Self> {
        nullable::Nullable::new(self)
    }
}

impl<T: Expression> NullableExpressionMethods for T {}
<commit_msg>Review global expression methods documentation<commit_after>use expression::{nullable, AsExpression, Expression};
use expression::array_comparison::{AsInExpression, In, NotIn};
use expression::operators::*;
use types::SingleValue;

pub trait ExpressionMethods: Expression + Sized {
    /// Creates a SQL `=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.eq("Sean"));
    /// assert_eq!(Ok(1), data.first(&connection));
    /// # }
    /// ```
    fn eq<T: AsExpression<Self::SqlType>>(self, other: T) -> Eq<Self, T::Expression> {
        Eq::new(self, other.as_expression())
    }

    /// Creates a SQL `!=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.ne("Sean"));
    /// assert_eq!(Ok(2), data.first(&connection));
    /// # }
    /// ```
    fn ne<T: AsExpression<Self::SqlType>>(self, other: T) -> NotEq<Self, T::Expression> {
        NotEq::new(self, other.as_expression())
    }

    /// Creates a SQL `IN` statement.
    ///
    /// Queries using this method will not be
    /// placed in the prepared statement cache. On PostgreSQL, you should use
    /// `eq(any())` instead. This method may change in the future to
    /// automatically perform `= ANY` on PostgreSQL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// #     connection.execute("INSERT INTO users (name) VALUES
    /// #         ('Jim')").unwrap();
    /// let data = users.select(id).filter(name.eq_any(vec!["Sean", "Jim"]));
    /// assert_eq!(Ok(vec![1, 3]), data.load(&connection));
    ///
    /// // Calling `eq_any` with an empty array is the same as doing `WHERE 1=0`
    /// let data = users.select(id).filter(name.eq_any(Vec::<String>::new()));
    /// assert_eq!(Ok(vec![]), data.load::<i32>(&connection));
    /// # }
    /// ```
    fn eq_any<T>(self, values: T) -> In<Self, T::InExpression>
    where
        T: AsInExpression<Self::SqlType>,
    {
        In::new(self, values.as_in_expression())
    }

    /// Creates a SQL `NOT IN` statement.
    ///
    /// Queries using this method will not be
    /// placed in the prepared statement cache. On PostgreSQL, you should use
    /// `ne(any())` instead. This method may change in the future to
    /// automatically perform `!= ANY` on PostgreSQL.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// #     connection.execute("INSERT INTO users (name) VALUES
    /// #         ('Jim')").unwrap();
    /// let data = users.select(id).filter(name.ne_any(vec!["Sean", "Jim"]));
    /// assert_eq!(Ok(vec![2]), data.load(&connection));
    ///
    /// let data = users.select(id).filter(name.ne_any(vec!["Tess"]));
    /// assert_eq!(Ok(vec![1, 3]), data.load(&connection));
    ///
    /// // Calling `ne_any` with an empty array is the same as doing `WHERE 1=1`
    /// let data = users.select(id).filter(name.ne_any(Vec::<String>::new()));
    /// assert_eq!(Ok(vec![1, 2, 3]), data.load(&connection));
    /// # }
    /// ```
    fn ne_any<T>(self, values: T) -> NotIn<Self, T::InExpression>
    where
        T: AsInExpression<Self::SqlType>,
    {
        NotIn::new(self, values.as_in_expression())
    }

    /// Creates a SQL `IS NULL` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use schema::users;
    /// #
    /// # fn main() {
    /// #     use animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(name.is_null())
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("spider".to_string()), data);
    /// # }
    fn is_null(self) -> IsNull<Self> {
        IsNull::new(self)
    }

    /// Creates a SQL `IS NOT NULL` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use schema::users;
    /// #
    /// # fn main() {
    /// #     use animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(name.is_not_null())
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("dog".to_string()), data);
    /// # }
    fn is_not_null(self) -> IsNotNull<Self> {
        IsNotNull::new(self)
    }

    /// Creates a SQL `>` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.gt(1));
    /// assert_eq!(Ok("Tess".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn gt<T: AsExpression<Self::SqlType>>(self, other: T) -> Gt<Self, T::Expression> {
        Gt::new(self, other.as_expression())
    }

    /// Creates a SQL `>=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.ge(2));
    /// assert_eq!(Ok("Tess".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn ge<T: AsExpression<Self::SqlType>>(self, other: T) -> GtEq<Self, T::Expression> {
        GtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `<` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.lt(2));
    /// assert_eq!(Ok("Sean".to_string()), data.first(&connection));
    /// # }
    /// ```
    fn lt<T: AsExpression<Self::SqlType>>(self, other: T) -> Lt<Self, T::Expression> {
        Lt::new(self, other.as_expression())
    }

    /// Creates a SQL `<=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(name).filter(id.le(2));
    /// assert_eq!(Ok("Sean".to_string()), data.first(&connection));
    /// # }
    fn le<T: AsExpression<Self::SqlType>>(self, other: T) -> LtEq<Self, T::Expression> {
        LtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `BETWEEN` expression using the given range.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use schema::users;
    /// #
    /// # fn main() {
    /// #     use animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.between(2..6))
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("dog".to_string()), data);
    /// # }
    fn between<T: AsExpression<Self::SqlType>>(
        self,
        other: ::std::ops::Range<T>,
    ) -> Between<Self, And<T::Expression, T::Expression>> {
        Between::new(
            self,
            And::new(other.start.as_expression(), other.end.as_expression()),
        )
    }

    /// Creates a SQL `NOT BETWEEN` expression using the given range.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use schema::users;
    /// #
    /// # fn main() {
    /// #     use animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.not_between(2..6))
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("spider".to_string()), data);
    /// # }
    fn not_between<T: AsExpression<Self::SqlType>>(
        self,
        other: ::std::ops::Range<T>,
    ) -> NotBetween<Self, And<T::Expression, T::Expression>> {
        NotBetween::new(
            self,
            And::new(other.start.as_expression(), other.end.as_expression()),
        )
    }

    /// Creates a SQL `DESC` expression, representing this expression in
    /// descending order.
    fn desc(self) -> Desc<Self> {
        Desc::new(self)
    }

    /// Creates a SQL `ASC` expression, representing this expression in
    /// ascending order.
    ///
    /// This is the same as leaving the direction unspecified. It is useful if
    /// you need to provide an unknown ordering, and need to box the return
    /// value of a function.
    ///
    /// # Example
    ///
    /// ```rust
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// #
    /// # table! {
    /// #     users {
    /// #         id -> Integer,
    /// #         name -> VarChar,
    /// #     }
    /// # }
    /// #
    /// # fn main() {
    /// #     use users::dsl::*;
    /// #     let order = "name";
    /// let ordering: Box<BoxableExpression<users, DB, SqlType=()>> =
    ///     if order == "name" {
    ///         Box::new(name.desc())
    ///     } else {
    ///         Box::new(id.asc())
    ///     };
    /// # }
    /// ```
    fn asc(self) -> Asc<Self> {
        Asc::new(self)
    }
}

impl<T> ExpressionMethods for T
where
    T: Expression,
    T::SqlType: SingleValue,
{
}

pub trait NullableExpressionMethods: Expression + Sized {
    /// Converts this potentially non-null expression into one which is treated
    /// as nullable. This method has no impact on the generated SQL, and is only
    /// used to allow certain comparisons that would otherwise fail to compile.
    ///
    /// # Example
    /// ```no_run
    /// # #![allow(dead_code)]
    /// # #[macro_use] extern crate diesel;
    /// # include!("../doctest_setup.rs");
    /// # use diesel::types::*;
    /// #
    /// table! {
    ///     users {
    ///         id -> Integer,
    ///         name -> VarChar,
    ///     }
    /// }
    ///
    /// table! {
    ///     posts {
    ///         id -> Integer,
    ///         user_id -> Integer,
    ///         author_name -> Nullable<VarChar>,
    ///     }
    /// }
    /// #
    /// #  pub struct User {
    /// #      id: i32,
    /// #      name: VarChar,
    /// #  }
    /// #
    /// #  pub struct Post {
    /// #      id: i32,
    /// #      user_id: i32,
    /// #      author_name: Option<VarChar>,
    /// #  }
    /// #
    /// #  joinable!(posts -> users (user_id));
    ///
    /// fn main() {
    ///     use users::dsl::*;
    ///     use posts::dsl::{posts, author_name};
    ///     let connection = establish_connection();
    ///
    ///     let data = users.inner_join(posts)
    ///         .filter(name.nullable().eq(author_name))
    ///         .select(name)
    ///         .load::<String>(&connection);
    ///     println!("{:?}", data);
    /// }
    fn nullable(self) -> nullable::Nullable<Self> {
        nullable::Nullable::new(self)
    }
}

impl<T: Expression> NullableExpressionMethods for T {}
<|endoftext|>