<commit_before>// Copyright 2021 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::os::unix::net::UnixListener;
use std::rc::Rc;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{warn, Event, UnlinkUnixListener};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor};
use data_model::DataInit;
use futures::channel::mpsc;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use once_cell::sync::OnceCell;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::snd::cras_backend::{
    async_funcs::{handle_ctrl_queue, handle_pcm_queue, send_pcm_response_worker},
    hardcoded_snd_data, hardcoded_virtio_snd_config, Parameters, PcmResponse, SndData, StreamInfo,
    MAX_QUEUE_NUM, MAX_VRING_LEN,
};
use crate::virtio::snd::layout::virtio_snd_config;
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::{self, copy_config};

static SND_EXECUTOR: OnceCell<Executor> = OnceCell::new();

// Async workers:
// 0 - ctrl
// 1 - event
// 2 - tx
// 3 - rx
const PCM_RESPONSE_WORKER_IDX_OFFSET: usize = 2;
struct CrasSndBackend {
    cfg: virtio_snd_config,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
    response_workers: [Option<AbortHandle>; 2], // tx and rx
    snd_data: Rc<SndData>,
    streams: Rc<AsyncMutex<Vec<AsyncMutex<StreamInfo<'static>>>>>,
    params: Parameters,
    tx_send: mpsc::UnboundedSender<PcmResponse>,
    rx_send: mpsc::UnboundedSender<PcmResponse>,
    tx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
    rx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
}

impl CrasSndBackend {
    pub fn new(params: Parameters) -> anyhow::Result<Self> {
        let cfg = hardcoded_virtio_snd_config(&params);
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        let snd_data = hardcoded_snd_data(&params);

        let mut streams: Vec<AsyncMutex<StreamInfo>> = Vec::new();
        streams.resize_with(snd_data.pcm_info_len(), Default::default);
        let streams = Rc::new(AsyncMutex::new(streams));

        let (tx_send, tx_recv) = mpsc::unbounded();
        let (rx_send, rx_recv) = mpsc::unbounded();

        Ok(CrasSndBackend {
            cfg,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
            response_workers: Default::default(),
            snd_data: Rc::new(snd_data),
            streams,
            params,
            tx_send,
            rx_send,
            tx_recv: Some(tx_recv),
            rx_recv: Some(rx_recv),
        })
    }
}

impl VhostUserBackend for CrasSndBackend {
    const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM;
    const MAX_VRING_LEN: u16 = MAX_VRING_LEN;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        copy_config(data, 0, self.cfg.as_slice(), offset)
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Safe because the executor is initialized in main() below.
        let ex = SND_EXECUTOR.get().expect("Executor not initialized");

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt =
            EventAsync::new(kick_evt.0, ex).context("failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                // ctrl queue
                let streams = self.streams.clone();
                let snd_data = self.snd_data.clone();
                let tx_send = self.tx_send.clone();
                let rx_send = self.rx_send.clone();
                let params = self.params.clone();
                ex.spawn_local(Abortable::new(
                    async move {
                        handle_ctrl_queue(
                            &ex, &mem, &streams, &*snd_data, queue, kick_evt, &doorbell, tx_send,
                            rx_send, &params,
                        )
                        .await
                    },
                    registration,
                ))
                .detach();
            }
            1 => {} // TODO(woodychow): Add event queue support
            2 | 3 => {
                let (send, recv) = if idx == 2 {
                    (self.tx_send.clone(), self.tx_recv.take())
                } else {
                    (self.rx_send.clone(), self.rx_recv.take())
                };
                let mut recv = recv.ok_or_else(|| anyhow!("queue restart is not supported"))?;
                let queue = Rc::new(AsyncMutex::new(queue));
                let queue2 = Rc::clone(&queue);
                let mem = Rc::new(mem);
                let mem2 = Rc::clone(&mem);
                let streams = Rc::clone(&self.streams);
                ex.spawn_local(Abortable::new(
                    async move { handle_pcm_queue(&*mem, &streams, send, &queue, kick_evt).await },
                    registration,
                ))
                .detach();

                let (handle2, registration2) = AbortHandle::new_pair();

                ex.spawn_local(Abortable::new(
                    async move {
                        send_pcm_response_worker(&*mem2, &queue2, &doorbell, &mut recv).await
                    },
                    registration2,
                ))
                .detach();

                self.response_workers[idx - PCM_RESPONSE_WORKER_IDX_OFFSET] = Some(handle2);
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
        if idx == 2 || idx == 3 {
            if let Some(handle) = self
                .response_workers
                .get_mut(idx - PCM_RESPONSE_WORKER_IDX_OFFSET)
                .and_then(Option::take)
            {
                handle.abort();
            }
        }
    }
}

#[derive(FromArgs)]
#[argh(description = "")]
struct Options {
    #[argh(option, description = "path to a socket", arg_name = "PATH")]
    socket: String,
    #[argh(
        option,
        description = "comma separated key=value pairs for setting up cras snd devices.
Possible key values:
capture - Enable audio capture. Default to false.
client_type - Set specific client type for cras backend.
num_output_streams - Set number of output PCM streams.
num_input_streams - Set number of input PCM streams.
Example: [capture=true,client=crosvm,socket=unified,num_output_streams=1,num_input_streams=1]",
        arg_name = "CONFIG"
    )]
    config: Option<String>,
}

/// Starts a vhost-user snd device with the cras backend.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_cras_snd_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };
    let params = opts
        .config
        .unwrap_or("".to_string())
        .parse::<Parameters>()?;

    let snd_device = CrasSndBackend::new(params)?;

    // Create and bind unix socket
    let listener = UnixListener::bind(opts.socket).map(UnlinkUnixListener)?;

    let handler = DeviceRequestHandler::new(snd_device);

    // Child, we can continue by spawning the executor and set up the device
    let ex = Executor::new().context("Failed to create executor")?;

    let _ = SND_EXECUTOR.set(ex.clone());

    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(handler.run_with_listener(listener, &ex))?
}
<commit_msg>devices: vhost-user: cras_snd: remove global executor variable<commit_after>// Copyright 2021 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::os::unix::net::UnixListener;
use std::rc::Rc;
use std::sync::Arc;

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{warn, Event, UnlinkUnixListener};
use cros_async::{sync::Mutex as AsyncMutex, EventAsync, Executor};
use data_model::DataInit;
use futures::channel::mpsc;
use futures::future::{AbortHandle, Abortable};
use hypervisor::ProtectionType;
use sync::Mutex;
use vm_memory::GuestMemory;
use vmm_vhost::message::{VhostUserProtocolFeatures, VhostUserVirtioFeatures};

use crate::virtio::snd::cras_backend::{
    async_funcs::{handle_ctrl_queue, handle_pcm_queue, send_pcm_response_worker},
    hardcoded_snd_data, hardcoded_virtio_snd_config, Parameters, PcmResponse, SndData, StreamInfo,
    MAX_QUEUE_NUM, MAX_VRING_LEN,
};
use crate::virtio::snd::layout::virtio_snd_config;
use crate::virtio::vhost::user::device::handler::{
    DeviceRequestHandler, Doorbell, VhostUserBackend,
};
use crate::virtio::{self, copy_config};

