<commit_before>//! Common ReQL data types

extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate uuid;
extern crate chrono;

use std::net::IpAddr;
use std::collections::HashMap;
use std::ops::Deref;

use serde_json::Value;
use uuid::Uuid;
use serde::{Serialize, Deserialize, Serializer, Deserializer};

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DateTime(chrono::DateTime<chrono::Utc>);

/// Status returned by a write command
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct WriteStatus {
    pub inserted: u32,
    pub replaced: u32,
    pub unchanged: u32,
    pub skipped: u32,
    pub deleted: u32,
    pub errors: u32,
    pub first_error: Option<String>,
    pub generated_keys: Option<Vec<Uuid>>,
    pub warnings: Option<Vec<String>>,
    pub changes: Option<Value>,
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ClusterConfig {
    pub id: String,
    pub heartbeat_timeout_secs: u32,
}

/// Structure of data in `current_issues` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CurrentIssue {
}

/// Structure of data in `db_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DbConfig {
}

/// Structure of data in `jobs` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Job {
}

/// Structure of data in `logs` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Log {
}

/// Structure of data in `permissions` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Permission {
}

/// Structure of data in `server_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ServerConfig {
}

#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CanonicalAddress {
    pub host: IpAddr,
    pub port: u16,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Network {
    pub canonical_addresses: Vec<CanonicalAddress>,
    pub cluster_port: u16,
    pub connected_to: HashMap<String, bool>,
    pub hostname: String,
    pub http_admin_port: u16,
    pub reql_port: u16,
    pub time_connected: DateTime,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Process {
    pub argv: Vec<String>,
    pub cache_size_mb: f64,
    pub pid: u64,
    pub time_started: DateTime,
    pub version: String,
}

/// Structure of data in `server_status` table
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerStatus {
    pub id: Uuid,
    pub name: String,
    pub network: Network,
    pub process: Process,
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Stat {
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TableConfig {
}

/// Structure of data in `table_status` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TableStatus {
}

/// Structure of data in `uses` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct User {
}

#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Change<O, N> {
    pub old_val: Option<O>,
    pub new_val: Option<N>,
    #[serde(rename = "type")]
    pub result_type: Option<String>,
    pub old_offset: Option<usize>,
    pub new_offset: Option<usize>,
    pub state: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Time {
    #[serde(rename = "$reql_type$")]
    reql_type: String,
    epoch_time: f64,
    timezone: String,
}

impl<'de> Deserialize<'de> for DateTime {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        let time = Time::deserialize(deserializer)?;
        let secs = time.epoch_time.trunc() as i64;
        // RethinkDB timestamps have millisecond precision so we need
        // to convert the milliseconds to nanoseconds first
        let msecs = time.epoch_time.fract().abs() as u32;
        let naive = chrono::NaiveDateTime::from_timestamp(secs, msecs * 1_000_000);
        let dt = chrono::DateTime::<chrono::Utc>::from_utc(naive, chrono::Utc);
        Ok(DateTime(dt))
    }
}

impl Serialize for DateTime {
    fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        unimplemented!();
    }
}

impl Deref for DateTime {
    type Target = chrono::DateTime<chrono::Utc>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<commit_msg>serialise DateTime<commit_after>//! Common ReQL data types

extern crate serde_json;
#[macro_use]
extern crate serde_derive;
extern crate serde;
extern crate uuid;
extern crate chrono;

use std::net::IpAddr;
use std::collections::HashMap;
use std::ops::Deref;

use serde_json::Value;
use uuid::Uuid;
use serde::{Serialize, Deserialize, Serializer, Deserializer};

#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DateTime(pub chrono::DateTime<chrono::Utc>);

/// Status returned by a write command
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct WriteStatus {
    pub inserted: u32,
    pub replaced: u32,
    pub unchanged: u32,
    pub skipped: u32,
    pub deleted: u32,
    pub errors: u32,
    pub first_error: Option<String>,
    pub generated_keys: Option<Vec<Uuid>>,
    pub warnings: Option<Vec<String>>,
    pub changes: Option<Value>,
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ClusterConfig {
    pub id: String,
    pub heartbeat_timeout_secs: u32,
}

/// Structure of data in `current_issues` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CurrentIssue {
}

/// Structure of data in `db_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DbConfig {
}

/// Structure of data in `jobs` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Job {
}

/// Structure of data in `logs` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Log {
}

/// Structure of data in `permissions` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Permission {
}

/// Structure of data in `server_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ServerConfig {
}

#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CanonicalAddress {
    pub host: IpAddr,
    pub port: u16,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Network {
    pub canonical_addresses: Vec<CanonicalAddress>,
    pub cluster_port: u16,
    pub connected_to: HashMap<String, bool>,
    pub hostname: String,
    pub http_admin_port: u16,
    pub reql_port: u16,
    pub time_connected: DateTime,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Process {
    pub argv: Vec<String>,
    pub cache_size_mb: f64,
    pub pid: u64,
    pub time_started: DateTime,
    pub version: String,
}

/// Structure of data in `server_status` table
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct ServerStatus {
    pub id: Uuid,
    pub name: String,
    pub network: Network,
    pub process: Process,
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Stat {
}

/// Structure of data in `cluster_config` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TableConfig {
}

/// Structure of data in `table_status` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct TableStatus {
}

/// Structure of data in `uses` table
#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct User {
}

#[derive(Debug, Clone, Deserialize, Serialize, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Change<O, N> {
    pub old_val: Option<O>,
    pub new_val: Option<N>,
    #[serde(rename = "type")]
    pub result_type: Option<String>,
    pub old_offset: Option<usize>,
    pub new_offset: Option<usize>,
    pub state: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Time {
    #[serde(rename = "$reql_type$")]
    reql_type: String,
    epoch_time: f64,
    timezone: String,
}

impl<'de> Deserialize<'de> for DateTime {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
        where D: Deserializer<'de>
    {
        let time = Time::deserialize(deserializer)?;
        let secs = time.epoch_time.trunc() as i64;
        // RethinkDB timestamps have millisecond precision so we need
        // to convert the milliseconds to nanoseconds first
        let msecs = time.epoch_time.fract().abs() as u32;
        let naive = chrono::NaiveDateTime::from_timestamp(secs, msecs * 1_000_000);
        let dt = chrono::DateTime::<chrono::Utc>::from_utc(naive, chrono::Utc);
        Ok(DateTime(dt))
    }
}

impl Serialize for DateTime {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        let reql_type = String::from("TIME");
        let epoch_time = {
            let t = format!("{}.{}", self.0.timestamp(), self.0.timestamp_subsec_millis());
            t.parse().unwrap()
        };
        let timezone = String::from("+00:00");
        let time = Time { reql_type, epoch_time, timezone };
        time.serialize(serializer)
    }
}

impl Deref for DateTime {
    type Target = chrono::DateTime<chrono::Utc>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#[allow(unused_imports)]
#[macro_use]
extern crate msg_on_socket_derive;
extern crate data_model;
extern crate sys_util;

mod msg_on_socket;

use std::marker::PhantomData;
use std::os::unix::io::RawFd;
use std::os::unix::net::UnixDatagram;
use sys_util::{ScmSocket, UnlinkUnixDatagram};

pub use msg_on_socket::*;
pub use msg_on_socket_derive::*;

/// Create a pair of socket. Request is send in one direction while response is in the other
/// direction.
pub fn pair<Request: MsgOnSocket, Response: MsgOnSocket>(
) -> Option<(MsgSocket<Request, Response>, MsgSocket<Response, Request>)> {
    let (sock1, sock2) = match UnixDatagram::pair() {
        Ok((sock1, sock2)) => (sock1, sock2),
        _ => {
            return None;
        }
    };
    let requester = MsgSocket {
        sock: sock1,
        _i: PhantomData,
        _o: PhantomData,
    };
    let responder = MsgSocket {
        sock: sock2,
        _i: PhantomData,
        _o: PhantomData,
    };
    Some((requester, responder))
}

/// Bidirection sock that support both send and recv.
pub struct MsgSocket<I: MsgOnSocket, O: MsgOnSocket> {
    sock: UnixDatagram,
    _i: PhantomData<I>,
    _o: PhantomData<O>,
}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSocket<I, O> {
    // Create a new MsgSocket.
    pub fn new(s: UnixDatagram) -> MsgSocket<I, O> {
        MsgSocket {
            sock: s,
            _i: PhantomData,
            _o: PhantomData,
        }
    }
}

/// Bidirection sock that support both send and recv.
pub struct UnlinkMsgSocket<I: MsgOnSocket, O: MsgOnSocket> {
    sock: UnlinkUnixDatagram,
    _i: PhantomData<I>,
    _o: PhantomData<O>,
}

impl<I: MsgOnSocket, O: MsgOnSocket> UnlinkMsgSocket<I, O> {
    // Create a new MsgSocket.
    pub fn new(s: UnlinkUnixDatagram) -> UnlinkMsgSocket<I, O> {
        UnlinkMsgSocket {
            sock: s,
            _i: PhantomData,
            _o: PhantomData,
        }
    }
}

/// One direction socket that only supports sending.
pub struct Sender<M: MsgOnSocket> {
    sock: UnixDatagram,
    _m: PhantomData<M>,
}

impl<M: MsgOnSocket> Sender<M> {
    /// Create a new sender sock.
    pub fn new(s: UnixDatagram) -> Sender<M> {
        Sender {
            sock: s,
            _m: PhantomData,
        }
    }
}

/// One direction socket that only supports receiving.
pub struct Receiver<M: MsgOnSocket> {
    sock: UnixDatagram,
    _m: PhantomData<M>,
}

impl<M: MsgOnSocket> Receiver<M> {
    /// Create a new receiver sock.
    pub fn new(s: UnixDatagram) -> Receiver<M> {
        Receiver {
            sock: s,
            _m: PhantomData,
        }
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> AsRef<UnixDatagram> for MsgSocket<I, O> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> AsRef<UnixDatagram> for UnlinkMsgSocket<I, O> {
    fn as_ref(&self) -> &UnixDatagram {
        self.sock.as_ref()
    }
}

impl<M: MsgOnSocket> AsRef<UnixDatagram> for Sender<M> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

impl<M: MsgOnSocket> AsRef<UnixDatagram> for Receiver<M> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

/// Types that could send a message.
pub trait MsgSender<M: MsgOnSocket>: AsRef<UnixDatagram> {
    fn send(&self, msg: &M) -> MsgResult<()> {
        let msg_size = M::msg_size();
        let fd_size = M::max_fd_count();
        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];

        let fd_size = msg.write_to_buffer(&mut msg_buffer, &mut fd_buffer)?;
        let sock: &UnixDatagram = self.as_ref();
        sock.send_with_fds(&msg_buffer[..], &fd_buffer[0..fd_size])
            .map_err(|e| MsgError::Send(e))?;
        Ok(())
    }
}

/// Types that could receive a message.
pub trait MsgReceiver<M: MsgOnSocket>: AsRef<UnixDatagram> {
    fn recv(&self) -> MsgResult<M> {
        let msg_size = M::msg_size();
        let fd_size = M::max_fd_count();
        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];

