#![allow(nonstandard_style)]
///! This file was automatically generated by Punybuf.
///! It's best you don't change anything.

use std::io;
use crate::*;

/// This enum contains all possible commands in the RPC definition.
#[derive(Debug, Clone)]
pub enum Command {
    setupEncryption(setupEncryption),
    negotiateLayer(negotiateLayer),
    initialize(initialize),
    peerChanged(peerChanged),
    peerRemoved(peerRemoved),
    proveIdentity(proveIdentity),
    probePeer(probePeer),
    ping(ping),
}
impl PBCommand for Command {
    fn id(&self) -> u32 {
        match self {
            Self::setupEncryption(_) => 2838900288,
            Self::negotiateLayer(_) => 1992668024,
            Self::initialize(_) => 272122219,
            Self::peerChanged(_) => 798753029,
            Self::peerRemoved(_) => 3152051513,
            Self::proveIdentity(_) => 3925159133,
            Self::probePeer(_) => 2060730800,
            Self::ping(_) => 771208796,
        }
    }
    fn is_void(&self) -> bool {
        match self {
            Self::setupEncryption(_) => false,
            Self::negotiateLayer(_) => false,
            Self::initialize(_) => false,
            Self::peerChanged(_) => true,
            Self::peerRemoved(_) => true,
            Self::proveIdentity(_) => false,
            Self::probePeer(_) => false,
            Self::ping(_) => false,
        }
    }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] {
        match self {
            Self::setupEncryption(_) => setupEncryption::ATTRIBUTES,
            Self::negotiateLayer(_) => negotiateLayer::ATTRIBUTES,
            Self::initialize(_) => initialize::ATTRIBUTES,
            Self::peerChanged(_) => peerChanged::ATTRIBUTES,
            Self::peerRemoved(_) => peerRemoved::ATTRIBUTES,
            Self::proveIdentity(_) => proveIdentity::ATTRIBUTES,
            Self::probePeer(_) => probePeer::ATTRIBUTES,
            Self::ping(_) => ping::ATTRIBUTES,
        }
    }
    fn required_capability(&self) -> Option<&'static str> {
        match self {
            Self::setupEncryption(_) => setupEncryption::REQUIRED_CAPABILITY,
            Self::negotiateLayer(_) => negotiateLayer::REQUIRED_CAPABILITY,
            Self::initialize(_) => initialize::REQUIRED_CAPABILITY,
            Self::peerChanged(_) => peerChanged::REQUIRED_CAPABILITY,
            Self::peerRemoved(_) => peerRemoved::REQUIRED_CAPABILITY,
            Self::proveIdentity(_) => proveIdentity::REQUIRED_CAPABILITY,
            Self::probePeer(_) => probePeer::REQUIRED_CAPABILITY,
            Self::ping(_) => ping::REQUIRED_CAPABILITY,
        }
    }
    fn serialize_self<R: io::Write>(&self, r: &mut R) -> Result<(), io::Error> {
        match self {
            Self::setupEncryption(c) => c.serialize_self(r),
            Self::negotiateLayer(c) => c.serialize_self(r),
            Self::initialize(c) => c.serialize_self(r),
            Self::peerChanged(c) => c.serialize_self(r),
            Self::peerRemoved(c) => c.serialize_self(r),
            Self::proveIdentity(c) => c.serialize_self(r),
            Self::probePeer(c) => c.serialize_self(r),
            Self::ping(c) => c.serialize_self(r),
        }
    }
}

impl Command {

    /// Reads both the ID of the command and its value
    fn deserialize<R: io::Read>(r: &mut R) -> Result<Self, io::Error> {
        let mut id = [0; 4];
        r.read_exact(&mut id)?;
        let id = u32::from_be_bytes(id);
        Ok(match id {
            2838900288 => Self::setupEncryption(setupEncryption::deserialize(r)?),
            1992668024 => Self::negotiateLayer(negotiateLayer::deserialize(r)?),
            272122219 => Self::initialize(initialize::deserialize(r)?),
            798753029 => Self::peerChanged(peerChanged::deserialize(r)?),
            3152051513 => Self::peerRemoved(peerRemoved::deserialize(r)?),
            3925159133 => Self::proveIdentity(proveIdentity::deserialize(r)?),
            2060730800 => Self::probePeer(probePeer::deserialize(r)?),
            771208796 => Self::ping(ping::deserialize(r)?),
            _ => Err(io::Error::other("Invalid or unsupported command ID"))?
        })
    }
}