// Async workers:
// 0 - ctrl
// 1 - event
// 2 - tx
// 3 - rx
const PCM_RESPONSE_WORKER_IDX_OFFSET: usize = 2;
struct CrasSndBackend {
    ex: Executor,
    cfg: virtio_snd_config,
    avail_features: u64,
    acked_features: u64,
    acked_protocol_features: VhostUserProtocolFeatures,
    workers: [Option<AbortHandle>; MAX_QUEUE_NUM],
    response_workers: [Option<AbortHandle>; 2], // tx and rx
    snd_data: Rc<SndData>,
    streams: Rc<AsyncMutex<Vec<AsyncMutex<StreamInfo<'static>>>>>,
    params: Parameters,
    tx_send: mpsc::UnboundedSender<PcmResponse>,
    rx_send: mpsc::UnboundedSender<PcmResponse>,
    tx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
    rx_recv: Option<mpsc::UnboundedReceiver<PcmResponse>>,
}

impl CrasSndBackend {
    pub fn new(ex: &Executor, params: Parameters) -> anyhow::Result<Self> {
        let cfg = hardcoded_virtio_snd_config(&params);
        let avail_features = virtio::base_features(ProtectionType::Unprotected)
            | VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits();

        let snd_data = hardcoded_snd_data(&params);

        let mut streams: Vec<AsyncMutex<StreamInfo>> = Vec::new();
        streams.resize_with(snd_data.pcm_info_len(), Default::default);
        let streams = Rc::new(AsyncMutex::new(streams));

        let (tx_send, tx_recv) = mpsc::unbounded();
        let (rx_send, rx_recv) = mpsc::unbounded();

        Ok(CrasSndBackend {
            ex: ex.clone(),
            cfg,
            avail_features,
            acked_features: 0,
            acked_protocol_features: VhostUserProtocolFeatures::empty(),
            workers: Default::default(),
            response_workers: Default::default(),
            snd_data: Rc::new(snd_data),
            streams,
            params,
            tx_send,
            rx_send,
            tx_recv: Some(tx_recv),
            rx_recv: Some(rx_recv),
        })
    }
}

impl VhostUserBackend for CrasSndBackend {
    const MAX_QUEUE_NUM: usize = MAX_QUEUE_NUM;
    const MAX_VRING_LEN: u16 = MAX_VRING_LEN;

    type Error = anyhow::Error;

    fn features(&self) -> u64 {
        self.avail_features
    }

    fn ack_features(&mut self, value: u64) -> anyhow::Result<()> {
        let unrequested_features = value & !self.avail_features;
        if unrequested_features != 0 {
            bail!("invalid features are given: {:#x}", unrequested_features);
        }

        self.acked_features |= value;

        Ok(())
    }

    fn acked_features(&self) -> u64 {
        self.acked_features
    }

    fn protocol_features(&self) -> VhostUserProtocolFeatures {
        VhostUserProtocolFeatures::CONFIG | VhostUserProtocolFeatures::MQ
    }

    fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> {
        let features = VhostUserProtocolFeatures::from_bits(features)
            .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?;
        let supported = self.protocol_features();
        self.acked_protocol_features = features & supported;
        Ok(())
    }

    fn acked_protocol_features(&self) -> u64 {
        self.acked_protocol_features.bits()
    }

    fn read_config(&self, offset: u64, data: &mut [u8]) {
        copy_config(data, 0, self.cfg.as_slice(), offset)
    }

    fn reset(&mut self) {
        for handle in self.workers.iter_mut().filter_map(Option::take) {
            handle.abort();
        }
    }

    fn start_queue(
        &mut self,
        idx: usize,
        mut queue: virtio::Queue,
        mem: GuestMemory,
        doorbell: Arc<Mutex<Doorbell>>,
        kick_evt: Event,
    ) -> anyhow::Result<()> {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            warn!("Starting new queue handler without stopping old handler");
            handle.abort();
        }

        // Enable any virtqueue features that were negotiated (like VIRTIO_RING_F_EVENT_IDX).
        queue.ack_features(self.acked_features);

        let kick_evt = EventAsync::new(kick_evt.0, &self.ex)
            .context("failed to create EventAsync for kick_evt")?;
        let (handle, registration) = AbortHandle::new_pair();
        match idx {
            0 => {
                // ctrl queue
                let streams = self.streams.clone();
                let snd_data = self.snd_data.clone();
                let tx_send = self.tx_send.clone();
                let rx_send = self.rx_send.clone();
                let params = self.params.clone();
                self.ex
                    .spawn_local(Abortable::new(
                        async move {
                            handle_ctrl_queue(
                                &self.ex, &mem, &streams, &*snd_data, queue, kick_evt, &doorbell,
                                tx_send, rx_send, &params,
                            )
                            .await
                        },
                        registration,
                    ))
                    .detach();
            }
            1 => {} // TODO(woodychow): Add event queue support
            2 | 3 => {
                let (send, recv) = if idx == 2 {
                    (self.tx_send.clone(), self.tx_recv.take())
                } else {
                    (self.rx_send.clone(), self.rx_recv.take())
                };
                let mut recv = recv.ok_or_else(|| anyhow!("queue restart is not supported"))?;
                let queue = Rc::new(AsyncMutex::new(queue));
                let queue2 = Rc::clone(&queue);
                let mem = Rc::new(mem);
                let mem2 = Rc::clone(&mem);
                let streams = Rc::clone(&self.streams);
                self.ex.spawn_local(Abortable::new(
                    async move { handle_pcm_queue(&*mem, &streams, send, &queue, kick_evt).await },
                    registration,
                ))
                .detach();

                let (handle2, registration2) = AbortHandle::new_pair();

                self.ex
                    .spawn_local(Abortable::new(
                        async move {
                            send_pcm_response_worker(&*mem2, &queue2, &doorbell, &mut recv).await
                        },
                        registration2,
                    ))
                    .detach();

                self.response_workers[idx - PCM_RESPONSE_WORKER_IDX_OFFSET] = Some(handle2);
            }
            _ => bail!("attempted to start unknown queue: {}", idx),
        }

        self.workers[idx] = Some(handle);
        Ok(())
    }

    fn stop_queue(&mut self, idx: usize) {
        if let Some(handle) = self.workers.get_mut(idx).and_then(Option::take) {
            handle.abort();
        }
        if idx == 2 || idx == 3 {
            if let Some(handle) = self
                .response_workers
                .get_mut(idx - PCM_RESPONSE_WORKER_IDX_OFFSET)
                .and_then(Option::take)
            {
                handle.abort();
            }
        }
    }
}