        let sock: &UnixDatagram = self.as_ref();
        let (recv_msg_size, recv_fd_size) = sock
            .recv_with_fds(&mut msg_buffer, &mut fd_buffer)
            .map_err(|e| MsgError::Recv(e))?;
        if msg_size != recv_msg_size {
            return Err(MsgError::BadRecvSize(msg_size));
        }
        // Safe because fd buffer is read from socket.
        let (v, read_fd_size) = unsafe {
            M::read_from_buffer(&msg_buffer[0..recv_msg_size], &fd_buffer[0..recv_fd_size])?
        };
        if recv_fd_size != read_fd_size {
            return Err(MsgError::NotExpectFd);
        }
        Ok(v)
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSender<I> for MsgSocket<I, O> {}
impl<I: MsgOnSocket, O: MsgOnSocket> MsgReceiver<O> for MsgSocket<I, O> {}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSender<I> for UnlinkMsgSocket<I, O> {}
impl<I: MsgOnSocket, O: MsgOnSocket> MsgReceiver<O> for UnlinkMsgSocket<I, O> {}

impl<M: MsgOnSocket> MsgSender<M> for Sender<M> {}
impl<M: MsgOnSocket> MsgReceiver<M> for Receiver<M> {}

#[cfg(test)]
mod tests {
    use super::*;
    use sys_util::EventFd;

    #[derive(MsgOnSocket)]
    struct Request {
        field0: u8,
        field1: EventFd,
        field2: u32,
    }

    #[derive(MsgOnSocket)]
    enum Response {
        A(u8),
        B,
        C(u32, EventFd),
        D([u8; 4]),
        E { f0: u8, f1: u32 },
    }

    #[derive(MsgOnSocket)]
    struct Message(u8, u16, EventFd);

    #[test]
    fn sock_send_recv_struct() {
        let (req, res) = pair::<Request, Response>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        req.send(&Request {
            field0: 2,
            field1: e0,
            field2: 0xf0f0,
        }).unwrap();
        let r = res.recv().unwrap();
        assert_eq!(r.field0, 2);
        assert_eq!(r.field2, 0xf0f0);
        r.field1.write(0x0f0f).unwrap();
        assert_eq!(e1.read().unwrap(), 0x0f0f);
    }

    #[test]
    fn sock_send_recv_enum() {
        let (req, res) = pair::<Request, Response>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        res.send(&Response::C(0xf0f0, e0)).unwrap();
        let r = req.recv().unwrap();
        match r {
            Response::C(v, efd) => {
                assert_eq!(v, 0xf0f0);
                efd.write(0x0f0f).unwrap();
            }
            _ => panic!("wrong type"),
        };
        assert_eq!(e1.read().unwrap(), 0x0f0f);

        res.send(&Response::B).unwrap();
        match req.recv().unwrap() {
            Response::B => {}
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::A(0x3)).unwrap();
        match req.recv().unwrap() {
            Response::A(v) => assert_eq!(v, 0x3),
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::D([0, 1, 2, 3])).unwrap();
        match req.recv().unwrap() {
            Response::D(v) => assert_eq!(v, [0, 1, 2, 3]),
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::E {
            f0: 0x12,
            f1: 0x0f0f,
        }).unwrap();
        match req.recv().unwrap() {
            Response::E { f0, f1 } => {
                assert_eq!(f0, 0x12);
                assert_eq!(f1, 0x0f0f);
            }
            _ => panic!("Wrong enum type"),
        };
    }

    #[test]
    fn sock_send_recv_tuple() {
        let (req, res) = pair::<Message, Message>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        req.send(&Message(1, 0x12, e0)).unwrap();
        let r = res.recv().unwrap();
        assert_eq!(r.0, 1);
        assert_eq!(r.1, 0x12);
        r.2.write(0x0f0f).unwrap();
        assert_eq!(e1.read().unwrap(), 0x0f0f);
    }

}
<commit_msg>msg_socket: avoid send_msg/recv_msg call if it's not necessary<commit_after>// Copyright 2018 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#[allow(unused_imports)]
#[macro_use]
extern crate msg_on_socket_derive;
extern crate data_model;
#[macro_use]
extern crate sys_util;

mod msg_on_socket;

use std::io::Result;
use std::marker::PhantomData;
use std::os::unix::io::RawFd;
use std::os::unix::net::UnixDatagram;
use sys_util::{Error as SysError, ScmSocket, UnlinkUnixDatagram};

pub use msg_on_socket::*;
pub use msg_on_socket_derive::*;

/// Create a pair of socket. Request is send in one direction while response is in the other
/// direction.
pub fn pair<Request: MsgOnSocket, Response: MsgOnSocket>(
) -> Option<(MsgSocket<Request, Response>, MsgSocket<Response, Request>)> {
    let (sock1, sock2) = match UnixDatagram::pair() {
        Ok((sock1, sock2)) => (sock1, sock2),
        _ => {
            return None;
        }
    };
    let requester = MsgSocket {
        sock: sock1,
        _i: PhantomData,
        _o: PhantomData,
    };
    let responder = MsgSocket {
        sock: sock2,
        _i: PhantomData,
        _o: PhantomData,
    };
    Some((requester, responder))
}

/// Bidirection sock that support both send and recv.
pub struct MsgSocket<I: MsgOnSocket, O: MsgOnSocket> {
    sock: UnixDatagram,
    _i: PhantomData<I>,
    _o: PhantomData<O>,
}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSocket<I, O> {
    // Create a new MsgSocket.
    pub fn new(s: UnixDatagram) -> MsgSocket<I, O> {
        MsgSocket {
            sock: s,
            _i: PhantomData,
            _o: PhantomData,
        }
    }
}

/// Bidirection sock that support both send and recv.
pub struct UnlinkMsgSocket<I: MsgOnSocket, O: MsgOnSocket> {
    sock: UnlinkUnixDatagram,
    _i: PhantomData<I>,
    _o: PhantomData<O>,
}

impl<I: MsgOnSocket, O: MsgOnSocket> UnlinkMsgSocket<I, O> {
    // Create a new MsgSocket.
    pub fn new(s: UnlinkUnixDatagram) -> UnlinkMsgSocket<I, O> {
        UnlinkMsgSocket {
            sock: s,
            _i: PhantomData,
            _o: PhantomData,
        }
    }
}

/// One direction socket that only supports sending.
pub struct Sender<M: MsgOnSocket> {
    sock: UnixDatagram,
    _m: PhantomData<M>,
}

impl<M: MsgOnSocket> Sender<M> {
    /// Create a new sender sock.
    pub fn new(s: UnixDatagram) -> Sender<M> {
        Sender {
            sock: s,
            _m: PhantomData,
        }
    }
}

/// One direction socket that only supports receiving.
pub struct Receiver<M: MsgOnSocket> {
    sock: UnixDatagram,
    _m: PhantomData<M>,
}

impl<M: MsgOnSocket> Receiver<M> {
    /// Create a new receiver sock.
    pub fn new(s: UnixDatagram) -> Receiver<M> {
        Receiver {
            sock: s,
            _m: PhantomData,
        }
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> AsRef<UnixDatagram> for MsgSocket<I, O> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> AsRef<UnixDatagram> for UnlinkMsgSocket<I, O> {
    fn as_ref(&self) -> &UnixDatagram {
        self.sock.as_ref()
    }
}

impl<M: MsgOnSocket> AsRef<UnixDatagram> for Sender<M> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

impl<M: MsgOnSocket> AsRef<UnixDatagram> for Receiver<M> {
    fn as_ref(&self) -> &UnixDatagram {
        &self.sock
    }
}

/// Types that could send a message.
pub trait MsgSender<M: MsgOnSocket>: AsRef<UnixDatagram> {
    fn send(&self, msg: &M) -> MsgResult<()> {
        let msg_size = M::msg_size();
        let fd_size = M::max_fd_count();
        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];

        let fd_size = msg.write_to_buffer(&mut msg_buffer, &mut fd_buffer)?;
        let sock: &UnixDatagram = self.as_ref();
        if fd_size == 0 {
            handle_eintr!(sock.send(&msg_buffer))
                .map_err(|e| MsgError::Send(SysError::new(e.raw_os_error().unwrap_or(0))))?;
        } else {
            sock.send_with_fds(&msg_buffer[..], &fd_buffer[0..fd_size])
                .map_err(|e| MsgError::Send(e))?;
        }
        Ok(())
    }
}

/// Types that could receive a message.
pub trait MsgReceiver<M: MsgOnSocket>: AsRef<UnixDatagram> {
    fn recv(&self) -> MsgResult<M> {
        let msg_size = M::msg_size();
        let fd_size = M::max_fd_count();
        let mut msg_buffer: Vec<u8> = vec![0; msg_size];
        let mut fd_buffer: Vec<RawFd> = vec![0; fd_size];

        let sock: &UnixDatagram = self.as_ref();

        let (recv_msg_size, recv_fd_size) = {
            if fd_size == 0 {
                let size = sock
                    .recv(&mut msg_buffer)
                    .map_err(|e| MsgError::Recv(SysError::new(e.raw_os_error().unwrap_or(0))))?;
                (size, 0)
            } else {
                sock.recv_with_fds(&mut msg_buffer, &mut fd_buffer)
                    .map_err(|e| MsgError::Recv(e))?
            }
        };
        if msg_size != recv_msg_size {
            return Err(MsgError::BadRecvSize(msg_size));
        }
        // Safe because fd buffer is read from socket.
        let (v, read_fd_size) = unsafe {
            M::read_from_buffer(&msg_buffer[0..recv_msg_size], &fd_buffer[0..recv_fd_size])?
        };
        if recv_fd_size != read_fd_size {
            return Err(MsgError::NotExpectFd);
        }
        Ok(v)
    }
}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSender<I> for MsgSocket<I, O> {}
impl<I: MsgOnSocket, O: MsgOnSocket> MsgReceiver<O> for MsgSocket<I, O> {}

impl<I: MsgOnSocket, O: MsgOnSocket> MsgSender<I> for UnlinkMsgSocket<I, O> {}
impl<I: MsgOnSocket, O: MsgOnSocket> MsgReceiver<O> for UnlinkMsgSocket<I, O> {}

impl<M: MsgOnSocket> MsgSender<M> for Sender<M> {}
impl<M: MsgOnSocket> MsgReceiver<M> for Receiver<M> {}

#[cfg(test)]
mod tests {
    use super::*;
    use sys_util::EventFd;