/// This enum contains all possible command return types in the RPC definition.
#[derive(Debug, Clone)]
pub enum CommandReturn {
    setupEncryption(EncryptionCreated),
    negotiateLayer(Done),
    initialize(Connection),
    peerChanged(Void),
    peerRemoved(Void),
    proveIdentity(Connection),
    probePeer(Done),
    ping(Done),
}
impl CommandReturn {
    pub fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::setupEncryption(c) => c.serialize(w)?,
            Self::negotiateLayer(c) => c.serialize(w)?,
            Self::initialize(c) => c.serialize(w)?,
            Self::peerChanged(c) => c.serialize(w)?,
            Self::peerRemoved(c) => c.serialize(w)?,
            Self::proveIdentity(c) => c.serialize(w)?,
            Self::probePeer(c) => c.serialize(w)?,
            Self::ping(c) => c.serialize(w)?,
        }
        Ok(())
    }
    pub fn deserialize_return<R: io::Read>(id: u32, r: &mut R) -> Result<Self, io::Error> {
        Ok(match id {
            2838900288 => Self::setupEncryption(EncryptionCreated::deserialize(r)?),
            1992668024 => Self::negotiateLayer(Done::deserialize(r)?),
            272122219 => Self::initialize(Connection::deserialize(r)?),
            798753029 => Self::peerChanged(Void::deserialize(r)?),
            3152051513 => Self::peerRemoved(Void::deserialize(r)?),
            3925159133 => Self::proveIdentity(Connection::deserialize(r)?),
            2060730800 => Self::probePeer(Done::deserialize(r)?),
            771208796 => Self::ping(Done::deserialize(r)?),
            _ => Err(io::Error::other("Invalid or unsupported command ID"))?
        })
    }
}

/// This enum contains all possible command error types in the RPC definition.
#[derive(Debug, Clone)]
pub enum CommandError {
    setupEncryption(setupEncryptionError),
    negotiateLayer(negotiateLayerError),
    initialize(initializeError),
    peerChanged(peerChangedError),
    peerRemoved(peerRemovedError),
    proveIdentity(proveIdentityError),
    probePeer(probePeerError),
    ping(pingError),
}
impl CommandError {
    pub fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::setupEncryption(c) => c.serialize(w)?,
            Self::negotiateLayer(c) => c.serialize(w)?,
            Self::initialize(c) => c.serialize(w)?,
            Self::peerChanged(c) => c.serialize(w)?,
            Self::peerRemoved(c) => c.serialize(w)?,
            Self::proveIdentity(c) => c.serialize(w)?,
            Self::probePeer(c) => c.serialize(w)?,
            Self::ping(c) => c.serialize(w)?,
        }
        Ok(())
    }
    pub fn deserialize_error<R: io::Read>(id: u32, r: &mut R) -> Result<Self, io::Error> {
        Ok(match id {
            2838900288 => Self::setupEncryption(setupEncryptionError::deserialize(r)?),
            1992668024 => Self::negotiateLayer(negotiateLayerError::deserialize(r)?),
            272122219 => Self::initialize(initializeError::deserialize(r)?),
            798753029 => Self::peerChanged(peerChangedError::deserialize(r)?),
            3152051513 => Self::peerRemoved(peerRemovedError::deserialize(r)?),
            3925159133 => Self::proveIdentity(proveIdentityError::deserialize(r)?),
            2060730800 => Self::probePeer(probePeerError::deserialize(r)?),
            771208796 => Self::ping(pingError::deserialize(r)?),
            _ => Err(io::Error::other("Invalid or unsupported command ID"))?
        })
    }
}