#[derive(FromArgs)]
#[argh(description = "")]
struct Options {
    #[argh(option, description = "path to a socket", arg_name = "PATH")]
    socket: String,
    #[argh(
        option,
        description = "comma separated key=value pairs for setting up cras snd devices.
Possible key values:
capture - Enable audio capture. Default to false.
client_type - Set specific client type for cras backend.
num_output_streams - Set number of output PCM streams.
num_input_streams - Set number of input PCM streams.
Example: [capture=true,client=crosvm,socket=unified,num_output_streams=1,num_input_streams=1]",
        arg_name = "CONFIG"
    )]
    config: Option<String>,
}

/// Starts a vhost-user snd device with the cras backend.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn run_cras_snd_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };
    let params = opts
        .config
        .unwrap_or("".to_string())
        .parse::<Parameters>()?;

    // Child, we can continue by spawning the executor and set up the device
    let ex = Executor::new().context("Failed to create executor")?;

    let snd_device = CrasSndBackend::new(&ex, params)?;

    // Create and bind unix socket
    let listener = UnixListener::bind(opts.socket).map(UnlinkUnixListener)?;

    let handler = DeviceRequestHandler::new(snd_device);

    // run_until() returns an Result<Result<..>> which the ? operator lets us flatten.
    ex.run_until(handler.run_with_listener(listener, &ex))?
}
<|endoftext|>


<commit_before>//! Within this module, types commonly use the following abbreviations:
//!
//! F: From Clause
//! S: Select Clause
//! D: Distinct Clause
//! W: Where Clause
//! O: Order By Clause
//! L: Limit Clause
//! Of: Offset Clause
//! G: Group By Clause
mod dsl_impls;
mod boxed;

pub use self::boxed::BoxedSelectStatement;

use backend::Backend;
use expression::*;
use query_source::*;
use query_source::joins::AppendSelection;
use result::QueryResult;
use super::distinct_clause::NoDistinctClause;
use super::for_update_clause::NoForUpdateClause;
use super::group_by_clause::NoGroupByClause;
use super::limit_clause::NoLimitClause;
use super::offset_clause::NoOffsetClause;
use super::order_clause::NoOrderClause;
use super::select_clause::*;
use super::where_clause::NoWhereClause;
use super::{AstPass, Query, QueryFragment};

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
pub struct SelectStatement<
    From,
    Select = DefaultSelectClause,
    Distinct = NoDistinctClause,
    Where = NoWhereClause,
    Order = NoOrderClause,
    Limit = NoLimitClause,
    Offset = NoOffsetClause,
    GroupBy = NoGroupByClause,
    ForUpdate = NoForUpdateClause,
> {
    select: Select,
    from: From,
    distinct: Distinct,
    where_clause: Where,
    order: Order,
    limit: Limit,
    offset: Offset,
    group_by: GroupBy,
    for_update: ForUpdate,
}

impl<F, S, D, W, O, L, Of, G, FU> SelectStatement<F, S, D, W, O, L, Of, G, FU> {
    #[cfg_attr(feature = "clippy", allow(too_many_arguments))]
    pub fn new(
        select: S,
        from: F,
        distinct: D,
        where_clause: W,
        order: O,
        limit: L,
        offset: Of,
        group_by: G,
        for_update: FU,
    ) -> Self {
        SelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            for_update,
        }
    }
}

impl<F> SelectStatement<F> {
    pub fn simple(from: F) -> Self {
        SelectStatement::new(
            DefaultSelectClause,
            from,
            NoDistinctClause,
            NoWhereClause,
            NoOrderClause,
            NoLimitClause,
            NoOffsetClause,
            NoGroupByClause,
            NoForUpdateClause,
        )
    }
}

impl<F, S, D, W, O, L, Of, G, FU> Query for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = S::SelectClauseSqlType;
}

#[cfg(feature = "postgres")]
impl<F, S, D, W, O, L, Of, G, FU> Expression for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = ::types::Array<S::SelectClauseSqlType>;
}

#[cfg(not(feature = "postgres"))]
impl<F, S, D, W, O, L, Of, G, FU> Expression for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = S::SelectClauseSqlType;
}

impl<F, S, D, W, O, L, Of, G, FU, DB> QueryFragment<DB>
    for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    DB: Backend,
    S: SelectClauseQueryFragment<F, DB>,
    F: QuerySource,
    F::FromClause: QueryFragment<DB>,
    D: QueryFragment<DB>,
    W: QueryFragment<DB>,
    O: QueryFragment<DB>,
    L: QueryFragment<DB>,
    Of: QueryFragment<DB>,
    G: QueryFragment<DB>,
    FU: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(&self.from, out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        self.for_update.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<S, D, W, O, L, Of, G, FU, DB> QueryFragment<DB>
    for SelectStatement<(), S, D, W, O, L, Of, G, FU>
where
    DB: Backend,
    S: SelectClauseQueryFragment<(), DB>,
    D: QueryFragment<DB>,
    W: QueryFragment<DB>,
    O: QueryFragment<DB>,
    L: QueryFragment<DB>,
    Of: QueryFragment<DB>,
    G: QueryFragment<DB>,
    FU: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(&(), out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        self.for_update.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl_query_id!(SelectStatement<F, S, D, W, O, L, Of, G, FU>);

impl<F, S, D, W, O, L, Of, G, FU, QS> SelectableExpression<QS>
    for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    Self: AppearsOnTable<QS>,
{
}

impl<S, F, D, W, O, L, Of, G, FU, QS> AppearsOnTable<QS>
    for SelectStatement<S, F, D, W, O, L, Of, FU, G>
where
    Self: Expression,
{
}

impl<F, S, D, W, O, L, Of, G, FU> NonAggregate for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    Self: Expression,
{
}

/// Allow `SelectStatement<From>` to act as if it were `From` as long as
/// no other query methods have been called on it
impl<From, T> AppearsInFromClause<T> for SelectStatement<From>
where
    From: AppearsInFromClause<T>,
{
    type Count = From::Count;
}

impl<From> QuerySource for SelectStatement<From>
where
    From: QuerySource,
    From::DefaultSelection: SelectableExpression<Self>,
{
    type FromClause = From::FromClause;
    type DefaultSelection = From::DefaultSelection;

    fn from_clause(&self) -> Self::FromClause {
        self.from.from_clause()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.from.default_selection()
    }
}

impl<From, Selection> AppendSelection<Selection> for SelectStatement<From>
where
    From: AppendSelection<Selection>,
{
    type Output = From::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.from.append_selection(selection)
    }
}
<commit_msg>Add For Update Symbol(FU) to Symbol List<commit_after>//! Within this module, types commonly use the following abbreviations:
//!
//! F: From Clause
//! S: Select Clause
//! D: Distinct Clause
//! W: Where Clause
//! O: Order By Clause
//! L: Limit Clause
//! Of: Offset Clause
//! G: Group By Clause
//! FU: For Update Clause
mod dsl_impls;
mod boxed;

pub use self::boxed::BoxedSelectStatement;

use backend::Backend;
use expression::*;
use query_source::*;
use query_source::joins::AppendSelection;
use result::QueryResult;
use super::distinct_clause::NoDistinctClause;
use super::for_update_clause::NoForUpdateClause;
use super::group_by_clause::NoGroupByClause;
use super::limit_clause::NoLimitClause;
use super::offset_clause::NoOffsetClause;
use super::order_clause::NoOrderClause;
use super::select_clause::*;
use super::where_clause::NoWhereClause;
use super::{AstPass, Query, QueryFragment};

#[derive(Debug, Clone, Copy)]
#[doc(hidden)]
#[must_use = "Queries are only executed when calling `load`, `get_result` or similar."]
pub struct SelectStatement<
    From,
    Select = DefaultSelectClause,
    Distinct = NoDistinctClause,
    Where = NoWhereClause,
    Order = NoOrderClause,
    Limit = NoLimitClause,
    Offset = NoOffsetClause,
    GroupBy = NoGroupByClause,
    ForUpdate = NoForUpdateClause,
> {
    select: Select,
    from: From,
    distinct: Distinct,
    where_clause: Where,
    order: Order,
    limit: Limit,
    offset: Offset,
    group_by: GroupBy,
    for_update: ForUpdate,
}

impl<F, S, D, W, O, L, Of, G, FU> SelectStatement<F, S, D, W, O, L, Of, G, FU> {
    #[cfg_attr(feature = "clippy", allow(too_many_arguments))]
    pub fn new(
        select: S,
        from: F,
        distinct: D,
        where_clause: W,
        order: O,
        limit: L,
        offset: Of,
        group_by: G,
        for_update: FU,
    ) -> Self {
        SelectStatement {
            select: select,
            from: from,
            distinct: distinct,
            where_clause: where_clause,
            order: order,
            limit: limit,
            offset: offset,
            group_by: group_by,
            for_update,
        }
    }
}

impl<F> SelectStatement<F> {
    pub fn simple(from: F) -> Self {
        SelectStatement::new(
            DefaultSelectClause,
            from,
            NoDistinctClause,
            NoWhereClause,
            NoOrderClause,
            NoLimitClause,
            NoOffsetClause,
            NoGroupByClause,
            NoForUpdateClause,
        )
    }
}

impl<F, S, D, W, O, L, Of, G, FU> Query for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = S::SelectClauseSqlType;
}