    #[derive(MsgOnSocket)]
    struct Request {
        field0: u8,
        field1: EventFd,
        field2: u32,
    }

    #[derive(MsgOnSocket)]
    enum Response {
        A(u8),
        B,
        C(u32, EventFd),
        D([u8; 4]),
        E { f0: u8, f1: u32 },
    }

    #[derive(MsgOnSocket)]
    struct Message(u8, u16, EventFd);

    #[test]
    fn sock_send_recv_struct() {
        let (req, res) = pair::<Request, Response>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        req.send(&Request {
            field0: 2,
            field1: e0,
            field2: 0xf0f0,
        }).unwrap();
        let r = res.recv().unwrap();
        assert_eq!(r.field0, 2);
        assert_eq!(r.field2, 0xf0f0);
        r.field1.write(0x0f0f).unwrap();
        assert_eq!(e1.read().unwrap(), 0x0f0f);
    }

    #[test]
    fn sock_send_recv_enum() {
        let (req, res) = pair::<Request, Response>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        res.send(&Response::C(0xf0f0, e0)).unwrap();
        let r = req.recv().unwrap();
        match r {
            Response::C(v, efd) => {
                assert_eq!(v, 0xf0f0);
                efd.write(0x0f0f).unwrap();
            }
            _ => panic!("wrong type"),
        };
        assert_eq!(e1.read().unwrap(), 0x0f0f);

        res.send(&Response::B).unwrap();
        match req.recv().unwrap() {
            Response::B => {}
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::A(0x3)).unwrap();
        match req.recv().unwrap() {
            Response::A(v) => assert_eq!(v, 0x3),
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::D([0, 1, 2, 3])).unwrap();
        match req.recv().unwrap() {
            Response::D(v) => assert_eq!(v, [0, 1, 2, 3]),
            _ => panic!("Wrong enum type"),
        };

        res.send(&Response::E {
            f0: 0x12,
            f1: 0x0f0f,
        }).unwrap();
        match req.recv().unwrap() {
            Response::E { f0, f1 } => {
                assert_eq!(f0, 0x12);
                assert_eq!(f1, 0x0f0f);
            }
            _ => panic!("Wrong enum type"),
        };
    }

    #[test]
    fn sock_send_recv_tuple() {
        let (req, res) = pair::<Message, Message>().unwrap();
        let e0 = EventFd::new().unwrap();
        let e1 = e0.try_clone().unwrap();
        req.send(&Message(1, 0x12, e0)).unwrap();
        let r = res.recv().unwrap();
        assert_eq!(r.0, 1);
        assert_eq!(r.1, 0x12);
        r.2.write(0x0f0f).unwrap();
        assert_eq!(e1.read().unwrap(), 0x0f0f);
    }

}
<|endoftext|>


<commit_before>extern crate sb;
use sb::options_parse::parse_options;
use sb::commands::command::Command;
use sb::commands::fetch_command::FetchCommand;
use sb::commands::find_command::FindCommand;
use sb::commands::make_command::MakeCommand;
use std::env::current_dir;
use std::path::{Path, PathBuf};

fn main() {
    let (app_path, options, mut arguments) = parse_options();

    let mut slice_root_directory = get_slice_root_directory(&app_path);
    if slice_root_directory.is_relative() {
        let mut new_slice_root_directory = current_dir().unwrap();
        new_slice_root_directory.push(slice_root_directory);
        slice_root_directory = new_slice_root_directory;
    }
    let slice_root_directory = &*slice_root_directory;

    assert!(arguments.len() != 0);
    let command = arguments.remove(0);
    let command: &str = &command;
    match command {
        "find" => {
            assert!(arguments.len() == 2);
            let os = arguments.remove(0);
            let layer = arguments.remove(0);
            run_command(FindCommand { layer: layer, os: os, slice_root_directory: slice_root_directory })
        },
        "fetch" => {
            run_command(FetchCommand { slice_root_directory: slice_root_directory })
        },
        "make" => {
            assert!(arguments.len() == 2);
            let os = arguments.remove(0);
            let layer = arguments.remove(0);
            run_command(MakeCommand { layer: layer, os: os, slice_root_directory: slice_root_directory })
        },
        _ => panic!()
    };
}

fn run_command<T>(mut command: T) where T : Command {
    command.run()
}

fn get_slice_root_directory(app_path: & String) -> PathBuf {
    let mut slice_root_directory = PathBuf::new();
    slice_root_directory.push(Path::new(&app_path).parent().unwrap());
    slice_root_directory.push(".sb");
    slice_root_directory.push("slices");
    slice_root_directory
}
<commit_msg>Fixed #4 #5<commit_after>extern crate sb;
use sb::options_parse::parse_options;
use sb::commands::command::Command;
use sb::commands::fetch_command::FetchCommand;
use sb::commands::find_command::FindCommand;
use sb::commands::make_command::MakeCommand;
use std::env::current_dir;
use std::path::{Path, PathBuf};

const DEFAULT_OS: &'static str = "debian";
const DEFAULT_LAYER: &'static str = "jekyll";

fn main() {
    let (app_path, options, mut arguments) = parse_options();

    let mut slice_root_directory = get_slice_root_directory(&app_path);
    if slice_root_directory.is_relative() {
        let mut new_slice_root_directory = current_dir().unwrap();
        new_slice_root_directory.push(slice_root_directory);
        slice_root_directory = new_slice_root_directory;
    }
    let slice_root_directory = &*slice_root_directory;

    assert!(arguments.len() != 0);
    let command = arguments.remove(0);
    let command: &str = &command;
    match command {
        "find" => {
            let os = get_os_from_arguments_or_default(&mut arguments);
            let layer = get_layer_from_arguments_or_default(&mut arguments);
            run_command(FindCommand { layer: layer, os: os, slice_root_directory: slice_root_directory })
        },
        "fetch" => {
            run_command(FetchCommand { slice_root_directory: slice_root_directory })
        },
        "make" => {
            let os = get_os_from_arguments_or_default(&mut arguments);
            let layer = get_layer_from_arguments_or_default(&mut arguments);
            run_command(MakeCommand { layer: layer, os: os, slice_root_directory: slice_root_directory })
        },
        _ => panic!()
    };
}

fn run_command<T>(mut command: T) where T : Command {
    command.run()
}

fn pop_first_argument_or_take_default(arguments: &mut Vec<String>, default_value: String) -> String {
    if arguments.len() == 0 {
        default_value
    } else {
        arguments.remove(0)
    }
}

fn get_os_from_arguments_or_default(arguments: &mut Vec<String>) -> String {
    pop_first_argument_or_take_default(arguments, DEFAULT_OS.to_string())
}

fn get_layer_from_arguments_or_default(arguments: &mut Vec<String>) -> String {
    pop_first_argument_or_take_default(arguments, DEFAULT_LAYER.to_string())
}

fn get_slice_root_directory(app_path: & String) -> PathBuf {
    let mut slice_root_directory = PathBuf::new();
    slice_root_directory.push(Path::new(&app_path).parent().unwrap());
    slice_root_directory.push(".sb");
    slice_root_directory.push("slices");
    slice_root_directory
}
<|endoftext|>


<commit_before>//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
//! Clippy.

use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::*;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol};

declare_tool_lint! {
    pub rustc::DEFAULT_HASH_TYPES,
    Allow,
    "forbid HashMap and HashSet and suggest the FxHash* variants",
    report_in_external_macro: true
}

declare_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);

impl LateLintPass<'_> for DefaultHashTypes {
    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
        let def_id = match path.res {
            Res::Def(rustc_hir::def::DefKind::Struct, id) => id,
            _ => return,
        };
        if matches!(cx.tcx.hir().get(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) {
            // don't lint imports, only actual usages
            return;
        }
        let replace = match cx.tcx.get_diagnostic_name(def_id) {
            Some(sym::HashMap) => "FxHashMap",
            Some(sym::HashSet) => "FxHashSet",
            _ => return,
        };
        cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
            let msg = format!(
                "prefer `{}` over `{}`, it has better performance",
                replace,
                cx.tcx.item_name(def_id)
            );
            lint.build(&msg)
                .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
                .emit();
        });
    }
}

