<commit_before>use std::path::PathBuf;
use std::default::Default;
use std::collections::BTreeMap;

use quire::validate::{Validator, Structure, Sequence, Scalar, Numeric, Enum};
use quire::validate::{Mapping};
use self::Volume::*;

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct TmpfsInfo {
    pub size: usize,
    pub mode: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct PersistentInfo {
    pub path: PathBuf,
    pub mkdir: bool,
    pub mode: u32,
    pub user: u32,
    pub group: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct StatedirInfo {
    pub path: PathBuf,
    pub mode: u32,
    pub user: u32,
    pub group: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub enum Volume {
    Readonly(PathBuf),
    Persistent(PersistentInfo),
    Tmpfs(TmpfsInfo),
    Statedir(StatedirInfo),
}

#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq, Eq)]
pub enum ContainerKind {
    Daemon,
    Command,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ResolvConf {
    pub copy_from_host: bool,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct HostsFile {
    pub localhost: bool,
    pub public_hostname: bool,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Copy)]
pub struct IdMap {
    pub inside: u32,
    pub outside: u32,
    pub count: u32,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ContainerConfig {
    pub kind: ContainerKind,
    pub volumes: BTreeMap<String, Volume>,
    pub user_id: u32,
    pub group_id: u32,
    pub restart_timeout: f32,
    pub memory_limit: u64,
    pub fileno_limit: u64,
    pub cpu_shares: usize,
    pub executable: String,
    pub arguments: Vec<String>,
    pub environ: BTreeMap<String, String>,
    pub workdir: PathBuf,
    pub resolv_conf: ResolvConf,
    pub hosts_file: HostsFile,
    pub uid_map: Vec<IdMap>,
    pub gid_map: Vec<IdMap>,
    pub stdout_stderr_file: Option<PathBuf>,
    pub restart_process_only: bool,
}

fn mapping_validator<'x>() -> Box<Validator + 'x> {
    return Box::new(Sequence {
        element: Box::new(Structure { members: vec!(
            ("inside".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("outside".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("count".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ), .. Default::default() }) as Box<Validator>,
        .. Default::default() }) as Box<Validator>;
}

impl ContainerConfig {
    pub fn map_uid(&self, uid: u32) -> Option<u32> {
        _map_id(&self.uid_map, uid)
    }
    pub fn map_gid(&self, gid: u32) -> Option<u32> {
        _map_id(&self.gid_map, gid)
    }
    pub fn validator<'x>() -> Box<Validator + 'x> {
        return Box::new(Structure { members: vec!(
            ("kind".to_string(), Box::new(Scalar {
                default: Some("Daemon".to_string()),
                .. Default::default() }) as Box<Validator>),
            ("volumes".to_string(), Box::new(Mapping {
                key_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                value_element: volume_validator(),
            .. Default::default() }) as Box<Validator>),
            ("user_id".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default()}) as Box<Validator>),
            ("group_id".to_string(), Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("memory_limit".to_string(), Box::new(Numeric {
                default: Some(0x7fffffffffffffffi64),
                .. Default::default()}) as Box<Validator>),
            ("fileno_limit".to_string(), Box::new(Numeric {
                default: Some(1024),
                .. Default::default()}) as Box<Validator>),
            ("cpu_shares".to_string(), Box::new(Numeric {
                default: Some(1024),
                .. Default::default()}) as Box<Validator>),
            ("restart_timeout".to_string(), Box::new(Numeric {
                min: Some(0),
                max: Some(86400),
                default: Some(1),
                .. Default::default()}) as Box<Validator>),
            ("executable".to_string(), Box::new(Scalar {
                .. Default::default() }) as Box<Validator>),
            ("arguments".to_string(), Box::new(Sequence {
                element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                .. Default::default() }) as Box<Validator>),
            ("environ".to_string(), Box::new(Mapping {
                key_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                value_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
            .. Default::default() }) as Box<Validator>),
            ("workdir".to_string(), Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("resolv_conf".to_string(), Box::new(Structure { members: vec!(
                ("copy_from_host".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ), .. Default::default()}) as Box<Validator>),
            ("hosts_file".to_string(), Box::new(Structure { members: vec!(
                ("localhost".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ("public_hostname".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ), .. Default::default()}) as Box<Validator>),
            ("uid_map".to_string(), mapping_validator()),
            ("gid_map".to_string(), mapping_validator()),
            ("stdout_stderr_file".to_string(), Box::new(Scalar {
                optional: true,
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("restart_process_only".to_string(), Box::new(Scalar {
                default: Some("false".to_string()),
                .. Default::default() }) as Box<Validator>),
        ), .. Default::default() }) as Box<Validator>;
    }
}

pub fn volume_validator<'a>() -> Box<Validator + 'a> {
    return Box::new(Enum { options: vec!(
        ("Persistent".to_string(),  Box::new(Structure { members: vec!(
            ("path".to_string(),  Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mkdir".to_string(),  Box::new(Scalar {
                default: Some("false".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o700),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ("user".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("group".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ("Readonly".to_string(), Box::new(Scalar {
            .. Default::default()}) as Box<Validator>),
        ("Tmpfs".to_string(),  Box::new(Structure { members: vec!(
            ("size".to_string(),  Box::new(Numeric {
                min: Some(0),
                default: Some(100*1024*1024),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o1777),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ("Statedir".to_string(),  Box::new(Structure { members: vec!(
            ("path".to_string(),  Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o700),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ("user".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("group".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ), .. Default::default()}) as Box<Validator>;
}

fn _map_id(map: &Vec<IdMap>, id: u32) -> Option<u32> {
    if map.len() == 0 {
        return Some(id);
    }
    for rng in map.iter() {
        if id >= rng.outside && id <= rng.outside + rng.count {
            return Some(rng.inside + (id - rng.outside));
        }
    }
    None
}
<commit_msg>Fix converting uid for filesystem mounts<commit_after>use std::path::PathBuf;
use std::default::Default;
use std::collections::BTreeMap;

use quire::validate::{Validator, Structure, Sequence, Scalar, Numeric, Enum};
use quire::validate::{Mapping};
use self::Volume::*;

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct TmpfsInfo {
    pub size: usize,
    pub mode: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct PersistentInfo {
    pub path: PathBuf,
    pub mkdir: bool,
    pub mode: u32,
    pub user: u32,
    pub group: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub struct StatedirInfo {
    pub path: PathBuf,
    pub mode: u32,
    pub user: u32,
    pub group: u32,
}

#[derive(RustcDecodable, RustcEncodable, Clone, PartialEq, Eq)]
pub enum Volume {
    Readonly(PathBuf),
    Persistent(PersistentInfo),
    Tmpfs(TmpfsInfo),
    Statedir(StatedirInfo),
}

#[derive(RustcDecodable, RustcEncodable, Debug, PartialEq, Eq)]
pub enum ContainerKind {
    Daemon,
    Command,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ResolvConf {
    pub copy_from_host: bool,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct HostsFile {
    pub localhost: bool,
    pub public_hostname: bool,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Copy, Debug)]
pub struct IdMap {
    pub inside: u32,
    pub outside: u32,
    pub count: u32,
}

#[derive(RustcDecodable, RustcEncodable)]
pub struct ContainerConfig {
    pub kind: ContainerKind,
    pub volumes: BTreeMap<String, Volume>,
    pub user_id: u32,
    pub group_id: u32,
    pub restart_timeout: f32,
    pub memory_limit: u64,
    pub fileno_limit: u64,
    pub cpu_shares: usize,
    pub executable: String,
    pub arguments: Vec<String>,
    pub environ: BTreeMap<String, String>,
    pub workdir: PathBuf,
    pub resolv_conf: ResolvConf,
    pub hosts_file: HostsFile,
    pub uid_map: Vec<IdMap>,
    pub gid_map: Vec<IdMap>,
    pub stdout_stderr_file: Option<PathBuf>,
    pub restart_process_only: bool,
}

fn mapping_validator<'x>() -> Box<Validator + 'x> {
    return Box::new(Sequence {
        element: Box::new(Structure { members: vec!(
            ("inside".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("outside".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("count".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default() }) as Box<Validator>),
            ), .. Default::default() }) as Box<Validator>,
        .. Default::default() }) as Box<Validator>;
}

impl ContainerConfig {
    pub fn map_uid(&self, internal_uid: u32) -> Option<u32> {
        _map_id(&self.uid_map, internal_uid)
    }
    pub fn map_gid(&self, internal_gid: u32) -> Option<u32> {
        _map_id(&self.gid_map, internal_gid)
    }
    pub fn validator<'x>() -> Box<Validator + 'x> {
        return Box::new(Structure { members: vec!(
            ("kind".to_string(), Box::new(Scalar {
                default: Some("Daemon".to_string()),
                .. Default::default() }) as Box<Validator>),
            ("volumes".to_string(), Box::new(Mapping {
                key_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                value_element: volume_validator(),
            .. Default::default() }) as Box<Validator>),
            ("user_id".to_string(), Box::new(Numeric {
                default: None,
                .. Default::default()}) as Box<Validator>),
            ("group_id".to_string(), Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("memory_limit".to_string(), Box::new(Numeric {
                default: Some(0x7fffffffffffffffi64),
                .. Default::default()}) as Box<Validator>),
            ("fileno_limit".to_string(), Box::new(Numeric {
                default: Some(1024),
                .. Default::default()}) as Box<Validator>),
            ("cpu_shares".to_string(), Box::new(Numeric {
                default: Some(1024),
                .. Default::default()}) as Box<Validator>),
            ("restart_timeout".to_string(), Box::new(Numeric {
                min: Some(0),
                max: Some(86400),
                default: Some(1),
                .. Default::default()}) as Box<Validator>),
            ("executable".to_string(), Box::new(Scalar {
                .. Default::default() }) as Box<Validator>),
            ("arguments".to_string(), Box::new(Sequence {
                element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                .. Default::default() }) as Box<Validator>),
            ("environ".to_string(), Box::new(Mapping {
                key_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
                value_element: Box::new(Scalar {
                    .. Default::default() }) as Box<Validator>,
            .. Default::default() }) as Box<Validator>),
            ("workdir".to_string(), Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("resolv_conf".to_string(), Box::new(Structure { members: vec!(
                ("copy_from_host".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ), .. Default::default()}) as Box<Validator>),
            ("hosts_file".to_string(), Box::new(Structure { members: vec!(
                ("localhost".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ("public_hostname".to_string(), Box::new(Scalar {
                    default: Some("true".to_string()),
                    .. Default::default() }) as Box<Validator>),
                ), .. Default::default()}) as Box<Validator>),
            ("uid_map".to_string(), mapping_validator()),
            ("gid_map".to_string(), mapping_validator()),
            ("stdout_stderr_file".to_string(), Box::new(Scalar {
                optional: true,
                default: None,
                .. Default::default() }) as Box<Validator>),
            ("restart_process_only".to_string(), Box::new(Scalar {
                default: Some("false".to_string()),
                .. Default::default() }) as Box<Validator>),
        ), .. Default::default() }) as Box<Validator>;
    }
}

pub fn volume_validator<'a>() -> Box<Validator + 'a> {
    return Box::new(Enum { options: vec!(
        ("Persistent".to_string(),  Box::new(Structure { members: vec!(
            ("path".to_string(),  Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mkdir".to_string(),  Box::new(Scalar {
                default: Some("false".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o700),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ("user".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("group".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ("Readonly".to_string(), Box::new(Scalar {
            .. Default::default()}) as Box<Validator>),
        ("Tmpfs".to_string(),  Box::new(Structure { members: vec!(
            ("size".to_string(),  Box::new(Numeric {
                min: Some(0),
                default: Some(100*1024*1024),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o1777),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ("Statedir".to_string(),  Box::new(Structure { members: vec!(
            ("path".to_string(),  Box::new(Scalar {
                default: Some("/".to_string()),
                .. Default::default()}) as Box<Validator>),
            ("mode".to_string(),  Box::new(Numeric {
                min: Some(0),
                max: Some(0o700),
                default: Some(0o766),
                .. Default::default()}) as Box<Validator>),
            ("user".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ("group".to_string(),  Box::new(Numeric {
                default: Some(0),
                .. Default::default()}) as Box<Validator>),
            ),.. Default::default()}) as Box<Validator>),
        ), .. Default::default()}) as Box<Validator>;
}

fn _map_id(map: &Vec<IdMap>, /*internal*/id: u32) -> Option<u32> {
    if map.len() == 0 {
        return Some(id);
    }
    for rng in map.iter() {
        if id >= rng.inside && id <= rng.inside + rng.count {
            return Some(rng.outside + (id - rng.inside));
        }
    }
    None
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Networking interfaces.
//!
//! This module provides generic, abstract networking interfaces for sending
//! buffers over a "network". The term "network" is used very loosely: for
//! our purposes, a network is an object upon which we can transact encoded
//! buffers along with the bits necessary to encode a Cerberus header.
//!
//! For example, if an integration wished to recieve requests from a "host"
//! device over a SPI line, it tie up all the necessary implementation
//! details into a [`HostPort`] implementation.
//!
//! [`HostPort`]: trait.HostPort.html

#![allow(missing_docs)]

use static_assertions::assert_obj_safe;

use crate::io;
use crate::io::Cursor;
use crate::io::Read;
use crate::io::Write;

pub use crate::protocol::Header;

/// A networking error.
#[derive(Copy, Clone, Debug)]
pub enum Error {
    /// Indicates an inderlying I/O error.
    Io(io::Error),
    /// Indicates an error constructing (or interpreting) an abstract Manticore
    /// header.
    BadHeader,
    /// Indicates that the other end of a connection is "disconnected". This
    /// can mean anything from a connection being explicitly terminated, to
    /// some internal timeout expiring.
    Disconnected,
    /// Indicates that some operation was done out of order, such as attempting
    /// to reference part of the request once a reply has begun.
    OutOfOrder,
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

/// Represents a physical port that can be used to interact with host devices.
///
/// This trait provides a generic mechanism for recieving and responding to
/// requests from host devices. A value of a type implementing this trait
/// implements the entire network stack below the Cerberus protocol: it must
/// know how to speak the physical layer and assemble messages out of that
/// physical layer's packets.
///
/// `HostPort` uses the traits [`HostRequest`] and [`HostReply`] to describe
/// a generic state machine, where a request is processed and replied to.
/// ```
/// # use manticore::net::*;
/// fn process_request(port: &mut impl HostPort) -> Result<(), Error> {
///     let req = port.receive()?;
///     let header = req.header()?;
///     let message = req.payload()?;
///     // At this point, you can use the contents of `header`, and the
///     // bytes in `message`, to construct a response. This will involve
///     // creating a new header for the response.
///
///     // ... do stuff with `message` ...
///
/// #   let resp_header = header;
///     // After calling `reply`, `message` will be inaccessible, so it
///     // needs to be consumed as far as necessary before this step.
///     let resp = req.reply(resp_header)?;
///
///     let sink = resp.sink()?;
///     // Now, the computed response can be written to `sink`:
/// #   let resp_message = [1, 2, 3];
///     sink.write_bytes(&resp_message);
///
///     // Finally, we finish the reply by calling `finish()`. This is
///     // necessary to signal to the port that we don't plan to add any
///     // more bytes.
///     resp.finish()
/// }
/// ```
/// Note that a lot of the state transitions described above aren't perfectly
/// enforced, because, since we want `HostPort` to be object-safe, we need to
/// use references exclusively. Implementations should return
/// [`Error::OutOfOrder`] when this state ordering is violated.
///
/// [`InMemHost`] is a simple implementation meant for testing; its
/// documentation contains a concrete example of how to use `HostPort`'s
/// interface.
///
/// This trait is object-safe. In the future, associated types may be added,
/// but this will still permit using the trait in an object-safe way.
///
/// # Implementing this trait
///
/// A `HostPort` provides all low-level management of incomming and outgoing
/// connections. An implementation is responsible for packet assembly,
/// verifying redundancy codes, tracking AEAD tags, and so on, exposing only
/// an abstract header and a I/O for the message payload itself to Manticore.
///
/// Moreover, implementations must be "robust". If a caller, for whatever
/// reason, drops any of the returned traits on the ground and attempts to
/// begin a new connection, `HostPort` must also drop any state regarding
/// that connection on the ground. Because all of the state is tied up with
/// a mutable reference, implementors can assume that upon calling `recieve()`,
/// a client isn't holding onto stale connection state.
///
/// Implementing this trait in a way that makes the borrow checker happy is
/// non-trivial, so [`InMemHost`] is also a useful example of how to build the
/// required "Russian nesting dolls" of trait objects.
///
/// [`HostRequest`]: trait.HostRequest.html
/// [`HostResponse`]: trait.HostResponse.html
/// [`InMemHost`]: struct.InMemHost.html
pub trait HostPort {
    /// Receives an incomming message from a connected host device.
    ///
    /// This function will block until a host device indicates that it wishes
    /// to communicate. At that point, this function will perform enough
    /// transport-level operations to populate an abstract Manticore header,
    /// and then hand off parsing to the caller.
    ///
    /// When a request begins, this function returns a [`HostRequest`], which
    /// can be used to respond to the request.
    ///
    /// [`HostRequest`]: trait.HostRequest.html
    fn receive(&mut self) -> Result<&mut dyn HostRequest, Error>;
}
assert_obj_safe!(HostPort);

/// Provides the "request" half of a transaction with a host.
///
/// See [`HostPort`](trait.HostPort.html) for more information.
pub trait HostRequest {
    /// Returns the header sent by the host for this request.
    ///
    /// This function should not be called after calling `reply()`.
    fn header(&self) -> Result<Header, Error>;

    /// Returns the raw byte stream for the payload of the request.
    ///
    /// This function should not be called after calling `reply()`.
    fn payload(&mut self) -> Result<&mut dyn Read, Error>;

    /// Replies to this request..
    ///
    /// Calling this function performs sufficient transport-level operations to
    /// begin a response, before handing off actually composing the payload to
    /// the caller via the returned [`HostResponse`].
    ///
    /// [`HostResponse`]: trait.HostResponse.html
    fn reply(&mut self, header: Header)
        -> Result<&mut dyn HostResponse, Error>;
}

/// Provides the "reponse" half of a transaction with a host.
///
/// See [`HostPort`](trait.HostPort.html) for more information.
pub trait HostResponse {
    /// Returns the raw byte stream for building the payload of the response.
    ///
    /// This function should not be called after calling `finish()`.
    fn sink(&mut self) -> Result<&mut dyn Write, Error>;

    /// Indicates that all payload data has been written.
    ///
    /// Callers should remember to call this function; failing to do so may
    /// result in a response not being sent properly.
    fn finish(&mut self) -> Result<(), Error>;
}

/// A simple in-memory [`HostPort`].
///
/// This type is both useful for testing, and as a demonstration of how to use
/// a [`HostPort`] and its associated traits.
///
/// [`HostPort`]: trait.HostPort.html
///
/// # Example
/// ```
/// # use manticore::io::*;
/// # use manticore::mem::*;
/// # use manticore::net::*;
/// # use manticore::protocol::*;
/// # use manticore::protocol::firmware_version::*;
/// # use manticore::protocol::wire::*;
/// // Build the InMemHost.
/// let mut buf = [0; 64];
/// let mut host = InMemHost::new(&mut buf);
///
/// // Prepare a request to push into the host.
/// let header = Header {
///     command: CommandType::FirmwareVersion,
///     is_request: true,
/// };
/// let req = [0];
/// host.request(header, &req);
///
/// // Set up an arena for parsing.
/// let mut arena = [0; 64];
/// let mut arena = BumpArena::new(&mut arena);
///
/// // Prepare to recieve a message.
/// let mut host_req = host.receive()?;
/// let header = host_req.header()?;
/// assert_eq!(header.command, CommandType::FirmwareVersion);
/// assert!(header.is_request);
///
/// // Parse and process the message.
/// let req = FirmwareVersionRequest::from_wire(
///     host_req.payload()?, &arena).unwrap();
/// assert_eq!(req.index, 0);
///
/// // Prepare to reply to the message.
/// let mut host_resp = host_req.reply(Header {
///     command: CommandType::FirmwareVersion,
///     is_request: false,
/// })?;
///
/// // Build and write a reply.
/// let resp = FirmwareVersionResponse {
///     version: &[0xba; 32],
/// };
/// resp.to_wire(host_resp.sink()?).unwrap();
/// host_resp.finish()?;
///
/// // Check that we got the right data back.
/// let (header, resp_bytes) = host.response().unwrap();
/// assert_eq!(header.command, CommandType::FirmwareVersion);
/// assert!(!header.is_request);
///
/// // Now, parse the response.
/// arena.reset();
/// let resp = FirmwareVersionResponse::from_wire(resp_bytes, &arena).unwrap();
/// assert_eq!(resp.version, &[0xba; 32]);
/// # Ok::<(), manticore::net::Error>(())
/// ```
pub struct InMemHost<'buf>(InMemInner<'buf>);

/// The actual guts of an `InMemHost`. This struct is used to implement the two
/// "connection state" traits used by `HostPort`.
///
/// This type is separate from `InMemHost` to hide an implementation detail. If
/// the connection state traits were implemented by `HostPort`, a caller could
/// simply convert InMemHost directly to a `HostResponse`, violating the
/// expected order of operations. This struct can be thought of as making the
/// impls of the connection traits for `InMemHost` "private".
///
/// Implementors of `HostPort` should take care that the same is not possible
/// with their implementation.
struct InMemInner<'buf> {
    rx_header: Option<Header>,
    rx: &'buf [u8],
    tx_header: Option<Header>,
    tx: Cursor<'buf>,
    finished: bool,
}

impl<'buf> InMemHost<'buf> {
    /// Creates a new `InMemHost`, with the given output buffer for holding
    /// messages to be "transmitted", acting as the final destination for
    /// replies to this host.
    pub fn new(out: &'buf mut [u8]) -> Self {
        Self(InMemInner {
            rx_header: None,
            rx: &[],
            tx_header: None,
            tx: Cursor::new(out),
            finished: false,
        })
    }

    /// Schedules a new request to be recieved, with the given request parts.
    ///
    /// Calling this function will make `recieve()` start working; otherwise,
    /// it will assert that the port is disconnected.
    pub fn request(&mut self, header: Header, message: &'buf [u8]) {
        self.0.rx_header = Some(header);
        self.0.rx = message;

        // Should be Cursor::seek when we get that.
        self.0.tx_header = None;
        let _ = self.0.tx.take_consumed_bytes();
        self.0.finished = false;
    }

    /// Gets the most recent response recieved until `request()` is called
    /// again.
    pub fn response(&self) -> Option<(Header, &[u8])> {
        match self.0.tx_header {
            Some(header) => Some((header, self.0.tx.consumed_bytes())),
            None => None,
        }
    }
}

impl HostPort for InMemHost<'_> {
    fn receive(&mut self) -> Result<&mut dyn HostRequest, Error> {
        if self.0.rx_header.is_none() {
            return Err(Error::Disconnected);
        }
        Ok(&mut self.0)
    }
}

impl HostRequest for InMemInner<'_> {
    fn header(&self) -> Result<Header, Error> {
        self.rx_header.ok_or(Error::OutOfOrder)
    }

    fn payload(&mut self) -> Result<&mut dyn Read, Error> {
        if self.rx_header.is_none() {
            return Err(Error::OutOfOrder);
        }
        Ok(&mut self.rx)
    }

    fn reply(
        &mut self,
        header: Header,
    ) -> Result<&mut dyn HostResponse, Error> {
        self.rx_header = None;
        self.tx_header = Some(header);
        Ok(self)
    }
}

impl HostResponse for InMemInner<'_> {
    fn sink(&mut self) -> Result<&mut dyn Write, Error> {
        if self.finished {
            return Err(Error::OutOfOrder);
        }
        Ok(&mut self.tx)
    }

    fn finish(&mut self) -> Result<(), Error> {
        self.finished = true;
        Ok(())
    }
}
<commit_msg>net: Add a DevicePort implementation<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! Networking interfaces.
//!
//! This module provides generic, abstract networking interfaces for sending
//! buffers over a "network". The term "network" is used very loosely: for
//! our purposes, a network is an object upon which we can transact encoded
//! buffers along with the bits necessary to encode a Cerberus header.
//!
//! For example, if an integration wished to recieve requests from a "host"
//! device over a SPI line, it tie up all the necessary implementation
//! details into a [`HostPort`] implementation.
//!
//! [`HostPort`]: trait.HostPort.html

#![allow(missing_docs)]

use core::cell::Cell;
use static_assertions::assert_obj_safe;

use crate::io;
use crate::io::Cursor;
use crate::io::Read;
use crate::io::Write;

pub use crate::protocol::Header;

/// A networking error.
#[derive(Copy, Clone, Debug)]
pub enum Error {
    /// Indicates an inderlying I/O error.
    Io(io::Error),
    /// Indicates an error constructing (or interpreting) an abstract Manticore
    /// header.
    BadHeader,
    /// Indicates that the other end of a connection is "disconnected". This
    /// can mean anything from a connection being explicitly terminated, to
    /// some internal timeout expiring.
    Disconnected,
    /// Indicates that some operation was done out of order, such as attempting
    /// to reference part of the request once a reply has begun.
    OutOfOrder,
    /// The operation timed out.
    Timeout,
}

impl From<io::Error> for Error {
    fn from(e: io::Error) -> Self {
        Self::Io(e)
    }
}

/// Represents a physical port that can be used to interact with host devices.
///
/// This trait provides a generic mechanism for recieving and responding to
/// requests from host devices. A value of a type implementing this trait
/// implements the entire network stack below the Cerberus protocol: it must
/// know how to speak the physical layer and assemble messages out of that
/// physical layer's packets.
///
/// `HostPort` uses the traits [`HostRequest`] and [`HostReply`] to describe
/// a generic state machine, where a request is processed and replied to.
/// ```
/// # use manticore::net::*;
/// fn process_request(port: &mut impl HostPort) -> Result<(), Error> {
///     let req = port.receive()?;
///     let header = req.header()?;
///     let message = req.payload()?;
///     // At this point, you can use the contents of `header`, and the
///     // bytes in `message`, to construct a response. This will involve
///     // creating a new header for the response.
///
///     // ... do stuff with `message` ...
///
/// #   let resp_header = header;
///     // After calling `reply`, `message` will be inaccessible, so it
///     // needs to be consumed as far as necessary before this step.
///     let resp = req.reply(resp_header)?;
///
///     let sink = resp.sink()?;
///     // Now, the computed response can be written to `sink`:
/// #   let resp_message = [1, 2, 3];
///     sink.write_bytes(&resp_message);
///
///     // Finally, we finish the reply by calling `finish()`. This is
///     // necessary to signal to the port that we don't plan to add any
///     // more bytes.
///     resp.finish()
/// }
/// ```
/// Note that a lot of the state transitions described above aren't perfectly
/// enforced, because, since we want `HostPort` to be object-safe, we need to
/// use references exclusively. Implementations should return
/// [`Error::OutOfOrder`] when this state ordering is violated.
///
/// [`InMemHost`] is a simple implementation meant for testing; its
/// documentation contains a concrete example of how to use `HostPort`'s
/// interface.
///
/// This trait is object-safe. In the future, associated types may be added,
/// but this will still permit using the trait in an object-safe way.
///
/// # Implementing this trait
///
/// A `HostPort` provides all low-level management of incomming and outgoing
/// connections. An implementation is responsible for packet assembly,
/// verifying redundancy codes, tracking AEAD tags, and so on, exposing only
/// an abstract header and a I/O for the message payload itself to Manticore.
///
/// Moreover, implementations must be "robust". If a caller, for whatever
/// reason, drops any of the returned traits on the ground and attempts to
/// begin a new connection, `HostPort` must also drop any state regarding
/// that connection on the ground. Because all of the state is tied up with
/// a mutable reference, implementors can assume that upon calling `recieve()`,
/// a client isn't holding onto stale connection state.
///
/// Implementing this trait in a way that makes the borrow checker happy is
/// non-trivial, so [`InMemHost`] is also a useful example of how to build the
/// required "Russian nesting dolls" of trait objects.
///
/// [`HostRequest`]: trait.HostRequest.html
/// [`HostResponse`]: trait.HostResponse.html
/// [`InMemHost`]: struct.InMemHost.html
pub trait HostPort {
    /// Receives an incomming message from a connected host device.
    ///
    /// This function will block until a host device indicates that it wishes
    /// to communicate. At that point, this function will perform enough
    /// transport-level operations to populate an abstract Manticore header,
    /// and then hand off parsing to the caller.
    ///
    /// When a request begins, this function returns a [`HostRequest`], which
    /// can be used to respond to the request.
    ///
    /// [`HostRequest`]: trait.HostRequest.html
    fn receive(&mut self) -> Result<&mut dyn HostRequest, Error>;
}
assert_obj_safe!(HostPort);

/// Provides the "request" half of a transaction with a host.
///
/// See [`HostPort`](trait.HostPort.html) for more information.
pub trait HostRequest {
    /// Returns the header sent by the host for this request.
    ///
    /// This function should not be called after calling `reply()`.
    fn header(&self) -> Result<Header, Error>;

    /// Returns the raw byte stream for the payload of the request.
    ///
    /// This function should not be called after calling `reply()`.
    fn payload(&mut self) -> Result<&mut dyn Read, Error>;

    /// Replies to this request..
    ///
    /// Calling this function performs sufficient transport-level operations to
    /// begin a response, before handing off actually composing the payload to
    /// the caller via the returned [`HostResponse`].
    ///
    /// [`HostResponse`]: trait.HostResponse.html
    fn reply(&mut self, header: Header)
        -> Result<&mut dyn HostResponse, Error>;
}

/// Provides the "reponse" half of a transaction with a host.
///
/// See [`HostPort`](trait.HostPort.html) for more information.
pub trait HostResponse {
    /// Returns the raw byte stream for building the payload of the response.
    ///
    /// This function should not be called after calling `finish()`.
    fn sink(&mut self) -> Result<&mut dyn Write, Error>;

    /// Indicates that all payload data has been written.
    ///
    /// Callers should remember to call this function; failing to do so may
    /// result in a response not being sent properly.
    fn finish(&mut self) -> Result<(), Error>;
}

/// Represents a physical port that can be used to interact with client devices.
///
/// This for example is used for a PA RoT to send messages to a AC RoT.
///
/// This trait provides a generic mechanism for sending and receiving requests
/// from devices.
pub trait DevicePort {
    /// The send function takes a `header` and `msg` to send to a device.
    /// The implementation of this function must send the header and msg
    /// to the device specified by `dest`.
    ///
    /// This should block until the operation is complete.
    ///
    /// On success it should return nothing.
    /// On a failure an error is returned.
    fn send(
        &mut self,
        dest: u8,
        header: Header,
        msg: &[u8],
    ) -> Result<(), Error>;

    /// This is a blocking call that should wait for a response or a timeout.
    ///
    /// `duration`: Number of milliseconds to wait.
    ///
    /// If a response is received in time this should return a success.
    /// On a time out Error::Timeout is returned.
    /// Other errors should return a suitable Error as well.
    fn wait_for_response(&mut self, duration: usize) -> Result<(), Error>;

    /// The `process_response()` function should be called once a reply
    /// has been received for the device the `send()` operation was sent to.
    /// `msg` should contain the raw message to be processed.
    ///
    /// On success returns the response.
    fn receive_response(&mut self) -> Result<&mut dyn DeviceResponse, Error>;
}
assert_obj_safe!(DevicePort);

/// Provides the "response" half of a transaction with a device.
///
/// This for example is used for a PA RoT to send messages to a AC RoT.
pub trait DeviceResponse {
    /// Returns the header sent by the device for this response.
    fn header(&self) -> Result<Header, Error>;

    /// Returns the raw byte stream for the payload of the response.
    fn payload(&mut self) -> Result<&mut dyn Read, Error>;
}

/// A simple in-memory [`HostPort`].
///
/// This type is both useful for testing, and as a demonstration of how to use
/// a [`HostPort`] and its associated traits.
///
/// [`HostPort`]: trait.HostPort.html
///
/// # Example
/// ```
/// # use manticore::io::*;
/// # use manticore::mem::*;
/// # use manticore::net::*;
/// # use manticore::protocol::*;
/// # use manticore::protocol::firmware_version::*;
/// # use manticore::protocol::wire::*;
/// // Build the InMemHost.
/// let mut buf = [0; 64];
/// let mut host = InMemHost::new(&mut buf);
///
/// // Prepare a request to push into the host.
/// let header = Header {
///     command: CommandType::FirmwareVersion,
///     is_request: true,
/// };
/// let req = [0];
/// host.request(header, &req);
///
/// // Set up an arena for parsing.
/// let mut arena = [0; 64];
/// let mut arena = BumpArena::new(&mut arena);
///
/// // Prepare to recieve a message.
/// let mut host_req = host.receive()?;
/// let header = host_req.header()?;
/// assert_eq!(header.command, CommandType::FirmwareVersion);
/// assert!(header.is_request);
///
/// // Parse and process the message.
/// let req = FirmwareVersionRequest::from_wire(
///     host_req.payload()?, &arena).unwrap();
/// assert_eq!(req.index, 0);
///
/// // Prepare to reply to the message.
/// let mut host_resp = host_req.reply(Header {
///     command: CommandType::FirmwareVersion,
///     is_request: false,
/// })?;
///
/// // Build and write a reply.
/// let resp = FirmwareVersionResponse {
///     version: &[0xba; 32],
/// };
/// resp.to_wire(host_resp.sink()?).unwrap();
/// host_resp.finish()?;
///
/// // Check that we got the right data back.
/// let (header, resp_bytes) = host.response().unwrap();
/// assert_eq!(header.command, CommandType::FirmwareVersion);
/// assert!(!header.is_request);
///
/// // Now, parse the response.
/// arena.reset();
/// let resp = FirmwareVersionResponse::from_wire(resp_bytes, &arena).unwrap();
/// assert_eq!(resp.version, &[0xba; 32]);
/// # Ok::<(), manticore::net::Error>(())
/// ```
pub struct InMemHost<'buf>(InMemInner<'buf>);

/// The actual guts of an `InMemHost`. This struct is used to implement the two
/// "connection state" traits used by `HostPort`.
///
/// This type is separate from `InMemHost` to hide an implementation detail. If
/// the connection state traits were implemented by `HostPort`, a caller could
/// simply convert InMemHost directly to a `HostResponse`, violating the
/// expected order of operations. This struct can be thought of as making the
/// impls of the connection traits for `InMemHost` "private".
///
/// Implementors of `HostPort` should take care that the same is not possible
/// with their implementation.
struct InMemInner<'buf> {
    rx_header: Option<Header>,
    rx: &'buf [u8],
    tx_header: Option<Header>,
    tx: Cursor<'buf>,
    finished: bool,
}

impl<'buf> InMemHost<'buf> {
    /// Creates a new `InMemHost`, with the given output buffer for holding
    /// messages to be "transmitted", acting as the final destination for
    /// replies to this host.
    pub fn new(out: &'buf mut [u8]) -> Self {
        Self(InMemInner {
            rx_header: None,
            rx: &[],
            tx_header: None,
            tx: Cursor::new(out),
            finished: false,
        })
    }

    /// Schedules a new request to be recieved, with the given request parts.
    ///
    /// Calling this function will make `recieve()` start working; otherwise,
    /// it will assert that the port is disconnected.
    pub fn request(&mut self, header: Header, message: &'buf [u8]) {
        self.0.rx_header = Some(header);
        self.0.rx = message;

        // Should be Cursor::seek when we get that.
        self.0.tx_header = None;
        let _ = self.0.tx.take_consumed_bytes();
        self.0.finished = false;
    }

    /// Gets the most recent response recieved until `request()` is called
    /// again.
    pub fn response(&self) -> Option<(Header, &[u8])> {
        match self.0.tx_header {
            Some(header) => Some((header, self.0.tx.consumed_bytes())),
            None => None,
        }
    }
}

impl HostPort for InMemHost<'_> {
    fn receive(&mut self) -> Result<&mut dyn HostRequest, Error> {
        if self.0.rx_header.is_none() {
            return Err(Error::Disconnected);
        }
        Ok(&mut self.0)
    }
}

impl HostRequest for InMemInner<'_> {
    fn header(&self) -> Result<Header, Error> {
        self.rx_header.ok_or(Error::OutOfOrder)
    }

    fn payload(&mut self) -> Result<&mut dyn Read, Error> {
        if self.rx_header.is_none() {
            return Err(Error::OutOfOrder);
        }
        Ok(&mut self.rx)
    }

    fn reply(
        &mut self,
        header: Header,
    ) -> Result<&mut dyn HostResponse, Error> {
        self.rx_header = None;
        self.tx_header = Some(header);
        Ok(self)
    }
}

impl HostResponse for InMemInner<'_> {
    fn sink(&mut self) -> Result<&mut dyn Write, Error> {
        if self.finished {
            return Err(Error::OutOfOrder);
        }
        Ok(&mut self.tx)
    }

    fn finish(&mut self) -> Result<(), Error> {
        self.finished = true;
        Ok(())
    }
}

/// A simple in-memory [`DevicePort`].
pub struct InMemDevice<'buf>(InMemDeviceInner<'buf>);

struct InMemDeviceInner<'buf> {
    rx_header: Cell<Option<Header>>,
    rx: &'buf [u8],
    tx_dest: Cell<u8>,
    tx_header: Cell<Option<Header>>,
    tx: &'buf mut [u8],
    finished: Cell<bool>,
}

impl<'buf> Default for InMemDevice<'buf> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'buf> InMemDevice<'buf> {
    /// Creates a new `InMemDeviceInner`, with the given output buffer for holding
    /// messages to be "transmitted", acting as the final destination for
    /// replies to this host.
    pub fn new() -> Self {
        Self(InMemDeviceInner {
            rx_header: Cell::new(None),
            rx: &[],
            tx_dest: Cell::new(0),
            tx_header: Cell::new(None),
            tx: &mut [],
            finished: Cell::new(false),
        })
    }

    pub fn response(&mut self, header: Header, message: &'buf [u8]) {
        self.0.rx_header.set(Some(header));
        self.0.rx = message;
    }
}

impl<'buf> DevicePort for InMemDevice<'buf> {
    fn send(
        &mut self,
        dest: u8,
        header: Header,
        msg: &[u8],
    ) -> Result<(), Error> {
        self.0.tx_dest.set(dest);
        self.0.tx_header.set(Some(header));
        self.0.tx.copy_from_slice(msg);

        self.0.finished.set(false);

        Ok(())
    }

    fn wait_for_response(&mut self, _timeout: usize) -> Result<(), Error> {
        Ok(())
    }

    fn receive_response(&mut self) -> Result<&mut dyn DeviceResponse, Error> {
        Ok(&mut self.0)
    }
}
impl DeviceResponse for InMemDeviceInner<'_> {
    fn header(&self) -> Result<Header, Error> {
        if !self.finished.get() {
            return Err(Error::OutOfOrder);
        }
        Ok(self.tx_header.get().unwrap())
    }

    fn payload(&mut self) -> Result<&mut dyn Read, Error> {
        Ok(&mut self.rx)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::ops::*;

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct Checked<T>(pub Option<T>);

impl<T> Checked<T> {
    /// Creates a new Checked instance from some sort of integer.
    /// This is essentially equivalent to From\<T\>.
    /// # Examples
    /// ```
    /// use checked::Checked;
    ///
    /// let x = Checked::new(1_000_u32);
    /// let y = Checked::new(1_000_000_u32);
    /// assert_eq!(x * x, y);
    /// ```
    pub fn new(x: T) -> Checked<T> {
        Checked(Some(x))
    }
}

impl<T> Default for Checked<T> {
    fn default() -> Checked<T> {
        Checked(None)
    }
}

impl<T: fmt::Debug> fmt::Debug for Checked<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(ref x) => x.fmt(f),
            None => "overflow".fmt(f),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Checked<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(ref x) => x.fmt(f),
            None => "overflow".fmt(f),
        }
    }
}

// I'd like to do
// impl<T, U> From<U> where T: From<U> for Checked<T>
// in the obvious way, but that "conflicts" with the default impl From<T> for T.
// This would subsume both the above Froms since Option has the right From impl.
impl<T> From<T> for Checked<T> {
    fn from(x: T) -> Checked<T> {
        Checked(Some(x))
    }
}

impl<T> From<Option<T>> for Checked<T> {
    fn from(x: Option<T>) -> Checked<T> {
        Checked(x)
    }
}

// implements the unary operator "op &T"
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
    (impl $imp:ident, $method:ident for $t:ty {}) => {
        impl<'a> $imp for &'a $t {
            type Output = <$t as $imp>::Output;

            fn $method(self) -> <$t as $imp>::Output {
                $imp::$method(*self)
            }
        }
    }
}

// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty {}) => {
        impl<'a> $imp<$u> for &'a $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, other)
            }
        }

        impl<'a> $imp<&'a $u> for $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $imp<&'a $u> for &'b $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, *other)
            }
        }
    }
}

macro_rules! impl_sh {
    ($t:ident, $f:ident) => {
        impl Shl<Checked<$f>> for Checked<$t> {
            type Output = Checked<$t>;

            fn shl(self, other: Checked<$f>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.checked_shl(y)),
                    _ => Checked(None),
                }
            }
        }

        impl Shl<$f> for Checked<$t> {
            type Output = Checked<$t>;

            fn shl(self, other: $f) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.checked_shl(other)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shl, shl for Checked<$t>, Checked<$f> {} }
        forward_ref_binop! { impl Shl, shl for Checked<$t>, $f {} }

        impl ShlAssign<$f> for Checked<$t> {
            fn shl_assign(&mut self, other: $f) {
                *self = *self << other;
            }
        }

        impl ShlAssign<Checked<$f>> for Checked<$t> {
            fn shl_assign(&mut self, other: Checked<$f>) {
                *self = *self << other;
            }
        }

        impl Shr<Checked<$f>> for Checked<$t> {
            type Output = Checked<$t>;

            fn shr(self, other: Checked<$f>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.checked_shr(y)),
                    _ => Checked(None),
                }
            }
        }

        impl Shr<$f> for Checked<$t> {
            type Output = Checked<$t>;

            fn shr(self, other: $f) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.checked_shr(other)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shr, shr for Checked<$t>, Checked<$f> {} }
        forward_ref_binop! { impl Shr, shr for Checked<$t>, $f {} }

        impl ShrAssign<$f> for Checked<$t> {
            fn shr_assign(&mut self, other: $f) {
                *self = *self >> other;
            }
        }

        impl ShrAssign<Checked<$f>> for Checked<$t> {
            fn shr_assign(&mut self, other: Checked<$f>) {
                *self = *self >> other;
            }
        }
    };
}

macro_rules! impl_sh_reverse {
    ($t:ident, $f:ident) => {
        impl Shl<Checked<$t>> for $f {
            type Output = Checked<$f>;

            fn shl(self, other: Checked<$t>) -> Checked<$f> {
                match other.0 {
                    Some(x) => Checked(self.checked_shl(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shl, shl for $f, Checked<$t> {} }

        impl Shr<Checked<$t>> for $f {
            type Output = Checked<$f>;

            fn shr(self, other: Checked<$t>) -> Checked<$f> {
                match other.0 {
                    Some(x) => Checked(self.checked_shr(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shr, shr for $f, Checked<$t> {} }
    };
}

macro_rules! impl_sh_all {
    ($($t:ident)*) => ($(
        // When checked_shX is added for other shift sizes, uncomment some of these.
        // impl_sh! { $t, u8 }
        // impl_sh! { $t, u16 }
        impl_sh! { $t, u32 }
        //impl_sh! { $t, u64 }
        //impl_sh! { $t, usize }

        //impl_sh! { $t, i8 }
        //impl_sh! { $t, i16 }
        //impl_sh! { $t, i32 }
        //impl_sh! { $t, i64 }
        //impl_sh! { $t, isize }

        // impl_sh_reverse! { u8, $t }
        // impl_sh_reverse! { u16, $t }
        impl_sh_reverse! { u32, $t }
        //impl_sh_reverse! { u64, $t }
        //impl_sh_reverse! { usize, $t }

        //impl_sh_reverse! { i8, $t }
        //impl_sh_reverse! { i16, $t }
        //impl_sh_reverse! { i32, $t }
        //impl_sh_reverse! { i64, $t }
        //impl_sh_reverse! { isize, $t }
    )*)
}

impl_sh_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }

// implements unary operators for checked types
macro_rules! impl_unop {
    (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.$checked_method()),
                    None => Checked(None)
                }
            }
        }

        forward_ref_unop! { impl $imp, $method for Checked<$t> {} }
    }
}

// implements unary operators for checked types (with no checked method)
macro_rules! impl_unop_unchecked {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(Some($op x)),
                    None => Checked(None)
                }
            }
        }

        forward_ref_unop! { impl $imp, $method for Checked<$t> {} }
    }
}

// implements binary operators for checked types
macro_rules! impl_binop {
    (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.$checked_method(y)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<$t> for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: $t) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.$checked_method(other)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<Checked<$t>> for $t {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match other.0 {
                    Some(x) => Checked(self.$checked_method(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} }
        forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} }
        forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} }
    }
}

// implements binary operators for checked types (no checked method)
macro_rules! impl_binop_unchecked {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(Some(x $op y)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<$t> for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: $t) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(Some(x $op other)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<Checked<$t>> for $t {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match other.0 {
                    Some(x) => Checked(Some(self $op x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} }
        forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} }
        forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} }
    }
}

// implements assignment operators for checked types
macro_rules! impl_binop_assign {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            fn $method(&mut self, other: Checked<$t>) {
                *self = *self $op other;
            }
        }

        impl $imp<$t> for Checked<$t> {
            fn $method(&mut self, other: $t) {
                *self = *self $op other;
            }
        }
    };
}

macro_rules! checked_impl {
    ($($t:ty)*) => {
        $(
            impl_binop! { impl Add, add, checked_add for $t {} }
            impl_binop_assign! { impl AddAssign, add_assign for $t {+} }
            impl_binop! { impl Sub, sub, checked_sub for $t {} }
            impl_binop_assign! { impl SubAssign, sub_assign for $t {-} }
            impl_binop! { impl Mul, mul, checked_mul for $t {} }
            impl_binop_assign! { impl MulAssign, mul_assign for $t {*} }
            impl_binop! { impl Div, div, checked_div for $t {} }
            impl_binop_assign! { impl DivAssign, div_assign for $t {/} }
            impl_binop! { impl Rem, rem, checked_rem for $t {} }
            impl_binop_assign! { impl RemAssign, rem_assign for $t {%} }
            impl_unop_unchecked! { impl Not, not for $t {!} }
            impl_binop_unchecked! { impl BitXor, bitxor for $t {^} }
            impl_binop_assign! { impl BitXorAssign, bitxor_assign for $t {^} }
            impl_binop_unchecked! { impl BitOr, bitor for $t {|} }
            impl_binop_assign! { impl BitOrAssign, bitor_assign for $t {|} }
            impl_binop_unchecked! { impl BitAnd, bitand for $t {&} }
            impl_binop_assign! { impl BitAndAssign, bitand_assign for $t {&} }
            impl_unop! { impl Neg, neg, checked_neg for $t {} }
        )*
    };
}

checked_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
<commit_msg>add Into and AsRef for Checked<commit_after>use std::fmt;
use std::ops::*;

#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct Checked<T>(pub Option<T>);

impl<T> Checked<T> {
    /// Creates a new Checked instance from some sort of integer.
    /// This is essentially equivalent to From\<T\>.
    /// # Examples
    /// ```
    /// use checked::Checked;
    ///
    /// let x = Checked::new(1_000_u32);
    /// let y = Checked::new(1_000_000_u32);
    /// assert_eq!(x * x, y);
    /// ```
    pub fn new(x: T) -> Checked<T> {
        Checked(Some(x))
    }
}

// The derived Default only works if T has Default
// Even though this is what it would be anyway
impl<T> Default for Checked<T> {
    fn default() -> Checked<T> {
        Checked(None)
    }
}

impl<T: fmt::Debug> fmt::Debug for Checked<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(ref x) => x.fmt(f),
            None => "overflow".fmt(f),
        }
    }
}

impl<T: fmt::Display> fmt::Display for Checked<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            Some(ref x) => x.fmt(f),
            None => "overflow".fmt(f),
        }
    }
}

// I'd like to do
// impl<T, U> From<U> where T: From<U> for Checked<T>
// in the obvious way, but that "conflicts" with the default impl From<T> for T.
// This would subsume both the below Froms since Option has the right From impl.
impl<T> From<T> for Checked<T> {
    fn from(x: T) -> Checked<T> {
        Checked(Some(x))
    }
}

impl<T> From<Option<T>> for Checked<T> {
    fn from(x: Option<T>) -> Checked<T> {
        Checked(x)
    }
}

impl<T> Into<Option<T>> for Checked<T> {
    fn into(self) -> Option<T> {
        self.0
    }
}

impl<T> AsRef<Option<T>> for Checked<T> {
    fn as_ref(&self) -> &Option<T> {
        &self.0
    }
}

// implements the unary operator "op &T"
// based on "op T" where T is expected to be `Copy`able
macro_rules! forward_ref_unop {
    (impl $imp:ident, $method:ident for $t:ty {}) => {
        impl<'a> $imp for &'a $t {
            type Output = <$t as $imp>::Output;

            fn $method(self) -> <$t as $imp>::Output {
                $imp::$method(*self)
            }
        }
    }
}

// implements binary operators "&T op U", "T op &U", "&T op &U"
// based on "T op U" where T and U are expected to be `Copy`able
macro_rules! forward_ref_binop {
    (impl $imp:ident, $method:ident for $t:ty, $u:ty {}) => {
        impl<'a> $imp<$u> for &'a $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, other)
            }
        }

        impl<'a> $imp<&'a $u> for $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(self, *other)
            }
        }

        impl<'a, 'b> $imp<&'a $u> for &'b $t {
            type Output = <$t as $imp<$u>>::Output;

            fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output {
                $imp::$method(*self, *other)
            }
        }
    }
}

macro_rules! impl_sh {
    ($t:ident, $f:ident) => {
        impl Shl<Checked<$f>> for Checked<$t> {
            type Output = Checked<$t>;

            fn shl(self, other: Checked<$f>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.checked_shl(y)),
                    _ => Checked(None),
                }
            }
        }

        impl Shl<$f> for Checked<$t> {
            type Output = Checked<$t>;

            fn shl(self, other: $f) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.checked_shl(other)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shl, shl for Checked<$t>, Checked<$f> {} }
        forward_ref_binop! { impl Shl, shl for Checked<$t>, $f {} }

        impl ShlAssign<$f> for Checked<$t> {
            fn shl_assign(&mut self, other: $f) {
                *self = *self << other;
            }
        }

        impl ShlAssign<Checked<$f>> for Checked<$t> {
            fn shl_assign(&mut self, other: Checked<$f>) {
                *self = *self << other;
            }
        }

        impl Shr<Checked<$f>> for Checked<$t> {
            type Output = Checked<$t>;

            fn shr(self, other: Checked<$f>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.checked_shr(y)),
                    _ => Checked(None),
                }
            }
        }

        impl Shr<$f> for Checked<$t> {
            type Output = Checked<$t>;

            fn shr(self, other: $f) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.checked_shr(other)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shr, shr for Checked<$t>, Checked<$f> {} }
        forward_ref_binop! { impl Shr, shr for Checked<$t>, $f {} }

        impl ShrAssign<$f> for Checked<$t> {
            fn shr_assign(&mut self, other: $f) {
                *self = *self >> other;
            }
        }

        impl ShrAssign<Checked<$f>> for Checked<$t> {
            fn shr_assign(&mut self, other: Checked<$f>) {
                *self = *self >> other;
            }
        }
    };
}

macro_rules! impl_sh_reverse {
    ($t:ident, $f:ident) => {
        impl Shl<Checked<$t>> for $f {
            type Output = Checked<$f>;

            fn shl(self, other: Checked<$t>) -> Checked<$f> {
                match other.0 {
                    Some(x) => Checked(self.checked_shl(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shl, shl for $f, Checked<$t> {} }

        impl Shr<Checked<$t>> for $f {
            type Output = Checked<$f>;

            fn shr(self, other: Checked<$t>) -> Checked<$f> {
                match other.0 {
                    Some(x) => Checked(self.checked_shr(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl Shr, shr for $f, Checked<$t> {} }
    };
}

macro_rules! impl_sh_all {
    ($($t:ident)*) => ($(
        // When checked_shX is added for other shift sizes, uncomment some of these.
        // impl_sh! { $t, u8 }
        // impl_sh! { $t, u16 }
        impl_sh! { $t, u32 }
        //impl_sh! { $t, u64 }
        //impl_sh! { $t, usize }

        //impl_sh! { $t, i8 }
        //impl_sh! { $t, i16 }
        //impl_sh! { $t, i32 }
        //impl_sh! { $t, i64 }
        //impl_sh! { $t, isize }

        // impl_sh_reverse! { u8, $t }
        // impl_sh_reverse! { u16, $t }
        impl_sh_reverse! { u32, $t }
        //impl_sh_reverse! { u64, $t }
        //impl_sh_reverse! { usize, $t }

        //impl_sh_reverse! { i8, $t }
        //impl_sh_reverse! { i16, $t }
        //impl_sh_reverse! { i32, $t }
        //impl_sh_reverse! { i64, $t }
        //impl_sh_reverse! { isize, $t }
    )*)
}

impl_sh_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }

// implements unary operators for checked types
macro_rules! impl_unop {
    (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.$checked_method()),
                    None => Checked(None)
                }
            }
        }

        forward_ref_unop! { impl $imp, $method for Checked<$t> {} }
    }
}

// implements unary operators for checked types (with no checked method)
macro_rules! impl_unop_unchecked {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(Some($op x)),
                    None => Checked(None)
                }
            }
        }

        forward_ref_unop! { impl $imp, $method for Checked<$t> {} }
    }
}

// implements binary operators for checked types
macro_rules! impl_binop {
    (impl $imp:ident, $method:ident, $checked_method:ident for $t:ty {}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(x.$checked_method(y)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<$t> for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: $t) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(x.$checked_method(other)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<Checked<$t>> for $t {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match other.0 {
                    Some(x) => Checked(self.$checked_method(x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} }
        forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} }
        forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} }
    }
}

// implements binary operators for checked types (no checked method)
macro_rules! impl_binop_unchecked {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match (self.0, other.0) {
                    (Some(x), Some(y)) => Checked(Some(x $op y)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<$t> for Checked<$t> {
            type Output = Checked<$t>;

            fn $method(self, other: $t) -> Checked<$t> {
                match self.0 {
                    Some(x) => Checked(Some(x $op other)),
                    _ => Checked(None),
                }
            }
        }

        impl $imp<Checked<$t>> for $t {
            type Output = Checked<$t>;

            fn $method(self, other: Checked<$t>) -> Checked<$t> {
                match other.0 {
                    Some(x) => Checked(Some(self $op x)),
                    None => Checked(None),
                }
            }
        }

        forward_ref_binop! { impl $imp, $method for Checked<$t>, Checked<$t> {} }
        forward_ref_binop! { impl $imp, $method for Checked<$t>, $t {} }
        forward_ref_binop! { impl $imp, $method for $t, Checked<$t> {} }
    }
}

// implements assignment operators for checked types
macro_rules! impl_binop_assign {
    (impl $imp:ident, $method:ident for $t:ty {$op:tt}) => {
        impl $imp for Checked<$t> {
            fn $method(&mut self, other: Checked<$t>) {
                *self = *self $op other;
            }
        }

        impl $imp<$t> for Checked<$t> {
            fn $method(&mut self, other: $t) {
                *self = *self $op other;
            }
        }
    };
}

macro_rules! checked_impl {
    ($($t:ty)*) => {
        $(
            impl_binop! { impl Add, add, checked_add for $t {} }
            impl_binop_assign! { impl AddAssign, add_assign for $t {+} }
            impl_binop! { impl Sub, sub, checked_sub for $t {} }
            impl_binop_assign! { impl SubAssign, sub_assign for $t {-} }
            impl_binop! { impl Mul, mul, checked_mul for $t {} }
            impl_binop_assign! { impl MulAssign, mul_assign for $t {*} }
            impl_binop! { impl Div, div, checked_div for $t {} }
            impl_binop_assign! { impl DivAssign, div_assign for $t {/} }
            impl_binop! { impl Rem, rem, checked_rem for $t {} }
            impl_binop_assign! { impl RemAssign, rem_assign for $t {%} }
            impl_unop_unchecked! { impl Not, not for $t {!} }
            impl_binop_unchecked! { impl BitXor, bitxor for $t {^} }
            impl_binop_assign! { impl BitXorAssign, bitxor_assign for $t {^} }
            impl_binop_unchecked! { impl BitOr, bitor for $t {|} }
            impl_binop_assign! { impl BitOrAssign, bitor_assign for $t {|} }
            impl_binop_unchecked! { impl BitAnd, bitand for $t {&} }
            impl_binop_assign! { impl BitAndAssign, bitand_assign for $t {&} }
            impl_unop! { impl Neg, neg, checked_neg for $t {} }
        )*
    };
}

checked_impl! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize }
<|endoftext|>


<commit_before>//! Data types for text representations of board positions and moves, which may be used for [Portable game notation][1].
//!
//! The terminology used in this module is specific to chess and chess variants, but it can be implemented for any game.
//!
//! [1]: https://en.wikipedia.org/wiki/Portable_Game_Notation

use search_algorithms::board;
use std::error;
use std::fmt;

/// A list of general categories of errors related to pgn parsing.
///
/// This list is intended to grow over time and it is not recommended to exhaustively match against it.
///
/// It is used with the [`Error`] type.
///
/// [`Error`]: struct.Error.html
#[derive(Clone, Copy, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub enum ErrorKind {
    ParseError,
    AmbiguousMove,
    IllegalMove,
    IllegalPosition,
    Other,
}

/// The error type for operations on a `PgnBoard`.
///
/// The error can be created with an arbitrary payload and optionally an underlying source error for error chaining.
#[derive(Debug)]
pub struct Error {
    kind: ErrorKind,
    error: Box<dyn error::Error + Send + Sync>,
    source: Option<Box<dyn error::Error + Send + Sync>>,
}

impl Error {
    /// Returns a new error of the specific `ErrorKind` with an arbitrary payload.
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
    where E: Into<Box<dyn error::Error + Send + Sync>> {
        Error { kind, error: error.into(), source: None}
    }

    /// Returns a new error of the specific `ErrorKind` with an arbitrary payload and source error.
    pub fn new_caused_by<E, F>(kind: ErrorKind, error: E, source: F) -> Error
    where E: Into<Box<dyn error::Error + Send + Sync>>,
          F: Into<Box<dyn error::Error + Send + Sync>> {
        Error { kind, error: error.into(), source: Some(source.into())}
    }
}

impl error::Error for Error {}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.kind {
            ErrorKind::ParseError => write!(fmt, "Parse error. "),
            ErrorKind::AmbiguousMove => write!(fmt, "Ambiguous move. "),
            ErrorKind::IllegalMove => write!(fmt, "Illegal move. "),
            ErrorKind::IllegalPosition => write!(fmt, "Illegal position. "),
            ErrorKind::Other => Ok(()),
        }?;
        write!(fmt, "{}", self.error)?;
        if let Some(ref source) = self.source {
            write!(fmt, "\nCaused by: {}", source)?;
        }
        Ok(())
    }
}

/// Trait for text representations of board positions and moves.
///
/// The terminology used in this trait is specific to chess and chess variants, but it can be implemented for any game.
pub trait PgnBoard: Sized + board::Board {
    /// Constructs a board from [Forsyth–Edwards Notation][1].
    ///
    /// Extensions to this notation exist for all large chess variants
    ///
    /// [1]: https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
    fn from_fen(fen: &str) -> Result<Self, Error>;

    /// Returns a string representation of the board in [Forsyth–Edwards Notation][1].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
    fn to_fen(&self) -> String;

    /// Construct a game move from [Standard Algebraic Notation][1], specifically the format used in [pgn notation][2].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
    /// [2]: https://en.wikipedia.org/wiki/Portable_Game_Notation
    fn move_from_san(&self, input: &str) -> Result<Self::Move, Error>;

    /// Returns a string representation of the move in [Standard Algebraic Notation][1], specifically the format used in [pgn notation][2].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
    /// [2]: https://en.wikipedia.org/wiki/Portable_Game_Notation
    fn move_to_san(&self, mv: &Self::Move) -> String;

    /// Construct a move from an alternative, [long algebraic notation][1].
    ///
    /// This is mostly used for chess and chess variations in the uci interface, or for convenient debugging.
    /// Implementations may simply wrap this function around `move_from_san` where appropriate.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Long_algebraic_notation
    fn move_from_lan(&self, input: &str) -> Result<Self::Move, Error>;

    /// Returns a string representation of the move in an alternative, [long algebraic notation][1].
    ///
    /// This is mostly used for chess and chess variations in the uci interface, or for convenient debugging.
    /// Implementations may simply wrap this function around `move_to_san` where appropriate.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Long_algebraic_notation
    fn move_to_lan(&self, mv: &Self::Move) -> String;

}<commit_msg>Add ErrorKind::IOError<commit_after>//! Data types for text representations of board positions and moves, which may be used for [Portable game notation][1].
//!
//! The terminology used in this module is specific to chess and chess variants, but it can be implemented for any game.
//!
//! [1]: https://en.wikipedia.org/wiki/Portable_Game_Notation

use search_algorithms::board;
use std::error;
use std::fmt;

/// A list of general categories of errors related to pgn parsing.
///
/// This list is intended to grow over time and it is not recommended to exhaustively match against it.
///
/// It is used with the [`Error`] type.
///
/// [`Error`]: struct.Error.html
#[derive(Clone, Copy, Eq, PartialEq, Debug, PartialOrd, Ord)]
pub enum ErrorKind {
    ParseError,
    AmbiguousMove,
    IllegalMove,
    IllegalPosition,
    IOError,
    Other,
}

/// The error type for operations on a `PgnBoard`.
///
/// The error can be created with an arbitrary payload and optionally an underlying source error for error chaining.
#[derive(Debug)]
pub struct Error {
    kind: ErrorKind,
    error: Box<dyn error::Error + Send + Sync>,
    source: Option<Box<dyn error::Error + Send + Sync>>,
}

impl Error {
    /// Returns a new error of the specific `ErrorKind` with an arbitrary payload.
    pub fn new<E>(kind: ErrorKind, error: E) -> Error
    where E: Into<Box<dyn error::Error + Send + Sync>> {
        Error { kind, error: error.into(), source: None}
    }

    /// Returns a new error of the specific `ErrorKind` with an arbitrary payload and source error.
    pub fn new_caused_by<E, F>(kind: ErrorKind, error: E, source: F) -> Error
    where E: Into<Box<dyn error::Error + Send + Sync>>,
          F: Into<Box<dyn error::Error + Send + Sync>> {
        Error { kind, error: error.into(), source: Some(source.into())}
    }
}

impl error::Error for Error {}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self.kind {
            ErrorKind::ParseError => write!(fmt, "Parse error. "),
            ErrorKind::AmbiguousMove => write!(fmt, "Ambiguous move. "),
            ErrorKind::IllegalMove => write!(fmt, "Illegal move. "),
            ErrorKind::IllegalPosition => write!(fmt, "Illegal position. "),
            ErrorKind::IOError => write!(fmt, "IO error. "),
            ErrorKind::Other => Ok(()),
        }?;
        write!(fmt, "{}", self.error)?;
        if let Some(ref source) = self.source {
            write!(fmt, "\nCaused by: {}", source)?;
        }
        Ok(())
    }
}