#[cfg(feature = "postgres")]
impl<F, S, D, W, O, L, Of, G, FU> Expression for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = ::types::Array<S::SelectClauseSqlType>;
}

#[cfg(not(feature = "postgres"))]
impl<F, S, D, W, O, L, Of, G, FU> Expression for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    S: SelectClauseExpression<F>,
{
    type SqlType = S::SelectClauseSqlType;
}

impl<F, S, D, W, O, L, Of, G, FU, DB> QueryFragment<DB>
    for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    DB: Backend,
    S: SelectClauseQueryFragment<F, DB>,
    F: QuerySource,
    F::FromClause: QueryFragment<DB>,
    D: QueryFragment<DB>,
    W: QueryFragment<DB>,
    O: QueryFragment<DB>,
    L: QueryFragment<DB>,
    Of: QueryFragment<DB>,
    G: QueryFragment<DB>,
    FU: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(&self.from, out.reborrow())?;
        out.push_sql(" FROM ");
        self.from.from_clause().walk_ast(out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        self.for_update.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl<S, D, W, O, L, Of, G, FU, DB> QueryFragment<DB>
    for SelectStatement<(), S, D, W, O, L, Of, G, FU>
where
    DB: Backend,
    S: SelectClauseQueryFragment<(), DB>,
    D: QueryFragment<DB>,
    W: QueryFragment<DB>,
    O: QueryFragment<DB>,
    L: QueryFragment<DB>,
    Of: QueryFragment<DB>,
    G: QueryFragment<DB>,
    FU: QueryFragment<DB>,
{
    fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
        out.push_sql("SELECT ");
        self.distinct.walk_ast(out.reborrow())?;
        self.select.walk_ast(&(), out.reborrow())?;
        self.where_clause.walk_ast(out.reborrow())?;
        self.group_by.walk_ast(out.reborrow())?;
        self.order.walk_ast(out.reborrow())?;
        self.limit.walk_ast(out.reborrow())?;
        self.offset.walk_ast(out.reborrow())?;
        self.for_update.walk_ast(out.reborrow())?;
        Ok(())
    }
}

impl_query_id!(SelectStatement<F, S, D, W, O, L, Of, G, FU>);

impl<F, S, D, W, O, L, Of, G, FU, QS> SelectableExpression<QS>
    for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    Self: AppearsOnTable<QS>,
{
}

impl<S, F, D, W, O, L, Of, G, FU, QS> AppearsOnTable<QS>
    for SelectStatement<S, F, D, W, O, L, Of, FU, G>
where
    Self: Expression,
{
}

impl<F, S, D, W, O, L, Of, G, FU> NonAggregate for SelectStatement<F, S, D, W, O, L, Of, G, FU>
where
    Self: Expression,
{
}

/// Allow `SelectStatement<From>` to act as if it were `From` as long as
/// no other query methods have been called on it
impl<From, T> AppearsInFromClause<T> for SelectStatement<From>
where
    From: AppearsInFromClause<T>,
{
    type Count = From::Count;
}

impl<From> QuerySource for SelectStatement<From>
where
    From: QuerySource,
    From::DefaultSelection: SelectableExpression<Self>,
{
    type FromClause = From::FromClause;
    type DefaultSelection = From::DefaultSelection;

    fn from_clause(&self) -> Self::FromClause {
        self.from.from_clause()
    }

    fn default_selection(&self) -> Self::DefaultSelection {
        self.from.default_selection()
    }
}

impl<From, Selection> AppendSelection<Selection> for SelectStatement<From>
where
    From: AppendSelection<Selection>,
{
    type Output = From::Output;

    fn append_selection(&self, selection: Selection) -> Self::Output {
        self.from.append_selection(selection)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows failing on win32 bot
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g

// This test uses some GDB Python API features (e.g. accessing anonymous fields)
// which are only available in newer GDB version. The following directive will
// case the test runner to ignore this test if an older GDB version is used:
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print regular_struct
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}

// gdb-command: print tuple
// gdb-check:$2 = {true, 103, "blub"}

// gdb-command: print tuple_struct
// gdb-check:$3 = TupleStruct = {-104.5, 105}

// gdb-command: print empty_struct
// gdb-check:$4 = EmptyStruct

// gdb-command: print c_style_enum1
// gdb-check:$5 = CStyleEnumVar1

// gdb-command: print c_style_enum2
// gdb-check:$6 = CStyleEnumVar2

// gdb-command: print c_style_enum3
// gdb-check:$7 = CStyleEnumVar3

// gdb-command: print mixed_enum_c_style_var
// gdb-check:$8 = MixedEnumCStyleVar

// gdb-command: print mixed_enum_tuple_var
// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}

// gdb-command: print mixed_enum_struct_var
// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}

// gdb-command: print some
// gdb-check:$11 = Some = {110}

// gdb-command: print none
// gdb-check:$12 = None

// gdb-command: print some_fat
// gdb-check:$13 = Some = {"abc"}

// gdb-command: print none_fat
// gdb-check:$14 = None

// gdb-command: print nested_variant1
// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}

// gdb-command: print nested_variant2
// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}

// gdb-command: print none_check1
// gdb-check:$16 = None

// gdb-command: print none_check2
// gdb-check:$17 = None

use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};