/// TLS must be preferred to this.
/// 
/// - First, the client generates the singature.
/// - The server must get the network password by the network ID.
/// - The server must generate `first_order_key = HKDF-SHA256(network_password, 0, FirstOrderKeyInfo)`
/// - Then the server generates a 256-bit random number and generates `key = HKDF-SHA256(first_order_key, random, 0)`
/// - The server uses the `first_order_key` to send the random number to the client.
/// - The client then decrypts the random number and derives `key` the same way. If this step fails, the client is to
/// close the connection immediately.
/// - Both the server and the client have arrived at the same `key`.
#[derive(Debug, Clone)]
pub struct setupEncryption {
    /// The network ID. The key used will be derived from the network password.
    pub network: String,
    pub identity: Bytes,
    pub client_random: Bytes,
    /// Signed with client's identity private key.
    pub signature: Bytes,
    /// always 1
    pub encryption_version: u8,
}
impl PBCommandExt for setupEncryption {
    type Error = setupEncryptionError;
    type Return = EncryptionCreated;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 2838900288;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.serverBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_network = String::deserialize(r)?;
        let field_identity = Bytes::deserialize(r)?;
        let field_client_random = Bytes::deserialize(r)?;
        let field_signature = Bytes::deserialize(r)?;
        let field_encryption_version = u8::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            network: field_network,
            identity: field_identity,
            client_random: field_client_random,
            signature: field_signature,
            encryption_version: field_encryption_version,
        })
    }
}
impl PBCommand for setupEncryption {
    fn id(&self) -> u32 { 2838900288 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.network.serialize(w)?;
        self.identity.serialize(w)?;
        self.client_random.serialize(w)?;
        self.signature.serialize(w)?;
        self.encryption_version.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum setupEncryptionError {
    UnexpectedError(String),
    Unsupported,
    InvalidNetwork,
}
impl PBType for setupEncryptionError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
            Self::Unsupported => {
                1u8.serialize(w)?;
            }
            Self::InvalidNetwork => {
                2u8.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            1 => {
                Self::Unsupported
            }
            2 => {
                Self::InvalidNetwork
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct negotiateLayer {
    pub client_layer: UInt,
}
impl PBCommandExt for negotiateLayer {
    type Error = negotiateLayerError;
    type Return = Done;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 1992668024;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.serverBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_client_layer = UInt::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            client_layer: field_client_layer,
        })
    }
}
impl PBCommand for negotiateLayer {
    fn id(&self) -> u32 { 1992668024 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.client_layer.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum negotiateLayerError {
    UnexpectedError(String),
    /// The layer is unsupported, fallback to this one
    Fallback(UInt),
}
impl PBType for negotiateLayerError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
            Self::Fallback(value) => {
                1u8.serialize(w)?;
                value.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            1 => {
                Self::Fallback(UInt::deserialize(r)?)
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct initialize {
    /// This is the internal virtual network ID.
    pub network: String,
    /// This is the identity public key of the client.
    pub identity: Bytes,
    pub preferred_ip: Option<u32>, // Flag of `flags`
    /// MAC'd with the network password.
    pub password_proof: Option<Bytes>, // Flag of `flags`
    /// List of capabilities supported by the client
    pub capabilities: Vec<String>,
}
impl PBCommandExt for initialize {
    type Error = initializeError;
    type Return = Connection;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 272122219;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.serverBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_network = String::deserialize(r)?;
        let field_identity = Bytes::deserialize(r)?;
        let field_flags = UInt::deserialize(r)?;
        let flag_preferred_ip = if (field_flags & (1 << 0)) != 0 {
            Some(u32::deserialize(r)?)
        } else { None };
        let flag_password_proof = if (field_flags & (1 << 1)) != 0 {
            Some(Bytes::deserialize(r)?)
        } else { None };
        let field_capabilities = Vec::<String>::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            network: field_network,
            identity: field_identity,
            preferred_ip: flag_preferred_ip,
            password_proof: flag_password_proof,
            capabilities: field_capabilities,
        })
    }
}
impl PBCommand for initialize {
    fn id(&self) -> u32 { 272122219 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.network.serialize(w)?;
        self.identity.serialize(w)?;
        // If you get an error here, this type doesn't support flags.
        let mut flags: UInt = 0.try_into().unwrap();
        if self.preferred_ip.is_some() { flags |= 1 << 0 }
        if self.password_proof.is_some() { flags |= 1 << 1 }
        flags.serialize(w)?;
        if let Some(ref v) = self.preferred_ip {
            v.serialize(w)?;
        }
        if let Some(ref v) = self.password_proof {
            v.serialize(w)?;
        }
        self.capabilities.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum initializeError {
    UnexpectedError(String),
    InvalidNetwork,
    InternalError(String),
    /// The client must prove that it has the private key.
    /// For that, the client must sign the `IdentityProof`, including this challenge.
    Challenge(Bytes),
}
impl PBType for initializeError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
            Self::InvalidNetwork => {
                1u8.serialize(w)?;
            }
            Self::InternalError(value) => {
                2u8.serialize(w)?;
                value.serialize(w)?;
            }
            Self::Challenge(value) => {
                3u8.serialize(w)?;
                value.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            1 => {
                Self::InvalidNetwork
            }
            2 => {
                Self::InternalError(String::deserialize(r)?)
            }
            3 => {
                Self::Challenge(Bytes::deserialize(r)?)
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct peerChanged {
    pub peer: Peer,
}
impl PBCommandExt for peerChanged {
    type Error = peerChangedError;
    type Return = Void;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 798753029;
    const IS_VOID: bool = true;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.clientBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_peer = Peer::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            peer: field_peer,
        })
    }
}
impl PBCommand for peerChanged {
    fn id(&self) -> u32 { 798753029 }
    fn is_void(&self) -> bool { true }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.peer.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum peerChangedError {
    UnexpectedError(String),
}
impl PBType for peerChangedError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct peerRemoved {
    pub virtual_ip: u32,
    pub identity: Bytes,
}
impl PBCommandExt for peerRemoved {
    type Error = peerRemovedError;
    type Return = Void;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 3152051513;
    const IS_VOID: bool = true;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.clientBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_virtual_ip = u32::deserialize(r)?;
        let field_identity = Bytes::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            virtual_ip: field_virtual_ip,
            identity: field_identity,
        })
    }
}
impl PBCommand for peerRemoved {
    fn id(&self) -> u32 { 3152051513 }
    fn is_void(&self) -> bool { true }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.virtual_ip.serialize(w)?;
        self.identity.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum peerRemovedError {
    UnexpectedError(String),
}
impl PBType for peerRemovedError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct proveIdentity {
    pub proof: Bytes,
    pub password_proof: Option<Bytes>, // Flag of `flags`
}
impl PBCommandExt for proveIdentity {
    type Error = proveIdentityError;
    type Return = Connection;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 3925159133;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.serverBound", None),
    ];
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_proof = Bytes::deserialize(r)?;
        let field_flags = UInt::deserialize(r)?;
        let flag_password_proof = if (field_flags & (1 << 0)) != 0 {
            Some(Bytes::deserialize(r)?)
        } else { None };
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            proof: field_proof,
            password_proof: flag_password_proof,
        })
    }
}
impl PBCommand for proveIdentity {
    fn id(&self) -> u32 { 3925159133 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.proof.serialize(w)?;
        // If you get an error here, this type doesn't support flags.
        let mut flags: UInt = 0.try_into().unwrap();
        if self.password_proof.is_some() { flags |= 1 << 0 }
        flags.serialize(w)?;
        if let Some(ref v) = self.password_proof {
            v.serialize(w)?;
        }
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum proveIdentityError {
    UnexpectedError(String),
    Denied,
}
impl PBType for proveIdentityError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
            Self::Denied => {
                1u8.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            1 => {
                Self::Denied
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct probePeer {
    pub peer_ip: u32,
}
impl PBCommandExt for probePeer {
    type Error = probePeerError;
    type Return = Done;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 2060730800;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.serverBound", None),
        ("@capability", Some("molerat_probe_v1")),
    ];
    const REQUIRED_CAPABILITY: Option<&'static str> = Some(&"molerat_probe_v1");
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_peer_ip = u32::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            peer_ip: field_peer_ip,
        })
    }
}
impl PBCommand for probePeer {
    fn id(&self) -> u32 { 2060730800 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn required_capability(&self) -> Option<&'static str> { 
        Self::REQUIRED_CAPABILITY
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.peer_ip.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum probePeerError {
    UnexpectedError(String),
    Unresponsive,
}
impl PBType for probePeerError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
            Self::Unresponsive => {
                1u8.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            1 => {
                Self::Unresponsive
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct ping;
impl PBCommandExt for ping {
    type Error = pingError;
    type Return = Done;
    const MIN_SIZE: usize = 0; // TODO
    const ID: u32 = 771208796;
    const ATTRIBUTES: &'static [(&'static str, Option<&'static str>)] = &[
        ("@.clientBound", None),
        ("@capability", Some("molerat_probe_v1")),
    ];
    const REQUIRED_CAPABILITY: Option<&'static str> = Some(&"molerat_probe_v1");
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        Ok(Self)
    }
}
impl PBCommand for ping {
    fn id(&self) -> u32 { 771208796 }
    fn attributes(&self) -> &'static [(&'static str, Option<&'static str>)] { 
        Self::ATTRIBUTES
    }
    fn required_capability(&self) -> Option<&'static str> { 
        Self::REQUIRED_CAPABILITY
    }
    fn serialize_self<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        Ok(())
    }
}