/// Trait for text representations of board positions and moves.
///
/// The terminology used in this trait is specific to chess and chess variants, but it can be implemented for any game.
pub trait PgnBoard: Sized + board::Board {
    /// Constructs a board from [Forsyth–Edwards Notation][1].
    ///
    /// Extensions to this notation exist for all large chess variants
    ///
    /// [1]: https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
    fn from_fen(fen: &str) -> Result<Self, Error>;

    /// Returns a string representation of the board in [Forsyth–Edwards Notation][1].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation
    fn to_fen(&self) -> String;

    /// Construct a game move from [Standard Algebraic Notation][1], specifically the format used in [pgn notation][2].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
    /// [2]: https://en.wikipedia.org/wiki/Portable_Game_Notation
    fn move_from_san(&self, input: &str) -> Result<Self::Move, Error>;

    /// Returns a string representation of the move in [Standard Algebraic Notation][1], specifically the format used in [pgn notation][2].
    ///
    /// Extensions to this notation exist for all large chess variants.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)
    /// [2]: https://en.wikipedia.org/wiki/Portable_Game_Notation
    fn move_to_san(&self, mv: &Self::Move) -> String;

    /// Construct a move from an alternative, [long algebraic notation][1].
    ///
    /// This is mostly used for chess and chess variations in the uci interface, or for convenient debugging.
    /// Implementations may simply wrap this function around `move_from_san` where appropriate.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Long_algebraic_notation
    fn move_from_lan(&self, input: &str) -> Result<Self::Move, Error>;

    /// Returns a string representation of the move in an alternative, [long algebraic notation][1].
    ///
    /// This is mostly used for chess and chess variations in the uci interface, or for convenient debugging.
    /// Implementations may simply wrap this function around `move_to_san` where appropriate.
    ///
    /// [1]: https://en.wikipedia.org/wiki/Algebraic_notation_(chess)#Long_algebraic_notation
    fn move_to_lan(&self, mv: &Self::Move) -> String;

}<|endoftext|>