struct RegularStruct {
    the_first_field: int,
    the_second_field: f64,
    the_third_field: bool,
    the_fourth_field: &'static str,
}

struct TupleStruct(f64, i16);

struct EmptyStruct;

enum CStyleEnum {
    CStyleEnumVar1,
    CStyleEnumVar2,
    CStyleEnumVar3,
}

enum MixedEnum {
    MixedEnumCStyleVar,
    MixedEnumTupleVar(u32, u16, bool),
    MixedEnumStructVar { field1: f64, field2: i32 }
}

struct NestedStruct {
    regular_struct: RegularStruct,
    tuple_struct: TupleStruct,
    empty_struct: EmptyStruct,
    c_style_enum: CStyleEnum,
    mixed_enum: MixedEnum,
}

enum NestedEnum {
    NestedVariant1(NestedStruct),
    NestedVariant2 { abc: NestedStruct }
}

fn main() {

    let regular_struct = RegularStruct {
        the_first_field: 101,
        the_second_field: 102.5,
        the_third_field: false,
        the_fourth_field: "I'm so pretty, oh so pretty..."
    };

    let tuple = ( true, 103u32, "blub" );

    let tuple_struct = TupleStruct(-104.5, 105);

    let empty_struct = EmptyStruct;

    let c_style_enum1 = CStyleEnumVar1;
    let c_style_enum2 = CStyleEnumVar2;
    let c_style_enum3 = CStyleEnumVar3;

    let mixed_enum_c_style_var = MixedEnumCStyleVar;
    let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
    let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };

    let some = Some(110u);
    let none: Option<int> = None;
    let some_fat = Some("abc");
    let none_fat: Option<&'static str> = None;

    let nested_variant1 = NestedVariant1(
        NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 111,
                the_second_field: 112.5,
                the_third_field: true,
                the_fourth_field: "NestedStructString1",
            },
            tuple_struct: TupleStruct(113.5, 114),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar2,
            mixed_enum: MixedEnumTupleVar(115, 116, false)
        }
    );

    let nested_variant2 = NestedVariant2 {
        abc: NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 117,
                the_second_field: 118.5,
                the_third_field: false,
                the_fourth_field: "NestedStructString10",
            },
            tuple_struct: TupleStruct(119.5, 120),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar3,
            mixed_enum: MixedEnumStructVar {
                field1: 121.5,
                field2: -122
            }
        }
    };

    let none_check1: Option<(uint, Vec<uint>)> = None;
    let none_check2: Option<String> = None;

    zzz(); // #break
}

fn zzz() { () }
<commit_msg>Fixed tests<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows failing on win32 bot
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g

// This test uses some GDB Python API features (e.g. accessing anonymous fields)
// which are only available in newer GDB version. The following directive will
// case the test runner to ignore this test if an older GDB version is used:
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print regular_struct
// gdb-check:$1 = RegularStruct = {the_first_field = 101, the_second_field = 102.5, the_third_field = false, the_fourth_field = "I'm so pretty, oh so pretty..."}

// gdb-command: print tuple
// gdb-check:$2 = {true, 103, "blub"}

// gdb-command: print tuple_struct
// gdb-check:$3 = TupleStruct = {-104.5, 105}

// gdb-command: print empty_struct
// gdb-check:$4 = EmptyStruct

// gdb-command: print c_style_enum1
// gdb-check:$5 = CStyleEnumVar1

// gdb-command: print c_style_enum2
// gdb-check:$6 = CStyleEnumVar2

// gdb-command: print c_style_enum3
// gdb-check:$7 = CStyleEnumVar3

// gdb-command: print mixed_enum_c_style_var
// gdb-check:$8 = MixedEnumCStyleVar

// gdb-command: print mixed_enum_tuple_var
// gdb-check:$9 = MixedEnumTupleVar = {106, 107, false}

// gdb-command: print mixed_enum_struct_var
// gdb-check:$10 = MixedEnumStructVar = {field1 = 108.5, field2 = 109}

// gdb-command: print some
// gdb-check:$11 = Some = {110}

// gdb-command: print none
// gdb-check:$12 = None

// gdb-command: print some_fat
// gdb-check:$13 = Some = {"abc"}

// gdb-command: print none_fat
// gdb-check:$14 = None

// gdb-command: print nested_variant1
// gdb-check:$15 = NestedVariant1 = {NestedStruct = {regular_struct = RegularStruct = {the_first_field = 111, the_second_field = 112.5, the_third_field = true, the_fourth_field = "NestedStructString1"}, tuple_struct = TupleStruct = {113.5, 114}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar2, mixed_enum = MixedEnumTupleVar = {115, 116, false}}}

// gdb-command: print nested_variant2
// gdb-check:$16 = NestedVariant2 = {abc = NestedStruct = {regular_struct = RegularStruct = {the_first_field = 117, the_second_field = 118.5, the_third_field = false, the_fourth_field = "NestedStructString10"}, tuple_struct = TupleStruct = {119.5, 120}, empty_struct = EmptyStruct, c_style_enum = CStyleEnumVar3, mixed_enum = MixedEnumStructVar = {field1 = 121.5, field2 = -122}}}

// gdb-command: print none_check1
// gdb-check:$17 = None

// gdb-command: print none_check2
// gdb-check:$18 = None

use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::CStyleEnum::{CStyleEnumVar1, CStyleEnumVar2, CStyleEnumVar3};
use self::MixedEnum::{MixedEnumCStyleVar, MixedEnumTupleVar, MixedEnumStructVar};
use self::NestedEnum::{NestedVariant1, NestedVariant2};

struct RegularStruct {
    the_first_field: int,
    the_second_field: f64,
    the_third_field: bool,
    the_fourth_field: &'static str,
}

struct TupleStruct(f64, i16);

struct EmptyStruct;

enum CStyleEnum {
    CStyleEnumVar1,
    CStyleEnumVar2,
    CStyleEnumVar3,
}

enum MixedEnum {
    MixedEnumCStyleVar,
    MixedEnumTupleVar(u32, u16, bool),
    MixedEnumStructVar { field1: f64, field2: i32 }
}

struct NestedStruct {
    regular_struct: RegularStruct,
    tuple_struct: TupleStruct,
    empty_struct: EmptyStruct,
    c_style_enum: CStyleEnum,
    mixed_enum: MixedEnum,
}