#[derive(Debug, Clone)]
pub enum pingError {
    UnexpectedError(String),
}
impl PBType for pingError {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::UnexpectedError(x) => { 0u8.serialize(w)?; x.serialize(w)?; }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => { Self::UnexpectedError(String::deserialize(r)?) }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

impl<K: PBType + std::hash::Hash + Eq, V: PBType> HashMapConvertible<K, V> for Map<K, V> {
    fn to_map_allow_duplicates(self) -> (std::collections::HashMap<K, V>, bool) {
        let mut hm = std::collections::HashMap::new();
        let mut duplicates = false;
        for pair in self {
            if hm.insert(pair.key, pair.value).is_some() {
                duplicates = true;
            }
        }
        (hm, duplicates)
    }
    fn from_map(map: std::collections::HashMap<K, V>) -> Self {
        let mut this = Self::new();
        for (key, value) in map.into_iter() {
            this.push(KeyPair { key, value });
        }
        this
    }
}
/// A map type. This isn't marked `@builtin`, but implementations may, for their
/// own convinience, allow to convert this type to their own `HashMap`
/// implementation. This conversion may fail, as this type enforces no rules
/// on the uniquness of the keys.
/// 
/// In the case that one of the keys is not unique, the implementation SHOULD NOT
/// reject a frame or fail the deserialization completely, but should react to this error
/// in some other way, like telling the user or throwing a more specific error.
pub type Map<K, V> = Vec<KeyPair<K, V>>;
#[derive(Debug, Clone)]
pub struct KeyPair<K, V> {
    pub key: K,
    pub value: V,
}
impl<K: PBType, V: PBType> PBType for KeyPair<K, V> {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.key.serialize(w)?;
        self.value.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_key = K::deserialize(r)?;
        let field_value = V::deserialize(r)?;
        Ok(Self {
            key: field_key,
            value: field_value,
        })
    }
}