declare_tool_lint! {
    pub rustc::POTENTIAL_QUERY_INSTABILITY,
    Allow,
    "require explicit opt-in when using potentially unstable methods or functions",
    report_in_external_macro: true
}

declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);

impl LateLintPass<'_> for QueryStability {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        let (def_id, span) = match expr.kind {
            ExprKind::Path(ref path) if let Some(def_id) = cx.qpath_res(path, expr.hir_id).opt_def_id() => {
                (def_id, expr.span)
            }
            ExprKind::MethodCall(_, span, _, _) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
                (def_id, span)
            },
            _ => return,
        };

        let substs = cx.typeck_results().node_substs(expr.hir_id);
        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
            let def_id = instance.def_id();
            if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
                    let msg = format!(
                        "using `{}` can result in unstable query results",
                        cx.tcx.item_name(def_id)
                    );
                    lint.build(&msg)
                        .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
                        .emit();
                })
            }
        }
    }
}

declare_tool_lint! {
    pub rustc::USAGE_OF_TY_TYKIND,
    Allow,
    "usage of `ty::TyKind` outside of the `ty::sty` module",
    report_in_external_macro: true
}

declare_tool_lint! {
    pub rustc::TY_PASS_BY_REFERENCE,
    Allow,
    "passing `Ty` or `TyCtxt` by reference",
    report_in_external_macro: true
}

declare_tool_lint! {
    pub rustc::USAGE_OF_QUALIFIED_TY,
    Allow,
    "using `ty::{Ty,TyCtxt}` instead of importing it",
    report_in_external_macro: true
}

declare_lint_pass!(TyTyKind => [
    USAGE_OF_TY_TYKIND,
    TY_PASS_BY_REFERENCE,
    USAGE_OF_QUALIFIED_TY,
]);

impl<'tcx> LateLintPass<'tcx> for TyTyKind {
    fn check_path(&mut self, cx: &LateContext<'_>, path: &'tcx Path<'tcx>, _: HirId) {
        let segments = path.segments.iter().rev().skip(1).rev();

        if let Some(last) = segments.last() {
            let span = path.span.with_hi(last.ident.span.hi());
            if lint_ty_kind_usage(cx, last) {
                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| {
                    lint.build("usage of `ty::TyKind::<kind>`")
                        .span_suggestion(
                            span,
                            "try using ty::<kind> directly",
                            "ty".to_string(),
                            Applicability::MaybeIncorrect, // ty maybe needs an import
                        )
                        .emit();
                })
            }
        }
    }

    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
        match &ty.kind {
            TyKind::Path(qpath) => {
                if let QPath::Resolved(_, path) = qpath {
                    if let Some(last) = path.segments.iter().last() {
                        if lint_ty_kind_usage(cx, last) {
                            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
                                lint.build("usage of `ty::TyKind`")
                                    .help("try using `Ty` instead")
                                    .emit();
                            })
                        } else {
                            if ty.span.from_expansion() {
                                return;
                            }
                            if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
                                if path.segments.len() > 1 {
                                    cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
                                        lint.build(&format!("usage of qualified `ty::{}`", t))
                                            .span_suggestion(
                                                path.span,
                                                "try using it unqualified",
                                                t,
                                                // The import probably needs to be changed
                                                Applicability::MaybeIncorrect,
                                            )
                                            .emit();
                                    })
                                }
                            }
                        }
                    }
                }
            }
            TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
                        return;
                    }
                }
                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
                    cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| {
                        lint.build(&format!("passing `{}` by reference", t))
                            .span_suggestion(
                                ty.span,
                                "try passing by value",
                                t,
                                // Changing type of function argument
                                Applicability::MaybeIncorrect,
                            )
                            .emit();
                    })
                }
            }
            _ => {}
        }
    }
}

fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool {
    if let Some(res) = segment.res {
        if let Some(did) = res.opt_def_id() {
            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
        }
    }

    false
}

fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
    if let TyKind::Path(qpath) = &ty.kind {
        if let QPath::Resolved(_, path) = qpath {
            match path.res {
                Res::Def(_, def_id) => {
                    if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
                    {
                        return Some(format!(
                            "{}{}",
                            name,
                            gen_args(path.segments.last().unwrap())
                        ));
                    }
                }
                // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
                Res::SelfTy(None, Some((did, _))) => {
                    if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                        if let Some(name @ (sym::Ty | sym::TyCtxt)) =
                            cx.tcx.get_diagnostic_name(adt.did)
                        {
                            // NOTE: This path is currently unreachable as `Ty<'tcx>` is
                            // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
                            // is not actually allowed.
                            //
                            // I(@lcnr) still kept this branch in so we don't miss this
                            // if we ever change it in the future.
                            return Some(format!("{}<{}>", name, substs[0]));
                        }
                    }
                }
                _ => (),
            }
        }
    }

    None
}

fn gen_args(segment: &PathSegment<'_>) -> String {
    if let Some(args) = &segment.args {
        let lifetimes = args
            .args
            .iter()
            .filter_map(|arg| {
                if let GenericArg::Lifetime(lt) = arg {
                    Some(lt.name.ident().to_string())
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        if !lifetimes.is_empty() {
            return format!("<{}>", lifetimes.join(", "));
        }
    }

    String::new()
}

declare_tool_lint! {
    pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
    Allow,
    "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
}

declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);

impl EarlyLintPass for LintPassImpl {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
        if let ast::ItemKind::Impl(box ast::ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind
        {
            if let Some(last) = lint_pass.path.segments.last() {
                if last.ident.name == sym::LintPass {
                    let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
                    let call_site = expn_data.call_site;
                    if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
                        && call_site.ctxt().outer_expn_data().kind
                            != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
                    {
                        cx.struct_span_lint(
                            LINT_PASS_IMPL_WITHOUT_MACRO,
                            lint_pass.path.span,
                            |lint| {
                                lint.build("implementing `LintPass` by hand")
                                    .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
                                    .emit();
                            },
                        )
                    }
                }
            }
        }
    }
}

declare_tool_lint! {
    pub rustc::EXISTING_DOC_KEYWORD,
    Allow,
    "Check that documented keywords in std and core actually exist",
    report_in_external_macro: true
}

declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]);

fn is_doc_keyword(s: Symbol) -> bool {
    s <= kw::Union
}

impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
    fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
        for attr in cx.tcx.hir().attrs(item.hir_id()) {
            if !attr.has_name(sym::doc) {
                continue;
            }
            if let Some(list) = attr.meta_item_list() {
                for nested in list {
                    if nested.has_name(sym::keyword) {
                        let v = nested
                            .value_str()
                            .expect("#[doc(keyword = \"...\")] expected a value!");
                        if is_doc_keyword(v) {
                            return;
                        }
                        cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
                            lint.build(&format!(
                                "Found non-existing keyword `{}` used in \
                                     `#[doc(keyword = \"...\")]`",
                                v,
                            ))
                            .help("only existing keywords are allowed in core/std")
                            .emit();
                        });
                    }
                }
            }
        }
    }
}
<commit_msg>ignore `potential_query_instability` in rustdoc<commit_after>//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
//! Clippy.

use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::*;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::symbol::{kw, sym, Symbol};

declare_tool_lint! {
    pub rustc::DEFAULT_HASH_TYPES,
    Allow,
    "forbid HashMap and HashSet and suggest the FxHash* variants",
    report_in_external_macro: true
}

declare_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);