enum NestedEnum {
    NestedVariant1(NestedStruct),
    NestedVariant2 { abc: NestedStruct }
}

fn main() {

    let regular_struct = RegularStruct {
        the_first_field: 101,
        the_second_field: 102.5,
        the_third_field: false,
        the_fourth_field: "I'm so pretty, oh so pretty..."
    };

    let tuple = ( true, 103u32, "blub" );

    let tuple_struct = TupleStruct(-104.5, 105);

    let empty_struct = EmptyStruct;

    let c_style_enum1 = CStyleEnumVar1;
    let c_style_enum2 = CStyleEnumVar2;
    let c_style_enum3 = CStyleEnumVar3;

    let mixed_enum_c_style_var = MixedEnumCStyleVar;
    let mixed_enum_tuple_var = MixedEnumTupleVar(106, 107, false);
    let mixed_enum_struct_var = MixedEnumStructVar { field1: 108.5, field2: 109 };

    let some = Some(110u);
    let none: Option<int> = None;
    let some_fat = Some("abc");
    let none_fat: Option<&'static str> = None;

    let nested_variant1 = NestedVariant1(
        NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 111,
                the_second_field: 112.5,
                the_third_field: true,
                the_fourth_field: "NestedStructString1",
            },
            tuple_struct: TupleStruct(113.5, 114),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar2,
            mixed_enum: MixedEnumTupleVar(115, 116, false)
        }
    );

    let nested_variant2 = NestedVariant2 {
        abc: NestedStruct {
            regular_struct: RegularStruct {
                the_first_field: 117,
                the_second_field: 118.5,
                the_third_field: false,
                the_fourth_field: "NestedStructString10",
            },
            tuple_struct: TupleStruct(119.5, 120),
            empty_struct: EmptyStruct,
            c_style_enum: CStyleEnumVar3,
            mixed_enum: MixedEnumStructVar {
                field1: 121.5,
                field2: -122
            }
        }
    };

    let none_check1: Option<(uint, Vec<uint>)> = None;
    let none_check2: Option<String> = None;

    zzz(); // #break
}

fn zzz() { () }
<|endoftext|>


<commit_before>// strcat: rusti: trait Foo { fn foo(&self); } trait Bar {}; impl<T: Bar> Foo
// for T { fn foo(&self) { println("default impl") } }; impl Bar for int {};
// 5.foo()

use agent::Crowd;
use std::io;
mod agent;

// Type Observer
pub trait Observer {
    fn see(&self, time: f64, crowd: &Crowd);
    fn request_at(&self, time: f64, dt: f64) -> bool;
    // fn request_at(&self, time: f64, dt: f64) -> bool {
    //     let inter_size = self.tmax / (self.freq as f64);
    //     let int_num=(time/inter_size) as uint;
    //     (time-inter_size*(int_num as f64)).abs() < dt
    // }
}

//
// * Barre de progression
//
struct ProgressMeter {
    tmax: f64,
    freq: uint
}

impl ProgressMeter {
    pub fn new(tmax: f64, freq: uint) -> ProgressMeter {
        ProgressMeter {tmax: tmax, freq: freq}
    }
}

impl Observer for ProgressMeter {
    fn see(&self, time: f64, crowd: &Crowd) {
        println!("{:f} : {:u} cellules", time, crowd.size());
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}
//
// * Affichage à l'écran
//
struct ScreenPrinter {
    tmax: f64,
    freq: uint
}

impl ScreenPrinter {
    pub fn new(tmax: f64, freq: uint) -> ScreenPrinter {
        ScreenPrinter { tmax: tmax, freq: freq}
    }
}

impl Observer for ScreenPrinter {
    fn see(&self, time: f64, crowd: &Crowd) {
        println!("{:f}\n", time);
        println(crowd.to_str());
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}

//
// * Sortie sur le disque
//
struct DiskWriter {
    tmax: f64,
    freq: uint,
    fname: ~str,
}

impl DiskWriter {
    pub fn new(tmax: f64, freq:uint, name: ~str) -> DiskWriter {
        DiskWriter {tmax: tmax, freq: freq, fname: name}
    }

    pub fn new_filename(&self, time: f64) -> ~str {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        format!("./{:s}-{:03u}.vtk", self.fname, int_num)
    }
}

impl Observer for DiskWriter {
    fn see(&self, time: f64, crowd: &Crowd) {
        let outfile=self.new_filename(time);
        let file_path=Path::new(outfile);
        let writer_result = io::file_writer(~file_path, [io::Create, io::Truncate] );

        if writer_result.is_ok() {
            let writer=writer_result.unwrap();

            // Ecriture de l'entête
            writer.write_str("# vtk DataFile Version 3.0\n");
            writer.write_str("Rusty_Cells\n");
            writer.write_str("ASCII\n");
            writer.write_str("DATASET UNSTRUCTURED_GRID\n");
            writer.write_str(format!("POINTS {:u} float\n", crowd.size()));

            // Coordonnées des cellules
            for cell in crowd.cells.iter() {
                writer.write_str(format!("{:f} {:f} {:f}\n",cell.x(), cell.y(), cell.z()))
            }

            // Données sur les nœuds
            // * Age
            writer.write_str(format!("POINT_DATA {:u}\nSCALARS {:s} float\nLOOKUP_TABLE default\n", crowd.size(), "age"));
            for cell in crowd.cells.iter() {
                writer.write_str(format!("{:f}\n", cell.age));
            }
            // * Vitesse
            writer.write_str(format!("VECTORS {:s} float\n",  "vitesse"));
            for cell in crowd.cells.iter() {
                let speed=cell.velocity*1e3f64;
                writer.write_str(format!("{:f} {:f} {:f}\n", speed.x, speed.y, speed.z))
            }
        }
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}
<commit_msg>Update for rust master<commit_after>use agent::Crowd;
use std::io::fs::File;
use std::io::{Write, Truncate};
mod agent;

// Type Observer
pub trait Observer {
    fn see(&self, time: f64, crowd: &Crowd);
    fn request_at(&self, time: f64, dt: f64) -> bool;
    // fn request_at(&self, time: f64, dt: f64) -> bool {
    //     let inter_size = self.tmax / (self.freq as f64);
    //     let int_num=(time/inter_size) as uint;
    //     (time-inter_size*(int_num as f64)).abs() < dt
    // }
}

//
// * Barre de progression
//
struct ProgressMeter {
    tmax: f64,
    freq: uint
}

impl ProgressMeter {
    pub fn new(tmax: f64, freq: uint) -> ProgressMeter {
        ProgressMeter {tmax: tmax, freq: freq}
    }
}

impl Observer for ProgressMeter {
    fn see(&self, time: f64, crowd: &Crowd) {
        println!("{:f} : {:u} cellules", time, crowd.size());
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}
//
// * Affichage à l'écran
//
struct ScreenPrinter {
    tmax: f64,
    freq: uint
}

impl ScreenPrinter {
    pub fn new(tmax: f64, freq: uint) -> ScreenPrinter {
        ScreenPrinter { tmax: tmax, freq: freq}
    }
}

impl Observer for ScreenPrinter {
    fn see(&self, time: f64, crowd: &Crowd) {
        println!("{:f}\n", time);
        println(crowd.to_str());
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}

//
// * Sortie sur le disque
//
struct DiskWriter {
    tmax: f64,
    freq: uint,
    fname: ~str,
}

impl DiskWriter {
    pub fn new(tmax: f64, freq:uint, name: ~str) -> DiskWriter {
        DiskWriter {tmax: tmax, freq: freq, fname: name}
    }