/// An empty type, used as a return type for a command that doesn't need to return
/// anything, but needs to indicate that it's been recieved or that the requested
/// operation finished processing.
/// 
/// Note that this is very different from the [`Void`](Void) type that means that
/// the reciever will never return any acknoledgement to the sender.
#[derive(Debug, Clone)]
pub struct Done {
}
impl PBType for Done {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        Ok(Self {
        })
    }
}

/// A boolean value.
/// 
/// In practice, you should prefer using flag fields instead of this type.
#[derive(Debug, Clone)]
pub enum Boolean {
    True,
    False,
}
impl PBType for Boolean {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::True => {
                0u8.serialize(w)?;
            }
            Self::False => {
                1u8.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => {
                Self::True
            }
            1 => {
                Self::False
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

/// Means that `T` may or may not be present.
/// 
/// In practice this type is rarely used, as flag fields are always preferred (they
/// save space).
#[derive(Debug, Clone)]
pub enum Optional<T> {
    None,
    Some(T),
}
impl<T: PBType> PBType for Optional<T> {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        match self {
            Self::None => {
                0u8.serialize(w)?;
            }
            Self::Some(value) => {
                1u8.serialize(w)?;
                value.serialize(w)?;
            }
        }
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let discriminant = u8::deserialize(r)?;
        Ok(match discriminant {
            0 => {
                Self::None
            }
            1 => {
                Self::Some(T::deserialize(r)?)
            }
            _ => {
                Err(io::Error::other("Unknown enum discriminant; enum is not extensible"))?
            }
        })
    }
}

#[derive(Debug, Clone)]
pub struct EncryptedSomething {
    pub nonce: Bytes,
    pub data: Bytes,
}
impl PBType for EncryptedSomething {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.nonce.serialize(w)?;
        self.data.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_nonce = Bytes::deserialize(r)?;
        let field_data = Bytes::deserialize(r)?;
        Ok(Self {
            nonce: field_nonce,
            data: field_data,
        })
    }
}

#[derive(Debug, Clone)]
pub struct EncryptionCreated {
    pub encrypted_random: EncryptedSomething,
}
impl PBType for EncryptionCreated {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.encrypted_random.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_encrypted_random = EncryptedSomething::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            encrypted_random: field_encrypted_random,
        })
    }
}