impl LateLintPass<'_> for DefaultHashTypes {
    fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
        let def_id = match path.res {
            Res::Def(rustc_hir::def::DefKind::Struct, id) => id,
            _ => return,
        };
        if matches!(cx.tcx.hir().get(hir_id), Node::Item(Item { kind: ItemKind::Use(..), .. })) {
            // don't lint imports, only actual usages
            return;
        }
        let replace = match cx.tcx.get_diagnostic_name(def_id) {
            Some(sym::HashMap) => "FxHashMap",
            Some(sym::HashSet) => "FxHashSet",
            _ => return,
        };
        cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
            let msg = format!(
                "prefer `{}` over `{}`, it has better performance",
                replace,
                cx.tcx.item_name(def_id)
            );
            lint.build(&msg)
                .note(&format!("a `use rustc_data_structures::fx::{}` may be necessary", replace))
                .emit();
        });
    }
}

declare_tool_lint! {
    pub rustc::POTENTIAL_QUERY_INSTABILITY,
    Allow,
    "require explicit opt-in when using potentially unstable methods or functions",
    report_in_external_macro: true
}

declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY]);

impl LateLintPass<'_> for QueryStability {
    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
        // FIXME(rustdoc): This lint uses typecheck results, causing rustdoc to
        // error if there are resolution failures.
        //
        // As internal lints are currently always run if there are `unstable_options`,
        // they are added to the lint store of rustdoc. Internal lints are also
        // not used via the `lint_mod` query. Crate lints run outside of a query
        // so rustdoc currently doesn't disable them.
        //
        // Instead of relying on this, either change crate lints to a query disabled by
        // rustdoc, only run internal lints if the user is explicitly opting in
        // or figure out a different way to avoid running lints for rustdoc.
        if cx.tcx.sess.opts.actually_rustdoc {
            return;
        }

        let (def_id, span) = match expr.kind {
            ExprKind::Path(ref path) if let Some(def_id) = cx.qpath_res(path, expr.hir_id).opt_def_id() => {
                (def_id, expr.span)
            }
            ExprKind::MethodCall(_, span, _, _) if let Some(def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
                (def_id, span)
            },
            _ => return,
        };

        let substs = cx.typeck_results().node_substs(expr.hir_id);
        if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
            let def_id = instance.def_id();
            if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
                cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
                    let msg = format!(
                        "using `{}` can result in unstable query results",
                        cx.tcx.item_name(def_id)
                    );
                    lint.build(&msg)
                        .note("if you believe this case to be fine, allow this lint and add a comment explaining your rationale")
                        .emit();
                })
            }
        }
    }
}

declare_tool_lint! {
    pub rustc::USAGE_OF_TY_TYKIND,
    Allow,
    "usage of `ty::TyKind` outside of the `ty::sty` module",
    report_in_external_macro: true
}

declare_tool_lint! {
    pub rustc::TY_PASS_BY_REFERENCE,
    Allow,
    "passing `Ty` or `TyCtxt` by reference",
    report_in_external_macro: true
}

declare_tool_lint! {
    pub rustc::USAGE_OF_QUALIFIED_TY,
    Allow,
    "using `ty::{Ty,TyCtxt}` instead of importing it",
    report_in_external_macro: true
}

declare_lint_pass!(TyTyKind => [
    USAGE_OF_TY_TYKIND,
    TY_PASS_BY_REFERENCE,
    USAGE_OF_QUALIFIED_TY,
]);

impl<'tcx> LateLintPass<'tcx> for TyTyKind {
    fn check_path(&mut self, cx: &LateContext<'_>, path: &'tcx Path<'tcx>, _: HirId) {
        let segments = path.segments.iter().rev().skip(1).rev();

        if let Some(last) = segments.last() {
            let span = path.span.with_hi(last.ident.span.hi());
            if lint_ty_kind_usage(cx, last) {
                cx.struct_span_lint(USAGE_OF_TY_TYKIND, span, |lint| {
                    lint.build("usage of `ty::TyKind::<kind>`")
                        .span_suggestion(
                            span,
                            "try using ty::<kind> directly",
                            "ty".to_string(),
                            Applicability::MaybeIncorrect, // ty maybe needs an import
                        )
                        .emit();
                })
            }
        }
    }

    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
        match &ty.kind {
            TyKind::Path(qpath) => {
                if let QPath::Resolved(_, path) = qpath {
                    if let Some(last) = path.segments.iter().last() {
                        if lint_ty_kind_usage(cx, last) {
                            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
                                lint.build("usage of `ty::TyKind`")
                                    .help("try using `Ty` instead")
                                    .emit();
                            })
                        } else {
                            if ty.span.from_expansion() {
                                return;
                            }
                            if let Some(t) = is_ty_or_ty_ctxt(cx, ty) {
                                if path.segments.len() > 1 {
                                    cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
                                        lint.build(&format!("usage of qualified `ty::{}`", t))
                                            .span_suggestion(
                                                path.span,
                                                "try using it unqualified",
                                                t,
                                                // The import probably needs to be changed
                                                Applicability::MaybeIncorrect,
                                            )
                                            .emit();
                                    })
                                }
                            }
                        }
                    }
                }
            }
            TyKind::Rptr(_, MutTy { ty: inner_ty, mutbl: Mutability::Not }) => {
                if let Some(impl_did) = cx.tcx.impl_of_method(ty.hir_id.owner.to_def_id()) {
                    if cx.tcx.impl_trait_ref(impl_did).is_some() {
                        return;
                    }
                }
                if let Some(t) = is_ty_or_ty_ctxt(cx, &inner_ty) {
                    cx.struct_span_lint(TY_PASS_BY_REFERENCE, ty.span, |lint| {
                        lint.build(&format!("passing `{}` by reference", t))
                            .span_suggestion(
                                ty.span,
                                "try passing by value",
                                t,
                                // Changing type of function argument
                                Applicability::MaybeIncorrect,
                            )
                            .emit();
                    })
                }
            }
            _ => {}
        }
    }
}

fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool {
    if let Some(res) = segment.res {
        if let Some(did) = res.opt_def_id() {
            return cx.tcx.is_diagnostic_item(sym::TyKind, did);
        }
    }

    false
}

fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option<String> {
    if let TyKind::Path(qpath) = &ty.kind {
        if let QPath::Resolved(_, path) = qpath {
            match path.res {
                Res::Def(_, def_id) => {
                    if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id)
                    {
                        return Some(format!(
                            "{}{}",
                            name,
                            gen_args(path.segments.last().unwrap())
                        ));
                    }
                }
                // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
                Res::SelfTy(None, Some((did, _))) => {
                    if let ty::Adt(adt, substs) = cx.tcx.type_of(did).kind() {
                        if let Some(name @ (sym::Ty | sym::TyCtxt)) =
                            cx.tcx.get_diagnostic_name(adt.did)
                        {
                            // NOTE: This path is currently unreachable as `Ty<'tcx>` is
                            // defined as a type alias meaning that `impl<'tcx> Ty<'tcx>`
                            // is not actually allowed.
                            //
                            // I(@lcnr) still kept this branch in so we don't miss this
                            // if we ever change it in the future.
                            return Some(format!("{}<{}>", name, substs[0]));
                        }
                    }
                }
                _ => (),
            }
        }
    }

    None
}

fn gen_args(segment: &PathSegment<'_>) -> String {
    if let Some(args) = &segment.args {
        let lifetimes = args
            .args
            .iter()
            .filter_map(|arg| {
                if let GenericArg::Lifetime(lt) = arg {
                    Some(lt.name.ident().to_string())
                } else {
                    None
                }
            })
            .collect::<Vec<_>>();

        if !lifetimes.is_empty() {
            return format!("<{}>", lifetimes.join(", "));
        }
    }

    String::new()
}

declare_tool_lint! {
    pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
    Allow,
    "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
}

declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);

impl EarlyLintPass for LintPassImpl {
    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
        if let ast::ItemKind::Impl(box ast::ImplKind { of_trait: Some(lint_pass), .. }) = &item.kind
        {
            if let Some(last) = lint_pass.path.segments.last() {
                if last.ident.name == sym::LintPass {
                    let expn_data = lint_pass.path.span.ctxt().outer_expn_data();
                    let call_site = expn_data.call_site;
                    if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
                        && call_site.ctxt().outer_expn_data().kind
                            != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
                    {
                        cx.struct_span_lint(
                            LINT_PASS_IMPL_WITHOUT_MACRO,
                            lint_pass.path.span,
                            |lint| {
                                lint.build("implementing `LintPass` by hand")
                                    .help("try using `declare_lint_pass!` or `impl_lint_pass!` instead")
                                    .emit();
                            },
                        )
                    }
                }
            }
        }
    }
}

declare_tool_lint! {
    pub rustc::EXISTING_DOC_KEYWORD,
    Allow,
    "Check that documented keywords in std and core actually exist",
    report_in_external_macro: true
}

declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]);

fn is_doc_keyword(s: Symbol) -> bool {
    s <= kw::Union
}

impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
    fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
        for attr in cx.tcx.hir().attrs(item.hir_id()) {
            if !attr.has_name(sym::doc) {
                continue;
            }
            if let Some(list) = attr.meta_item_list() {
                for nested in list {
                    if nested.has_name(sym::keyword) {
                        let v = nested
                            .value_str()
                            .expect("#[doc(keyword = \"...\")] expected a value!");
                        if is_doc_keyword(v) {
                            return;
                        }
                        cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
                            lint.build(&format!(
                                "Found non-existing keyword `{}` used in \
                                     `#[doc(keyword = \"...\")]`",
                                v,
                            ))
                            .help("only existing keywords are allowed in core/std")
                            .emit();
                        });
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::ffi::CStr;
use std::fs::File;
use std::rc::Rc;

use anyhow::anyhow;
use anyhow::Context as AnyhowContext;
use anyhow::Result;
use base::AsRawDescriptor;

use crate::bindings;
use crate::config::Config;
use crate::context::Context;
use crate::status::Status;
use crate::surface::Surface;
use crate::UsageHint;

/// An owned VADisplay
pub struct Display {
    /// The handle to interact with the underlying VADisplay.
    handle: bindings::VADisplay,
    /// The DRM file that must be kept open while the VADisplay is in use.
    #[allow(dead_code)]
    drm_file: File,
}

impl Display {
    /// Opens and initializes an owned Display
    pub fn open() -> Result<Self> {
        let (display, drm_file) = match Display::drm_open()? {
            Some(x) => x,
            None => return Err(anyhow!("Couldn't open a suitable DRM file descriptor")),
        };

        let mut major = 0i32;
        let mut minor = 0i32;
        // Safe because we ensure that the display is valid (i.e not NULL)
        // before calling vaInitialize
        let result =
            Status(unsafe { bindings::vaInitialize(display, &mut major, &mut minor) }).check();

        if let Err(error) = result {
            // The File will close the DRM fd on drop.
            return Err(error);
        }

        Ok(Self {
            handle: display,
            drm_file,
        })
    }

    fn drm_open() -> Result<Option<(bindings::VADisplay, File)>> {
        let udev_context = libudev::Context::new()?;
        let mut enumerator = libudev::Enumerator::new(&udev_context)?;

        enumerator
            .match_subsystem("drm")
            .context("udev error when matching DRM devices")?;

        for device in enumerator.scan_devices()? {
            let path = device
                .devnode()
                .and_then(|f| f.file_name())
                .and_then(|f| f.to_str());

            match path {
                Some(name) => {
                    if !name.contains("renderD") {
                        continue;
                    }
                }
                None => continue,
            }

            let file = std::fs::File::open(device.devnode().unwrap())?;
            let fd = file.as_raw_descriptor();

            // Safe because fd represents a valid file descriptor and
            // the pointer is checked for NULL afterwards.
            let display = unsafe { bindings::vaGetDisplayDRM(fd) };

            if display.is_null() {
                // The File will close the DRM fd on drop.
                return Err(anyhow!("va_open_display() failed"));
            }

            return Ok(Some((display, file)));
        }

        Ok(None)
    }

    /// Returns the associated handle
    pub(crate) fn handle(&self) -> bindings::VADisplay {
        self.handle
    }

    /// Queries supported profiles
    pub fn query_config_profiles(&self) -> Result<Vec<bindings::VAProfile::Type>> {
        // Safe because `self` represents a valid VADisplay.
        let mut max_num_profiles = unsafe { bindings::vaMaxNumProfiles(self.handle) };
        let mut profiles = Vec::with_capacity(max_num_profiles as usize);

        // Safe because `self` represents a valid VADisplay and the vector has
        // "max_num_profiles" as capacity.
        Status(unsafe {
            bindings::vaQueryConfigProfiles(
                self.handle,
                profiles.as_mut_ptr(),
                &mut max_num_profiles,
            )
        })
        .check()?;

        // Safe because "profiles" is allocated with a "max_num_profiles"
        // capacity. Additionally, vaQueryConfigProfiles will write to
        // "max_num_entrypoints" entries in the vector.
        unsafe {
            profiles.set_len(max_num_profiles as usize);
        };

        Ok(profiles)
    }

    /// Returns a String describing some aspects of the VA implemenation on a
    /// specific hardware accelerator. The format of the returned string is
    /// vendor specific and at the discretion of the implementer. e.g. for the
    /// Intel GMA500 implementation, an example would be: "Intel GMA500 -
    /// 2.0.0.32L.0005"
    pub fn query_vendor_string(&self) -> std::result::Result<String, &'static str> {
        // Safe because `self` represents a valid VADisplay.
        let vendor_string = unsafe { bindings::vaQueryVendorString(self.handle) };

        if vendor_string.is_null() {
            return Err("vaQueryVendorString() returned NULL");
        }

        // Safe because we check the whether the vendor_String pointer is NULL
        Ok(unsafe { CStr::from_ptr(vendor_string) }
            .to_string_lossy()
            .to_string())
    }

    /// Query supported entrypoints for a given profile
    pub fn query_config_entrypoints(
        &self,
        profile: bindings::VAProfile::Type,
    ) -> Result<Vec<bindings::VAEntrypoint::Type>> {
        // Safe because `self` represents a valid VADisplay.
        let mut max_num_entrypoints = unsafe { bindings::vaMaxNumEntrypoints(self.handle) };
        let mut entrypoints = Vec::with_capacity(max_num_entrypoints as usize);

        // Safe because `self` represents a valid VADisplay and the vector has
        // "max_num_entrypoints" as capacity.
        Status(unsafe {
            bindings::vaQueryConfigEntrypoints(
                self.handle,
                profile,
                entrypoints.as_mut_ptr(),
                &mut max_num_entrypoints,
            )
        })
        .check()?;

        // Safe because "entrypoints" is allocated with a
        // "max_num_entrypoints" capacity. Safe because
        // vaQueryConfigEntrypoints will write to "max_num_entrypoints"
        // entries in the vector.
        unsafe {
            entrypoints.set_len(max_num_entrypoints as usize);
        }

        Ok(entrypoints)
    }

    /// Get attributes for a given profile/entrypoint pair
    pub fn get_config_attributes(
        &self,
        profile: bindings::VAProfile::Type,
        entrypoint: bindings::VAEntrypoint::Type,
        attributes: &mut [bindings::VAConfigAttrib],
    ) -> Result<()> {
        // Safe because `self` represents a valid VADisplay. The slice length
        // is passed to the C function, so it is impossible to write past the
        // end of the slice's storage by mistake.
        Status(unsafe {
            bindings::vaGetConfigAttributes(
                self.handle,
                profile,
                entrypoint,
                attributes.as_mut_ptr(),
                attributes.len() as i32,
            )
        })
        .check()
    }

    /// Create VASurfaces by wrapping around a vaCreateSurfaces call
    ///  `rt_format` is the desired surface format. See VA_RT_FORMAT_*
    ///  `va_fourcc` is the desired pixel format. See VA_FOURCC_*
    ///  `width` is the surface width
    ///  `height` is the surface height
    ///  `usage_hint` gives the driver a hint of intended usage to optimize allocation (e.g. tiling)
    ///  `num_surfaces` is the number of surfaces to create
    pub fn create_surfaces(
        self: &Rc<Self>,
        rt_format: u32,
        va_fourcc: Option<u32>,
        width: u32,
        height: u32,
        usage_hint: Option<UsageHint>,
        num_surfaces: u32,
    ) -> Result<Vec<Surface>> {
        Surface::new(
            Rc::clone(self),
            rt_format,
            va_fourcc,
            width,
            height,
            usage_hint,
            num_surfaces,
        )
    }

    /// Create a Context by wrapping around a vaCreateContext call.
    ///  `config` is the configuration for the context
    ///  `coded_width` is the coded picture width
    ///  `coded_height` is the coded picture height
    ///  `progressive` is whether only progressive frame pictures are present in the sequence
    ///  `surfaces` are a hint for the amount of surfaces tied to the context
    pub fn create_context(
        self: &Rc<Self>,
        config: &Config,
        coded_width: i32,
        coded_height: i32,
        surfaces: Option<&Vec<Surface>>,
        progressive: bool,
    ) -> Result<Context> {
        Context::new(
            Rc::clone(self),
            config,
            coded_width,
            coded_height,
            surfaces,
            progressive,
        )
    }

    /// Create a VAConfig by wrapping around the vaCreateConfig call. `attrs`
    /// describe the attributes to set for this config. A list of the supported
    /// attributes for a given profile/entrypoint pair can be retrieved using
    /// Display::get_config_attributes. Other attributes will take their default
    /// values
    pub fn create_config(
        self: &Rc<Self>,
        attrs: Option<Vec<bindings::VAConfigAttrib>>,
        profile: bindings::VAProfile::Type,
        entrypoint: bindings::VAEntrypoint::Type,
    ) -> Result<Config> {
        Config::new(Rc::clone(self), attrs, profile, entrypoint)
    }

    /// A wrapper over vaQueryImageFormats.
    pub fn query_image_formats(self: &Rc<Self>) -> Result<Vec<bindings::VAImageFormat>> {
        // Safe because `self` represents a valid VADisplay
        let mut num_image_formats = unsafe { bindings::vaMaxNumImageFormats(self.handle) };
        let mut image_formats = Vec::with_capacity(num_image_formats as usize);

        // Safe because `self` represents a valid VADisplay. The "image_formats"
        // vector is properly initialized and a valid size is passed to the C
        // function, so it is impossible to write past the end of their storage
        // by mistake
        Status(unsafe {
            bindings::vaQueryImageFormats(
                self.handle,
                image_formats.as_mut_ptr(),
                &mut num_image_formats,
            )
        })
        .check()?;

        // Safe because the C function will have writter to exactly
        // "num_image_format" entries, which is known to be within the vector's
        // capacity.
        unsafe {
            image_formats.set_len(num_image_formats as usize);
        }

        Ok(image_formats)
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        // Safe because `self` represents a valid VADisplay.
        unsafe {
            bindings::vaTerminate(self.handle);
            // The File will close the DRM fd on drop.
        }
    }
}
<commit_msg>media: libva: open DRM fd as O_RDWR<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::ffi::CStr;
use std::fs::File;
use std::rc::Rc;

use anyhow::anyhow;
use anyhow::Context as AnyhowContext;
use anyhow::Result;
use base::AsRawDescriptor;

use crate::bindings;
use crate::config::Config;
use crate::context::Context;
use crate::status::Status;
use crate::surface::Surface;
use crate::UsageHint;

/// An owned VADisplay
pub struct Display {
    /// The handle to interact with the underlying VADisplay.
    handle: bindings::VADisplay,
    /// The DRM file that must be kept open while the VADisplay is in use.
    #[allow(dead_code)]
    drm_file: File,
}

impl Display {
    /// Opens and initializes an owned Display
    pub fn open() -> Result<Self> {
        let (display, drm_file) = match Display::drm_open()? {
            Some(x) => x,
            None => return Err(anyhow!("Couldn't open a suitable DRM file descriptor")),
        };

        let mut major = 0i32;
        let mut minor = 0i32;
        // Safe because we ensure that the display is valid (i.e not NULL)
        // before calling vaInitialize
        let result =
            Status(unsafe { bindings::vaInitialize(display, &mut major, &mut minor) }).check();

        if let Err(error) = result {
            // The File will close the DRM fd on drop.
            return Err(error);
        }

        Ok(Self {
            handle: display,
            drm_file,
        })
    }

    fn drm_open() -> Result<Option<(bindings::VADisplay, File)>> {
        let udev_context = libudev::Context::new()?;
        let mut enumerator = libudev::Enumerator::new(&udev_context)?;

        enumerator
            .match_subsystem("drm")
            .context("udev error when matching DRM devices")?;

        for device in enumerator.scan_devices()? {
            let path = device
                .devnode()
                .and_then(|f| f.file_name())
                .and_then(|f| f.to_str());

            match path {
                Some(name) => {
                    if !name.contains("renderD") {
                        continue;
                    }
                }
                None => continue,
            }

            let file = std::fs::File::options()
                .read(true)
                .write(true)
                .open(device.devnode().unwrap())?;
            let fd = file.as_raw_descriptor();

            // Safe because fd represents a valid file descriptor and
            // the pointer is checked for NULL afterwards.
            let display = unsafe { bindings::vaGetDisplayDRM(fd) };

            if display.is_null() {
                // The File will close the DRM fd on drop.
                return Err(anyhow!("va_open_display() failed"));
            }

            return Ok(Some((display, file)));
        }

        Ok(None)
    }

    /// Returns the associated handle
    pub(crate) fn handle(&self) -> bindings::VADisplay {
        self.handle
    }

    /// Queries supported profiles
    pub fn query_config_profiles(&self) -> Result<Vec<bindings::VAProfile::Type>> {
        // Safe because `self` represents a valid VADisplay.
        let mut max_num_profiles = unsafe { bindings::vaMaxNumProfiles(self.handle) };
        let mut profiles = Vec::with_capacity(max_num_profiles as usize);

        // Safe because `self` represents a valid VADisplay and the vector has
        // "max_num_profiles" as capacity.
        Status(unsafe {
            bindings::vaQueryConfigProfiles(
                self.handle,
                profiles.as_mut_ptr(),
                &mut max_num_profiles,
            )
        })
        .check()?;

        // Safe because "profiles" is allocated with a "max_num_profiles"
        // capacity. Additionally, vaQueryConfigProfiles will write to
        // "max_num_entrypoints" entries in the vector.
        unsafe {
            profiles.set_len(max_num_profiles as usize);
        };

        Ok(profiles)
    }

    /// Returns a String describing some aspects of the VA implemenation on a
    /// specific hardware accelerator. The format of the returned string is
    /// vendor specific and at the discretion of the implementer. e.g. for the
    /// Intel GMA500 implementation, an example would be: "Intel GMA500 -
    /// 2.0.0.32L.0005"
    pub fn query_vendor_string(&self) -> std::result::Result<String, &'static str> {
        // Safe because `self` represents a valid VADisplay.
        let vendor_string = unsafe { bindings::vaQueryVendorString(self.handle) };

        if vendor_string.is_null() {
            return Err("vaQueryVendorString() returned NULL");
        }

        // Safe because we check the whether the vendor_String pointer is NULL
        Ok(unsafe { CStr::from_ptr(vendor_string) }
            .to_string_lossy()
            .to_string())
    }

    /// Query supported entrypoints for a given profile
    pub fn query_config_entrypoints(
        &self,
        profile: bindings::VAProfile::Type,
    ) -> Result<Vec<bindings::VAEntrypoint::Type>> {
        // Safe because `self` represents a valid VADisplay.
        let mut max_num_entrypoints = unsafe { bindings::vaMaxNumEntrypoints(self.handle) };
        let mut entrypoints = Vec::with_capacity(max_num_entrypoints as usize);

        // Safe because `self` represents a valid VADisplay and the vector has
        // "max_num_entrypoints" as capacity.
        Status(unsafe {
            bindings::vaQueryConfigEntrypoints(
                self.handle,
                profile,
                entrypoints.as_mut_ptr(),
                &mut max_num_entrypoints,
            )
        })
        .check()?;

        // Safe because "entrypoints" is allocated with a
        // "max_num_entrypoints" capacity. Safe because
        // vaQueryConfigEntrypoints will write to "max_num_entrypoints"
        // entries in the vector.
        unsafe {
            entrypoints.set_len(max_num_entrypoints as usize);
        }

        Ok(entrypoints)
    }

    /// Get attributes for a given profile/entrypoint pair
    pub fn get_config_attributes(
        &self,
        profile: bindings::VAProfile::Type,
        entrypoint: bindings::VAEntrypoint::Type,
        attributes: &mut [bindings::VAConfigAttrib],
    ) -> Result<()> {
        // Safe because `self` represents a valid VADisplay. The slice length
        // is passed to the C function, so it is impossible to write past the
        // end of the slice's storage by mistake.
        Status(unsafe {
            bindings::vaGetConfigAttributes(
                self.handle,
                profile,
                entrypoint,
                attributes.as_mut_ptr(),
                attributes.len() as i32,
            )
        })
        .check()
    }

    /// Create VASurfaces by wrapping around a vaCreateSurfaces call
    ///  `rt_format` is the desired surface format. See VA_RT_FORMAT_*
    ///  `va_fourcc` is the desired pixel format. See VA_FOURCC_*
    ///  `width` is the surface width
    ///  `height` is the surface height
    ///  `usage_hint` gives the driver a hint of intended usage to optimize allocation (e.g. tiling)
    ///  `num_surfaces` is the number of surfaces to create
    pub fn create_surfaces(
        self: &Rc<Self>,
        rt_format: u32,
        va_fourcc: Option<u32>,
        width: u32,
        height: u32,
        usage_hint: Option<UsageHint>,
        num_surfaces: u32,
    ) -> Result<Vec<Surface>> {
        Surface::new(
            Rc::clone(self),
            rt_format,
            va_fourcc,
            width,
            height,
            usage_hint,
            num_surfaces,
        )
    }

    /// Create a Context by wrapping around a vaCreateContext call.
    ///  `config` is the configuration for the context
    ///  `coded_width` is the coded picture width
    ///  `coded_height` is the coded picture height
    ///  `progressive` is whether only progressive frame pictures are present in the sequence
    ///  `surfaces` are a hint for the amount of surfaces tied to the context
    pub fn create_context(
        self: &Rc<Self>,
        config: &Config,
        coded_width: i32,
        coded_height: i32,
        surfaces: Option<&Vec<Surface>>,
        progressive: bool,
    ) -> Result<Context> {
        Context::new(
            Rc::clone(self),
            config,
            coded_width,
            coded_height,
            surfaces,
            progressive,
        )
    }

    /// Create a VAConfig by wrapping around the vaCreateConfig call. `attrs`
    /// describe the attributes to set for this config. A list of the supported
    /// attributes for a given profile/entrypoint pair can be retrieved using
    /// Display::get_config_attributes. Other attributes will take their default
    /// values
    pub fn create_config(
        self: &Rc<Self>,
        attrs: Option<Vec<bindings::VAConfigAttrib>>,
        profile: bindings::VAProfile::Type,
        entrypoint: bindings::VAEntrypoint::Type,
    ) -> Result<Config> {
        Config::new(Rc::clone(self), attrs, profile, entrypoint)
    }

    /// A wrapper over vaQueryImageFormats.
    pub fn query_image_formats(self: &Rc<Self>) -> Result<Vec<bindings::VAImageFormat>> {
        // Safe because `self` represents a valid VADisplay
        let mut num_image_formats = unsafe { bindings::vaMaxNumImageFormats(self.handle) };
        let mut image_formats = Vec::with_capacity(num_image_formats as usize);

        // Safe because `self` represents a valid VADisplay. The "image_formats"
        // vector is properly initialized and a valid size is passed to the C
        // function, so it is impossible to write past the end of their storage
        // by mistake
        Status(unsafe {
            bindings::vaQueryImageFormats(
                self.handle,
                image_formats.as_mut_ptr(),
                &mut num_image_formats,
            )
        })
        .check()?;

        // Safe because the C function will have writter to exactly
        // "num_image_format" entries, which is known to be within the vector's
        // capacity.
        unsafe {
            image_formats.set_len(num_image_formats as usize);
        }

        Ok(image_formats)
    }
}