    pub fn new_filename(&self, time: f64) -> ~str {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        format!("./{:s}-{:03u}.vtk", self.fname, int_num)
    }
}

impl Observer for DiskWriter {
    fn see(&self, time: f64, crowd: &Crowd) {
        let outfile=self.new_filename(time);
        let file_path=Path::new(outfile);

        match File::open_mode(&file_path, Truncate , Write)  {
            None => fail!(),

            Some(ref mut f) => {
                let writer= f as &mut Writer;
                // Ecriture de l'entête
                write!(writer, "{:c} vtk DataFile Version 3.0\n", '#');
                write!(writer, "Rusty_Cells\n");
                write!(writer, "ASCII\n");
                write!(writer, "DATASET UNSTRUCTURED_GRID\n");
                write!(writer, "POINTS {:u} float\n", crowd.size());

                // Coordonnées des cellules
                for cell in crowd.cells.iter() {
                    write!(writer, "{:f} {:f} {:f}\n", cell.x(), cell.y(), cell.z() );
                }

                // Données sur les nœuds
                // * Age
                 write!(writer,"POINT_DATA {:u}\nSCALARS {:s} float\nLOOKUP_TABLE default\n", crowd.size(), "age");
                for cell in crowd.cells.iter() {
                    write!(writer,"{:f}\n", cell.age);
                }
                // * Vitesse
                write!(writer,"VECTORS {:s} float\n",  "vitesse");
                for cell in crowd.cells.iter() {
                    let speed=cell.velocity*1e3f64;
                    write!(writer,"{:f} {:f} {:f}\n", speed.x, speed.y, speed.z)
                }
            }
        }
    }

    fn request_at(&self, time: f64, dt: f64) -> bool {
        let inter_size = self.tmax / (self.freq as f64);
        let int_num=(time/inter_size) as uint;
        (time-inter_size*(int_num as f64)).abs() < dt
    }
}
<|endoftext|>


<commit_before>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

pub const RAND_MAX: ::c_int = 0x7fff_ffff;

pub const SO_DOMAIN: ::c_int = 0x1019;

pub const EINTEGRITY: ::c_int = 97;
pub const ELAST: ::c_int = 97;
pub const GRND_INSECURE: ::c_uint = 0x4;

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
    pub fn setproctitle_fast(fmt: *const ::c_char, ...);
    pub fn timingsafe_bcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
    pub fn timingsafe_memcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<commit_msg>adding LOCAL_CREDS_PERSISTENT for FreeBSD.<commit_after>// APIs in FreeBSD 13 that have changed since 11.

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }

    pub struct sockcred2 {
        pub sc_version: ::c_int,
        pub sc_pid: ::pid_t,
        pub sc_uid: ::uid_t,
        pub sc_euid: ::uid_t,
        pub sc_gid: ::gid_t,
        pub sc_egid: ::gid_t,
        pub sc_ngroups: ::c_int,
        pub sc_groups: [::gid_t; 1],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

pub const RAND_MAX: ::c_int = 0x7fff_ffff;

pub const SO_DOMAIN: ::c_int = 0x1019;

pub const EINTEGRITY: ::c_int = 97;
pub const ELAST: ::c_int = 97;
pub const GRND_INSECURE: ::c_uint = 0x4;

pub const LOCAL_CREDS_PERSISTENT: ::c_int = 3;
pub const SCM_CREDS2: ::c_int = 0x08;

f! {
    pub fn SOCKCRED2SIZE(ngrps: usize) -> usize {
        let ngrps = if ngrps > 0 {
            ngrps - 1
        } else {
            0
        };
        ::mem::size_of::<sockcred2>() + ::mem::size_of::<::gid_t>() * ngrps
    }
}

extern "C" {
    pub fn aio_readv(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn aio_writev(aiocbp: *mut ::aiocb) -> ::c_int;
    pub fn setgrent();
    pub fn mprotect(addr: *mut ::c_void, len: ::size_t, prot: ::c_int) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(buf: *mut ::c_void, buflen: ::size_t, flags: ::c_uint) -> ::ssize_t;
    pub fn getentropy(buf: *mut ::c_void, buflen: ::size_t) -> ::c_int;
    pub fn elf_aux_info(aux: ::c_int, buf: *mut ::c_void, buflen: ::c_int) -> ::c_int;
    pub fn setproctitle_fast(fmt: *const ::c_char, ...);
    pub fn timingsafe_bcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
    pub fn timingsafe_memcmp(a: *const ::c_void, b: *const ::c_void, len: ::size_t) -> ::c_int;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<|endoftext|>


<commit_before>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::io::Error as IoError;
use std::result::Result;

use libc::{uname, utsname};

#[derive(Debug)]
pub enum Error {
    Uname(IoError),
    InvalidUtf8(std::string::FromUtf8Error),
    InvalidFormat,
    InvalidInt(std::num::ParseIntError),
}

#[derive(PartialEq, PartialOrd)]
#[cfg_attr(test, derive(Debug))]
pub struct KernelVersion {
    major: u16,
    minor: u16,
    patch: u16,
}

impl KernelVersion {
    pub fn new(major: u16, minor: u16, patch: u16) -> Self {
        Self {
            major,
            minor,
            patch,
        }
    }

    pub fn get() -> Result<Self, Error> {
        let mut name: utsname = utsname {
            sysname: [0; 65],
            nodename: [0; 65],
            release: [0; 65],
            version: [0; 65],
            machine: [0; 65],
            domainname: [0; 65],
        };
        let res = unsafe { uname((&mut name) as *mut utsname) };

        if res < 0 {
            return Err(Error::Uname(IoError::last_os_error()));
        }

        Self::parse(
            String::from_utf8(name.release.iter().map(|c| *c as u8).collect())
                .map_err(Error::InvalidUtf8)?,
        )
    }

    fn parse(release: String) -> Result<Self, Error> {
        let mut tokens = release.split('.');

        let major = tokens.next().ok_or(Error::InvalidFormat)?;
        let minor = tokens.next().ok_or(Error::InvalidFormat)?;
        let mut patch = tokens.next().ok_or(Error::InvalidFormat)?;

        // Parse the `patch`, since it may contain other tokens as well.
        if let Some(index) = patch.find(|c: char| !c.is_digit(10)) {
            patch = &patch[..index];
        }

        Ok(Self {
            major: major.parse().map_err(Error::InvalidInt)?,
            minor: minor.parse().map_err(Error::InvalidInt)?,
            patch: patch.parse().map_err(Error::InvalidInt)?,
        })
    }
}

#[macro_export]
macro_rules! skip_if_kernel_lt_5_10 {
    () => {
        if KernelVersion::get().unwrap() < KernelVersion::new(5, 10, 0) {
            return;
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_get() {
        assert!(KernelVersion::get().is_ok());
    }

    #[test]
    fn test_parse_valid() {
        assert_eq!(
            KernelVersion::parse("5.10.0".to_string()).unwrap(),
            KernelVersion::new(5, 10, 0),
        );
        assert_eq!(
            KernelVersion::parse("5.10.50".to_string()).unwrap(),
            KernelVersion::new(5, 10, 50)
        );
        assert_eq!(
            KernelVersion::parse("5.10.50-38.132.amzn2int.x86_64".to_string()).unwrap(),
            KernelVersion::new(5, 10, 50)
        );
    }

    #[test]
    fn test_parse_invalid() {
        assert!(KernelVersion::parse("".to_string()).is_err());
        assert!(KernelVersion::parse("ffff".to_string()).is_err());
        assert!(KernelVersion::parse("ffff.55.0".to_string()).is_err());
        assert!(KernelVersion::parse("5.10.".to_string()).is_err());
        assert!(KernelVersion::parse("5.0".to_string()).is_err());
        assert!(KernelVersion::parse("5.0fff".to_string()).is_err());
    }

    #[test]
    fn test_cmp() {
        // Comparing major.
        assert!(KernelVersion::new(4, 0, 0) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(4, 0, 0) > KernelVersion::new(3, 10, 15));

        // Comparing minor.
        assert!(KernelVersion::new(5, 0, 20) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 20, 20) > KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 100, 20) > KernelVersion::new(5, 20, 0));

        // Comparing patch.
        assert!(KernelVersion::new(5, 0, 20) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 0, 20) > KernelVersion::new(4, 10, 15));

        // Equal.
        assert!(KernelVersion::new(5, 0, 20) == KernelVersion::new(5, 0, 20));
        assert!(KernelVersion::new(5, 0, 20) >= KernelVersion::new(5, 0, 20));
        assert!(KernelVersion::new(5, 0, 20) <= KernelVersion::new(5, 0, 20));
    }
}
<commit_msg>utils: add skip_if_kernel_ge_5_10 macro<commit_after>// Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

use std::io::Error as IoError;
use std::result::Result;

use libc::{uname, utsname};

#[derive(Debug)]
pub enum Error {
    Uname(IoError),
    InvalidUtf8(std::string::FromUtf8Error),
    InvalidFormat,
    InvalidInt(std::num::ParseIntError),
}

#[derive(PartialEq, PartialOrd)]
#[cfg_attr(test, derive(Debug))]
pub struct KernelVersion {
    major: u16,
    minor: u16,
    patch: u16,
}

impl KernelVersion {
    pub fn new(major: u16, minor: u16, patch: u16) -> Self {
        Self {
            major,
            minor,
            patch,
        }
    }

    pub fn get() -> Result<Self, Error> {
        let mut name: utsname = utsname {
            sysname: [0; 65],
            nodename: [0; 65],
            release: [0; 65],
            version: [0; 65],
            machine: [0; 65],
            domainname: [0; 65],
        };
        let res = unsafe { uname((&mut name) as *mut utsname) };

        if res < 0 {
            return Err(Error::Uname(IoError::last_os_error()));
        }

        Self::parse(
            String::from_utf8(name.release.iter().map(|c| *c as u8).collect())
                .map_err(Error::InvalidUtf8)?,
        )
    }

    fn parse(release: String) -> Result<Self, Error> {
        let mut tokens = release.split('.');

        let major = tokens.next().ok_or(Error::InvalidFormat)?;
        let minor = tokens.next().ok_or(Error::InvalidFormat)?;
        let mut patch = tokens.next().ok_or(Error::InvalidFormat)?;

        // Parse the `patch`, since it may contain other tokens as well.
        if let Some(index) = patch.find(|c: char| !c.is_digit(10)) {
            patch = &patch[..index];
        }

        Ok(Self {
            major: major.parse().map_err(Error::InvalidInt)?,
            minor: minor.parse().map_err(Error::InvalidInt)?,
            patch: patch.parse().map_err(Error::InvalidInt)?,
        })
    }
}

#[macro_export]
macro_rules! skip_if_kernel_lt_5_10 {
    () => {
        if KernelVersion::get().unwrap() < KernelVersion::new(5, 10, 0) {
            return;
        }
    };
}

#[macro_export]
macro_rules! skip_if_kernel_ge_5_10 {
    () => {
        if KernelVersion::get().unwrap() >= KernelVersion::new(5, 10, 0) {
            return;
        }
    };
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_get() {
        assert!(KernelVersion::get().is_ok());
    }

    #[test]
    fn test_parse_valid() {
        assert_eq!(
            KernelVersion::parse("5.10.0".to_string()).unwrap(),
            KernelVersion::new(5, 10, 0),
        );
        assert_eq!(
            KernelVersion::parse("5.10.50".to_string()).unwrap(),
            KernelVersion::new(5, 10, 50)
        );
        assert_eq!(
            KernelVersion::parse("5.10.50-38.132.amzn2int.x86_64".to_string()).unwrap(),
            KernelVersion::new(5, 10, 50)
        );
    }

    #[test]
    fn test_parse_invalid() {
        assert!(KernelVersion::parse("".to_string()).is_err());
        assert!(KernelVersion::parse("ffff".to_string()).is_err());
        assert!(KernelVersion::parse("ffff.55.0".to_string()).is_err());
        assert!(KernelVersion::parse("5.10.".to_string()).is_err());
        assert!(KernelVersion::parse("5.0".to_string()).is_err());
        assert!(KernelVersion::parse("5.0fff".to_string()).is_err());
    }

    #[test]
    fn test_cmp() {
        // Comparing major.
        assert!(KernelVersion::new(4, 0, 0) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(4, 0, 0) > KernelVersion::new(3, 10, 15));

        // Comparing minor.
        assert!(KernelVersion::new(5, 0, 20) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 20, 20) > KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 100, 20) > KernelVersion::new(5, 20, 0));

        // Comparing patch.
        assert!(KernelVersion::new(5, 0, 20) < KernelVersion::new(5, 10, 15));
        assert!(KernelVersion::new(5, 0, 20) > KernelVersion::new(4, 10, 15));

        // Equal.
        assert!(KernelVersion::new(5, 0, 20) == KernelVersion::new(5, 0, 20));
        assert!(KernelVersion::new(5, 0, 20) >= KernelVersion::new(5, 0, 20));
        assert!(KernelVersion::new(5, 0, 20) <= KernelVersion::new(5, 0, 20));
    }
}
<|endoftext|>