#[derive(Debug, Clone)]
pub struct FirstOrderKeyInfo {
    pub network: String,
    pub identity: Bytes,
    pub client_random: Bytes,
}
impl PBType for FirstOrderKeyInfo {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.network.serialize(w)?;
        self.identity.serialize(w)?;
        self.client_random.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_network = String::deserialize(r)?;
        let field_identity = Bytes::deserialize(r)?;
        let field_client_random = Bytes::deserialize(r)?;
        Ok(Self {
            network: field_network,
            identity: field_identity,
            client_random: field_client_random,
        })
    }
}

#[derive(Debug, Clone)]
pub struct EncryptionSetup {
    /// Always "molerat_v1_encryption_setup"
    pub constant: String,
    pub network: String,
    pub client_random: Bytes,
}
impl PBType for EncryptionSetup {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.constant.serialize(w)?;
        self.network.serialize(w)?;
        self.client_random.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_constant = String::deserialize(r)?;
        let field_network = String::deserialize(r)?;
        let field_client_random = Bytes::deserialize(r)?;
        Ok(Self {
            constant: field_constant,
            network: field_network,
            client_random: field_client_random,
        })
    }
}

#[derive(Debug, Clone)]
pub struct Connection {
    pub you: Peer,
    /// The server's UDP port to use for figuring out the client's outward IP:Port.
    pub natt_port: u16,
    /// Server-chosen encryption key to use for the UDP communication.
    pub natt_key: Bytes,
    /// List of capabilities supported by the server
    pub capabilities: Vec<String>,
    /// The (virtual) IP of the virtual network. Clients are not required to use it locally, but all addresses must be in this subnet.
    pub virtual_subnet_ip: u32,
    /// The mask of the virtual network.
    pub virtual_subnet_mask: u8,
}
impl PBType for Connection {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.you.serialize(w)?;
        self.natt_port.serialize(w)?;
        self.natt_key.serialize(w)?;
        self.capabilities.serialize(w)?;
        self.virtual_subnet_ip.serialize(w)?;
        self.virtual_subnet_mask.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_you = Peer::deserialize(r)?;
        let field_natt_port = u16::deserialize(r)?;
        let field_natt_key = Bytes::deserialize(r)?;
        let field_capabilities = Vec::<String>::deserialize(r)?;
        let field_virtual_subnet_ip = u32::deserialize(r)?;
        let field_virtual_subnet_mask = u8::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            you: field_you,
            natt_port: field_natt_port,
            natt_key: field_natt_key,
            capabilities: field_capabilities,
            virtual_subnet_ip: field_virtual_subnet_ip,
            virtual_subnet_mask: field_virtual_subnet_mask,
        })
    }
}