impl Drop for Display {
    fn drop(&mut self) {
        // Safe because `self` represents a valid VADisplay.
        unsafe {
            bindings::vaTerminate(self.handle);
            // The File will close the DRM fd on drop.
        }
    }
}
<|endoftext|>


<commit_before>
use num::*;
use mat::Mat4;
use vec::Vec3;
use std::ops::*;

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Quaternion<T: Num + Float + Copy> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Num + Float + Copy> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::new()
    }
}

impl<T: Num + Float + Copy> Quaternion<T> {
    /// Creates a new identity quaternion
    pub fn new() -> Quaternion<T> {
        Quaternion {
            x: T::zero(),
            y: T::zero(),
            z: T::zero(),
            w: T::one(),
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::one() + T::one());
        let (sin, cos) = angle.sin_cos();
        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        let unit = Vec3::new(T::one(), T::zero(), T::zero()); // Any unit vector would work
        let a_dir = a*unit;
        let b_dir = b*unit;

        Vec3::dot(a_dir, b_dir).acos()
    }
}

// Quaternion vector multiplication
impl<T: Num + Float + Copy> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::one();
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Num + Float + Copy> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion scalar multiplication
impl<T: Num + Float + Copy> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Num + Float + Copy> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Num + Float + Copy> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Num + Float + Copy> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::new();
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }
}
<commit_msg>Quaternion dot product and lerp<commit_after>
use num::*;
use mat::Mat4;
use vec::Vec3;
use std::ops::*;