#[derive(Debug, Clone)]
pub struct IdentityProof {
    /// Always "molerat_v1_identity_proof"
    pub constant: String,
    pub network: String,
    /// The challenge that was sent by the server
    pub challenge: Bytes,
}
impl PBType for IdentityProof {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.constant.serialize(w)?;
        self.network.serialize(w)?;
        self.challenge.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_constant = String::deserialize(r)?;
        let field_network = String::deserialize(r)?;
        let field_challenge = Bytes::deserialize(r)?;
        Ok(Self {
            constant: field_constant,
            network: field_network,
            challenge: field_challenge,
        })
    }
}

#[derive(Debug, Clone)]
pub struct PasswordProof {
    /// Always "molerat_v1_password_proof"
    pub constant: String,
    pub network: String,
    pub password: String,
    /// If not sent as part of `proveIdentity`, must be empty.
    pub challenge: Bytes,
}
impl PBType for PasswordProof {
    const MIN_SIZE: usize = 0; // TODO
    fn attributes() -> &'static [(&'static str, Option<&'static str>)] { &[
        ("@sealed", None),
    ] }
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        self.constant.serialize(w)?;
        self.network.serialize(w)?;
        self.password.serialize(w)?;
        self.challenge.serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_constant = String::deserialize(r)?;
        let field_network = String::deserialize(r)?;
        let field_password = String::deserialize(r)?;
        let field_challenge = Bytes::deserialize(r)?;
        Ok(Self {
            constant: field_constant,
            network: field_network,
            password: field_password,
            challenge: field_challenge,
        })
    }
}

#[derive(Debug, Clone)]
pub struct Peer {
    pub real_ip: Option<u32>, // Flag of `flags`
    pub real_port: Option<u16>, // Flag of `flags`
    pub virtual_ip: u32,
    pub identity: Bytes,
}
impl PBType for Peer {
    const MIN_SIZE: usize = 0; // TODO
    fn serialize<W: io::Write>(&self, w: &mut W) -> io::Result<()> {
        // If you get an error here, this type doesn't support flags.
        let mut flags: UInt = 0.try_into().unwrap();
        if self.real_ip.is_some() { flags |= 1 << 0 }
        if self.real_port.is_some() { flags |= 1 << 1 }
        flags.serialize(w)?;
        if let Some(ref v) = self.real_ip {
            v.serialize(w)?;
        }
        if let Some(ref v) = self.real_port {
            v.serialize(w)?;
        }
        self.virtual_ip.serialize(w)?;
        self.identity.serialize(w)?;
        UInt(0).serialize(w)?;
        Ok(())
    }
    fn deserialize<R: io::Read>(r: &mut R) -> io::Result<Self> {
        let field_flags = UInt::deserialize(r)?;
        let flag_real_ip = if (field_flags & (1 << 0)) != 0 {
            Some(u32::deserialize(r)?)
        } else { None };
        let flag_real_port = if (field_flags & (1 << 1)) != 0 {
            Some(u16::deserialize(r)?)
        } else { None };
        let field_virtual_ip = u32::deserialize(r)?;
        let field_identity = Bytes::deserialize(r)?;
        let mut _extension_bytes = Bytes::deserialize(r)?;
        let _extension_reader = &mut &_extension_bytes.0[..];
        Ok(Self {
            real_ip: flag_real_ip,
            real_port: flag_real_port,
            virtual_ip: field_virtual_ip,
            identity: field_identity,
        })
    }
}


// Because of Rust's orphan rules, we can't put this in the punybuf_common crate.

pub struct DuplicateKeysFound;
pub trait HashMapConvertible<K, V>: Sized {
    /// Converts the value to a `HashMap`, overriding duplicate keys.  
    /// Returns the resulting hashmap and a boolean indicating whether any duplicate keys were found
    fn to_map_allow_duplicates(self) -> (std::collections::HashMap<K, V>, bool);

    /// Returns an error if there were any duplicate keys in the Map
    fn try_to_map(self) -> Result<std::collections::HashMap<K, V>, DuplicateKeysFound> {
        let (map, duplicates_found) = self.to_map_allow_duplicates();
        if !duplicates_found {
            Ok(map)
        } else {
            Err(DuplicateKeysFound)
        }
    }
    fn from_map(map: std::collections::HashMap<K, V>) -> Self;
}