#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Quaternion<T: Num + Float + Copy> {
    pub x: T,
    pub y: T,
    pub w: T,
    pub z: T,
}

impl<T: Num + Float + Copy> Default for Quaternion<T> {
    fn default() -> Quaternion<T> {
        Quaternion::new()
    }
}

impl<T: Num + Float + Copy> Quaternion<T> {
    /// Creates a new identity quaternion
    pub fn new() -> Quaternion<T> {
        Quaternion {
            x: T::zero(),
            y: T::zero(),
            z: T::zero(),
            w: T::one(),
        }
    }

    /// Creates a quaternion representing a counterclockwise rotation of `angle` radians around the
    /// given axis. This function normalizes the axis, but if the axis is `(0, 0, 0)` the quaternion
    /// will have its `x`, `y` and `z` fields set to 0.
    pub fn rotation(angle: T, axis: Vec3<T>) -> Quaternion<T> {
        let axis = axis.normalize();
        let angle = angle / (T::one() + T::one());
        let (sin, cos) = angle.sin_cos();
        Quaternion {
            x: axis.x*sin,
            y: axis.y*sin,
            z: axis.z*sin,
            w: cos,
        }
    }

    /// Calculates the length of this quaternion, raised to the power of two. Note that this is
    /// cheaper than computing the actual length.
    pub fn len_sqr(&self) -> T {
        self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w
    }

    /// Calculates the length of this quaternion.
    pub fn len(&self) -> T {
        (self.x*self.x + self.y*self.y + self.z*self.z + self.w*self.w).sqrt()
    }

    /// Normalizes this quaternion, returning a new quaternion with length 1.
    pub fn normalize(&self) -> Quaternion<T> {
        *self / self.len()
    }

    /// Calculates the dot (inner) product of the two given quaternions.
    pub fn dot(a: Quaternion<T>, b: Quaternion<T>) -> T {
        a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w
    }

    /// Calculates the angle between the two given quaternions
    pub fn angle_between(a: Quaternion<T>, b: Quaternion<T>) -> T {
        Quaternion::dot(a, b).acos()
    }

    /// Interpolates linearly between the two given quaternions. This works well as long as the
    /// quaternions are not to different. `t` should be in the range `0..1`.
    ///
    /// nlerp stands for normalized linear interpolation.
    pub fn nlerp(a: Quaternion<T>, b: Quaternion<T>, t: T) -> Quaternion<T> {
        (a*(T::one() - t) + b*t).normalize()
    }
}

// Quaternion vector multiplication
impl<T: Num + Float + Copy> Mul<Vec3<T>> for Quaternion<T> {
    type Output = Vec3<T>;
    fn mul(self, vec: Vec3<T>) -> Vec3<T> {
        let one = T::one();
        let two = one + one;

        let a11 = one - two*self.y*self.y - two*self.z*self.z;
        let a12 = two*self.x*self.y - two*self.z*self.w;
        let a13 = two*self.x*self.z + two*self.y*self.w;

        let a21 = two*self.x*self.y + two*self.w*self.z;
        let a22 = one - two*self.x*self.x - two*self.z*self.z;
        let a23 = two*self.y*self.z - two*self.w*self.x;

        let a31 = two*self.x*self.z - two*self.w*self.y;
        let a32 = two*self.y*self.z + two*self.w*self.x;
        let a33 = one - two*self.x*self.x - two*self.y*self.y;

        Vec3 {
            x: vec.x*a11 + vec.y*a12 + vec.z*a13,
            y: vec.x*a21 + vec.y*a22 + vec.z*a23,
            z: vec.x*a31 + vec.y*a32 + vec.z*a33,
        }
    }
}

// Quaternion quaternion multiplication
impl<T: Num + Float + Copy> Mul for Quaternion<T> {
    type Output = Self;
    fn mul(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y,
            y: self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z,
            z: self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x,
            w: self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign for Quaternion<T> {
    fn mul_assign(&mut self, other: Quaternion<T>) {
        let x = self.w*other.x + self.x*other.w + self.y*other.z - self.z*other.y;
        let y = self.w*other.y + self.y*other.w + self.z*other.x - self.x*other.z;
        let z = self.w*other.z + self.z*other.w + self.x*other.y - self.y*other.x;
        let w = self.w*other.w - self.x*other.x - self.y*other.y - self.z*other.z;
        self.x = x;
        self.y = y;
        self.z = z;
        self.w = w;
    }
}

// Quaternion quaternion addition
impl<T: Num + Float + Copy> Add for Quaternion<T> {
    type Output = Self;
    fn add(self, other: Quaternion<T>) -> Self {
        Quaternion {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
            w: self.w + other.w,
        }
    }
}

// Quaternion scalar multiplication
impl<T: Num + Float + Copy> Mul<T> for Quaternion<T> {
    type Output = Self;
    fn mul(self, scalar: T) -> Self {
        Quaternion {
            x: self.x * scalar,
            y: self.y * scalar,
            z: self.z * scalar,
            w: self.w * scalar,
        }
    }
}
impl<T: Num + Float + Copy> MulAssign<T> for Quaternion<T> {
    fn mul_assign(&mut self, scalar: T) {
        self.x = self.x * scalar;
        self.y = self.y * scalar;
        self.z = self.z * scalar;
        self.w = self.w * scalar;
    }
}
impl<T: Num + Float + Copy> Div<T> for Quaternion<T> {
    type Output = Self;
    fn div(self, scalar: T) -> Self {
        Quaternion {
            x: self.x / scalar,
            y: self.y / scalar,
            z: self.z / scalar,
            w: self.w / scalar,
        }
    }
}
impl<T: Num + Float + Copy> DivAssign<T> for Quaternion<T> {
    fn div_assign(&mut self, scalar: T) {
        self.x = self.x / scalar;
        self.y = self.y / scalar;
        self.z = self.z / scalar;
        self.w = self.w / scalar;
    }
}

impl<T: Num + Float + Copy> From<Quaternion<T>> for Mat4<T> {
    fn from(quat: Quaternion<T>) -> Mat4<T> {
        Mat4::from_quaternion(quat.x, quat.y, quat.z, quat.w)
    }
}

#[cfg(test)]
mod tests {
    use std::f32;
    use super::*;
    use {Mat4, Vec4};

    #[test]
    fn identity() {
        let identity = Quaternion::<f32>::new();
        assert_eq!(identity, identity*identity);
        assert_eq!(identity, identity*identity*identity);
    }

    #[test]
    fn matrix_rotation() {
        let quat = Quaternion::<f32>::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0));
        let mat: Mat4<f32> = quat.into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);
        let b = Vec4::new(0.0, 0.0, 1.0, 1.0);

        let diff = (mat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn matrix_rotation_reverse() {
        let mat_a: Mat4<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let mat_b: Mat4<f32> = Quaternion::rotation(-f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec4::new(0.0, 1.0, 0.0, 1.0);

        let diff = (mat_a*mat_b*a - a).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn quaternion_rotation() {
        let quat: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();

        let a = Vec3::new(0.0, 1.0, 0.0);
        let b = Vec3::new(0.0, 0.0, 1.0);

        let diff = (quat*a - b).len();
        assert!(diff < 0.001);
    }

    #[test]
    fn angle_between() {
        let a: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b: Quaternion<f32> = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(0.0, 1.0, 0.0)).into();

        let diff = Quaternion::angle_between(a, b) - f32::consts::PI/2.0;
        assert!(diff < 0.001);
    }

    #[test]
    fn nlerp() {
        let a = Quaternion::rotation(f32::consts::PI/2.0, Vec3::new(1.0, 0.0, 0.0)).into();
        let b = Quaternion::new();

        let c = Quaternion::nlerp(a, b, 0.5);
        let expected = Quaternion::rotation(f32::consts::PI/4.0, Vec3::new(1.0, 0.0, 0.0));

        let diff = Quaternion::angle_between(c, expected);
        assert!(diff < 0.001);
    }
}
<|endoftext|>