<commit_before>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! gRPC client pseudo-Node functionality.

use crate::{
    io::Receiver,
    node::{
        grpc::{codec::VecCodec, invocation::Invocation},
        ConfigurationError, Node,
    },
    runtime::RuntimeProxy,
};
use log::{debug, error, info};
use oak_abi::{
    proto::{
        google::rpc,
        oak::{application::GrpcClientConfiguration, encap::GrpcResponse},
    },
    Handle, OakStatus,
};
use tokio::sync::oneshot;
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Uri};

/// Struct that represents a gRPC client pseudo-Node.
pub struct GrpcClientNode {
    /// Pseudo-Node name.
    node_name: String,
    /// The URI component of a gRPC server endpoint. Must contain the "Host" element.
    /// https://docs.rs/tonic/0.2.1/tonic/transport/struct.Uri.html
    uri: Uri,
    /// Loaded PEM encoded X.509 TLS root certificate file used to authenticate an external gRPC
    /// service.
    root_tls_certificate: Certificate,
}

/// Checks if URI contains the "Host" element.
fn check_uri(uri: &Uri) -> Result<(), ConfigurationError> {
    uri.authority()
        .filter(|authority| !authority.host().is_empty())
        .map(|_| ())
        .ok_or(ConfigurationError::NoHostElement)
}

impl GrpcClientNode {
    /// Creates a new [`GrpcClientNode`] instance, but does not start it.
    pub fn new(
        node_name: &str,
        config: GrpcClientConfiguration,
        root_tls_certificate: Certificate,
    ) -> Result<Self, ConfigurationError> {
        let uri = config.uri.parse().map_err(|error| {
            error!("Error parsing URI {}: {:?}", config.uri, error);
            ConfigurationError::IncorrectURI
        })?;
        check_uri(&uri)?;
        Ok(Self {
            node_name: node_name.to_string(),
            uri,
            root_tls_certificate,
        })
    }

    /// Main loop that handles gRPC invocations from the `handle`, sends gRPC requests to an
    /// external gRPC service and writes gRPC responses back to the invocation channel.
    async fn handle_loop(&self, runtime: RuntimeProxy, handle: Handle) -> Result<(), OakStatus> {
        // Create a [`Receiver`] used for reading gRPC invocations.
        let receiver = Receiver::<Invocation>::new(handle);
        loop {
            debug!("Waiting for gRPC invocation");
            // Read a gRPC invocation from the [`Receiver`].
            let invocation = receiver.receive(&runtime).map_err(|error| {
                error!("Couldn't receive the invocation: {:?}", error);
                error
            })?;

            let result = self.process_invocation(&runtime, &invocation).await;
            info!("Invocation processing finished: {:?}", result);
            invocation.close(&runtime);
        }
    }

    /// Process a gRPC method invocation for an external gRPC service.
    async fn process_invocation(
        &self,
        runtime: &RuntimeProxy,
        invocation: &Invocation,
    ) -> Result<(), OakStatus> {
        // Receive a request from the invocation channel.
        let request = invocation.receive_request(&runtime).map_err(|error| {
            invocation.send_error(rpc::Code::Internal, "Failed to read request", runtime);
            error!(
                "Couldn't read gRPC request from the invocation: {:?}",
                error
            );
            error
        })?;
        debug!("Incoming gRPC request: {:?}", request);

        // Connect to an external gRPC service.
        // TOOD(#1057): persist and re-use the client/connection
        let mut grpc_client = self.connect().await.map_err(|error| {
            error!("Couldn't connect to {}: {:?}", self.uri, error);
            invocation.send_error(rpc::Code::NotFound, "Service connection failed", runtime);
            OakStatus::ErrInternal
        })?;
        grpc_client.ready().await.map_err(|error| {
            error!("Service was not ready: {}", error);
            invocation.send_error(rpc::Code::NotFound, "Service not ready", runtime);
            OakStatus::ErrInternal
        })?;

        let codec = VecCodec::default();
        let path = request.method_name.parse().map_err(|error| {
            error!("Invalid URI {}: {}", request.method_name, error);
            invocation.send_error(rpc::Code::InvalidArgument, "Invalid URI", runtime);
            OakStatus::ErrInternal
        })?;

        // Forward the request to the external gRPC service and wait for the response(s).
        let request = tonic::Request::new(request.req_msg);
        let request_stream =
            request.map(|m| futures_util::stream::once(futures_util::future::ready(m)));
        let mut rsp_stream = grpc_client
            .streaming(request_stream, path, codec)
            .await
            .map_err(|error| {
                error!("Request failed: {}", error);
                invocation.send_error(tonic_code_to_grpc(error.code()), error.message(), runtime);
                OakStatus::ErrInternal
            })?;

        let body_stream = rsp_stream.get_mut();
        loop {
            let message = body_stream.message().await.map_err(|error| {
                error!("Failed to read response: {}", error);
                invocation.send_error(rpc::Code::Internal, "Failed to read response", runtime);
                OakStatus::ErrInternal
            })?;

            if let Some(message) = message {
                let encap_rsp = GrpcResponse {
                    rsp_msg: message,
                    status: None,
                    last: false,
                };
                // Send the response back to the invocation channel.
                debug!("Sending gRPC response: {:?}", encap_rsp);
                invocation
                    .send_response(encap_rsp, &runtime)
                    .map_err(|error| {
                        error!("Couldn't send gRPC response to the invocation: {:?}", error);
                        error
                    })?;
            } else {
                debug!("No message available, close out method invocation");
                break;
            }
        }
        Ok(())
    }

    /// Creates a TLS connection to an external gRPC service.
    async fn connect(
        &self,
    ) -> Result<tonic::client::Grpc<tonic::transport::channel::Channel>, tonic::transport::Error>
    {
        debug!("Connecting to {}", self.uri);

        // Create a TLS configuration.
        let tls_config = ClientTlsConfig::new().ca_certificate(self.root_tls_certificate.clone());

        // Connect to a remote gRPC service.
        let connection = Channel::builder(self.uri.clone())
            .tls_config(tls_config)
            .connect()
            .await?;

        debug!("Connected to {}", self.uri);
        Ok(tonic::client::Grpc::new(connection))
    }
}

/// Oak Node implementation for the gRPC client pseudo-Node.
impl Node for GrpcClientNode {
    fn run(
        self: Box<Self>,
        runtime: RuntimeProxy,
        handle: Handle,
        notify_receiver: oneshot::Receiver<()>,
    ) {
        // Create an Async runtime for executing futures.
        // https://docs.rs/tokio/
        let mut async_runtime = tokio::runtime::Builder::new()
            // Use simple scheduler that runs all tasks on the current-thread.
            // https://docs.rs/tokio/0.2.16/tokio/runtime/index.html#basic-scheduler
            .basic_scheduler()
            // Enables the I/O driver.
            // Necessary for using net, process, signal, and I/O types on the Tokio runtime.
            .enable_io()
            // Enables the time driver.
            // Necessary for creating a Tokio Runtime.
            .enable_time()
            .build()
            .expect("Couldn't create an Async runtime");

        // Listen to incoming gRPC invocations.
        info!(
            "{}: Starting gRPC client pseudo-Node thread",
            self.node_name
        );
        async_runtime.block_on(futures::future::select(
            Box::pin(self.handle_loop(runtime, handle)),
            notify_receiver,
        ));
        info!("{}: Exiting gRPC client pseudo-Node thread", self.node_name);
    }
}

fn tonic_code_to_grpc(code: tonic::Code) -> rpc::Code {
    match code {
        tonic::Code::Ok => rpc::Code::Ok,
        tonic::Code::Cancelled => rpc::Code::Cancelled,
        tonic::Code::Unknown => rpc::Code::Unknown,
        tonic::Code::InvalidArgument => rpc::Code::InvalidArgument,
        tonic::Code::DeadlineExceeded => rpc::Code::DeadlineExceeded,
        tonic::Code::NotFound => rpc::Code::NotFound,
        tonic::Code::AlreadyExists => rpc::Code::AlreadyExists,
        tonic::Code::PermissionDenied => rpc::Code::PermissionDenied,
        tonic::Code::ResourceExhausted => rpc::Code::ResourceExhausted,
        tonic::Code::FailedPrecondition => rpc::Code::FailedPrecondition,
        tonic::Code::Aborted => rpc::Code::Aborted,
        tonic::Code::OutOfRange => rpc::Code::OutOfRange,
        tonic::Code::Unimplemented => rpc::Code::Unimplemented,
        tonic::Code::Internal => rpc::Code::Internal,
        tonic::Code::Unavailable => rpc::Code::Unavailable,
        tonic::Code::DataLoss => rpc::Code::DataLoss,
        tonic::Code::Unauthenticated => rpc::Code::Unauthenticated,
        _ => rpc::Code::Unknown,
    }
}
<commit_msg>runtime: re-use gRPC client connection<commit_after>//
// Copyright 2020 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! gRPC client pseudo-Node functionality.

use crate::{
    io::Receiver,
    node::{
        grpc::{codec::VecCodec, invocation::Invocation},
        ConfigurationError, Node,
    },
    runtime::RuntimeProxy,
};
use log::{debug, error, info, warn};
use oak_abi::{
    proto::{
        google::rpc,
        oak::{application::GrpcClientConfiguration, encap::GrpcResponse},
    },
    Handle, OakStatus,
};
use tokio::sync::oneshot;
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Uri};

/// Struct that represents a gRPC client pseudo-Node.
pub struct GrpcClientNode {
    /// Pseudo-Node name.
    node_name: String,
    /// The URI component of a gRPC server endpoint. Must contain the "Host" element.
    /// https://docs.rs/tonic/0.2.1/tonic/transport/struct.Uri.html
    uri: Uri,
    /// Loaded PEM encoded X.509 TLS root certificate file used to authenticate an external gRPC
    /// service.
    root_tls_certificate: Certificate,
    /// gRPC client to allow re-use of connection across multiple method invocations.
    grpc_client: Option<tonic::client::Grpc<tonic::transport::channel::Channel>>,
}

/// Checks if URI contains the "Host" element.
fn check_uri(uri: &Uri) -> Result<(), ConfigurationError> {
    uri.authority()
        .filter(|authority| !authority.host().is_empty())
        .map(|_| ())
        .ok_or(ConfigurationError::NoHostElement)
}

impl GrpcClientNode {
    /// Creates a new [`GrpcClientNode`] instance, but does not start it.
    pub fn new(
        node_name: &str,
        config: GrpcClientConfiguration,
        root_tls_certificate: Certificate,
    ) -> Result<Self, ConfigurationError> {
        let uri = config.uri.parse().map_err(|error| {
            error!("Error parsing URI {}: {:?}", config.uri, error);
            ConfigurationError::IncorrectURI
        })?;
        check_uri(&uri)?;
        Ok(Self {
            node_name: node_name.to_string(),
            uri,
            root_tls_certificate,
            grpc_client: None,
        })
    }

    /// Main loop that handles gRPC invocations from the `handle`, sends gRPC requests to an
    /// external gRPC service and writes gRPC responses back to the invocation channel.
    async fn handle_loop(
        &mut self,
        runtime: RuntimeProxy,
        handle: Handle,
    ) -> Result<(), OakStatus> {
        // Create a [`Receiver`] used for reading gRPC invocations.
        let receiver = Receiver::<Invocation>::new(handle);
        loop {
            debug!("Waiting for gRPC invocation");
            // Read a gRPC invocation from the [`Receiver`].
            let invocation = receiver.receive(&runtime).map_err(|error| {
                error!("Couldn't receive the invocation: {:?}", error);
                error
            })?;

            let result = self.process_invocation(&runtime, &invocation).await;
            info!("Invocation processing finished: {:?}", result);
            if result.is_err() {
                warn!(
                    "Error encountered; forcing re-connection next time around ({:?})",
                    result
                );
                self.grpc_client = None;
            }
            invocation.close(&runtime);
        }
    }

    /// Process a gRPC method invocation for an external gRPC service.
    async fn process_invocation(
        &mut self,
        runtime: &RuntimeProxy,
        invocation: &Invocation,
    ) -> Result<(), OakStatus> {
        // Receive a request from the invocation channel.
        let request = invocation.receive_request(&runtime).map_err(|error| {
            invocation.send_error(rpc::Code::Internal, "Failed to read request", runtime);
            error!(
                "Couldn't read gRPC request from the invocation: {:?}",
                error
            );
            error
        })?;
        debug!("Incoming gRPC request: {:?}", request);

        if self.grpc_client.is_none() {
            // Connect to an external gRPC service.
            self.grpc_client = Some(self.connect().await.map_err(|error| {
                error!("Couldn't connect to {}: {:?}", self.uri, error);
                invocation.send_error(rpc::Code::NotFound, "Service connection failed", runtime);
                OakStatus::ErrInternal
            })?);
        }
        let grpc_client = self.grpc_client.as_mut().unwrap();
        grpc_client.ready().await.map_err(|error| {
            error!("Service was not ready: {}", error);
            invocation.send_error(rpc::Code::NotFound, "Service not ready", runtime);
            OakStatus::ErrInternal
        })?;

        let codec = VecCodec::default();
        let path = request.method_name.parse().map_err(|error| {
            error!("Invalid URI {}: {}", request.method_name, error);
            invocation.send_error(rpc::Code::InvalidArgument, "Invalid URI", runtime);
            OakStatus::ErrInternal
        })?;

        // Forward the request to the external gRPC service and wait for the response(s).
        let request = tonic::Request::new(request.req_msg);
        let request_stream =
            request.map(|m| futures_util::stream::once(futures_util::future::ready(m)));
        let mut rsp_stream = match grpc_client.streaming(request_stream, path, codec).await {
            Ok(rsp_stream) => rsp_stream,
            Err(error) => {
                error!("Request to remote service failed: {}", error);
                invocation.send_error(tonic_code_to_grpc(error.code()), error.message(), runtime);
                return Ok(());
            }
        };

        let body_stream = rsp_stream.get_mut();
        loop {
            let message = body_stream.message().await.map_err(|error| {
                error!("Failed to read response: {}", error);
                invocation.send_error(rpc::Code::Internal, "Failed to read response", runtime);
                OakStatus::ErrInternal
            })?;

            if let Some(message) = message {
                let encap_rsp = GrpcResponse {
                    rsp_msg: message,
                    status: None,
                    last: false,
                };
                // Send the response back to the invocation channel.
                debug!("Sending gRPC response: {:?}", encap_rsp);
                invocation
                    .send_response(encap_rsp, &runtime)
                    .map_err(|error| {
                        error!("Couldn't send gRPC response to the invocation: {:?}", error);
                        error
                    })?;
            } else {
                debug!("No message available, close out method invocation");
                break;
            }
        }

        Ok(())
    }

    /// Creates a TLS connection to an external gRPC service.
    async fn connect(
        &self,
    ) -> Result<tonic::client::Grpc<tonic::transport::channel::Channel>, tonic::transport::Error>
    {
        debug!("Connecting to {}", self.uri);

        // Create a TLS configuration.
        let tls_config = ClientTlsConfig::new().ca_certificate(self.root_tls_certificate.clone());

        // Connect to a remote gRPC service.
        let connection = Channel::builder(self.uri.clone())
            .tls_config(tls_config)
            .connect()
            .await?;

        debug!("Connected to {}", self.uri);
        Ok(tonic::client::Grpc::new(connection))
    }
}

/// Oak Node implementation for the gRPC client pseudo-Node.
impl Node for GrpcClientNode {
    fn run(
        mut self: Box<Self>,
        runtime: RuntimeProxy,
        handle: Handle,
        notify_receiver: oneshot::Receiver<()>,
    ) {
        // Create an Async runtime for executing futures.
        // https://docs.rs/tokio/
        let mut async_runtime = tokio::runtime::Builder::new()
            // Use simple scheduler that runs all tasks on the current-thread.
            // https://docs.rs/tokio/0.2.16/tokio/runtime/index.html#basic-scheduler
            .basic_scheduler()
            // Enables the I/O driver.
            // Necessary for using net, process, signal, and I/O types on the Tokio runtime.
            .enable_io()
            // Enables the time driver.
            // Necessary for creating a Tokio Runtime.
            .enable_time()
            .build()
            .expect("Couldn't create an Async runtime");

        // Listen to incoming gRPC invocations.
        info!(
            "{}: Starting gRPC client pseudo-Node thread",
            self.node_name
        );
        async_runtime.block_on(futures::future::select(
            Box::pin(self.handle_loop(runtime, handle)),
            notify_receiver,
        ));
        info!("{}: Exiting gRPC client pseudo-Node thread", self.node_name);
    }
}

fn tonic_code_to_grpc(code: tonic::Code) -> rpc::Code {
    match code {
        tonic::Code::Ok => rpc::Code::Ok,
        tonic::Code::Cancelled => rpc::Code::Cancelled,
        tonic::Code::Unknown => rpc::Code::Unknown,
        tonic::Code::InvalidArgument => rpc::Code::InvalidArgument,
        tonic::Code::DeadlineExceeded => rpc::Code::DeadlineExceeded,
        tonic::Code::NotFound => rpc::Code::NotFound,
        tonic::Code::AlreadyExists => rpc::Code::AlreadyExists,
        tonic::Code::PermissionDenied => rpc::Code::PermissionDenied,
        tonic::Code::ResourceExhausted => rpc::Code::ResourceExhausted,
        tonic::Code::FailedPrecondition => rpc::Code::FailedPrecondition,
        tonic::Code::Aborted => rpc::Code::Aborted,
        tonic::Code::OutOfRange => rpc::Code::OutOfRange,
        tonic::Code::Unimplemented => rpc::Code::Unimplemented,
        tonic::Code::Internal => rpc::Code::Internal,
        tonic::Code::Unavailable => rpc::Code::Unavailable,
        tonic::Code::DataLoss => rpc::Code::DataLoss,
        tonic::Code::Unauthenticated => rpc::Code::Unauthenticated,
        _ => rpc::Code::Unknown,
    }
}
<|endoftext|>


<commit_before>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a collection of block devices.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use devicemapper::{Bytes, Device, Sectors, Segment};
use time::Timespec;
use uuid::Uuid;

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, MIN_MDA_SECTORS, StaticHeader, validate_mda_size};
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi);

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    let mut devices = HashSet::new();
    for path in paths {
        devices.insert(try!(Device::from_str(&path.to_string_lossy())));
    }
    Ok(devices)
}

#[derive(Debug)]
pub struct BlockDevMgr {
    block_devs: Vec<BlockDev>,
}

impl BlockDevMgr {
    pub fn new(block_devs: Vec<BlockDev>) -> BlockDevMgr {
        BlockDevMgr { block_devs: block_devs }
    }

    /// Initialize a new BlockDevMgr with specified pool and devices.
    pub fn initialize(pool_uuid: &PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<BlockDevMgr> {
        let devices = try!(resolve_devices(paths));
        Ok(BlockDevMgr::new(try!(initialize(pool_uuid, devices, mda_size, force))))
    }

    /// Obtain a BlockDev by its Device.
    pub fn get_by_device(&self, device: Device) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.device() == &device)
    }

    // Obtain a BlockDev by its UUID.
    pub fn get_by_uuid(&self, uuid: &DevUuid) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.uuid() == uuid)
    }

    pub fn add(&mut self,
               pool_uuid: &PoolUuid,
               paths: &[&Path],
               force: bool)
               -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.push(bd);
        }
        Ok(bdev_paths)
    }

    pub fn destroy_all(mut self) -> EngineResult<()> {
        for bd in self.block_devs.drain(..) {
            try!(bd.wipe_metadata());
        }
        Ok(())
    }

    // Unused space left on blockdevs
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// If available space is less than size, return None, else return
    /// the segments allocated.
    pub fn alloc_space(&mut self, size: Sectors) -> Option<Vec<Segment>> {
        let mut needed: Sectors = size;
        let mut segs = Vec::new();

        if self.avail_space() < size {
            return None;
        }

        for mut bd in self.block_devs.iter_mut() {
            if needed == Sectors(0) {
                break;
            }

            let (gotten, r_segs) = bd.request_space(needed);
            segs.extend(r_segs);
            needed = needed - gotten;
        }

        assert_eq!(needed, Sectors(0));

        Some(segs)
    }

    pub fn devnodes(&self) -> Vec<PathBuf> {
        self.block_devs
            .iter()
            .map(|d| d.devnode.clone())
            .collect()
    }

    /// Write the given data to all blockdevs marking with specified time.
    // TODO: Cap # of blockdevs written to, as described in SWDD
    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        // TODO: Do something better than panic when saving to blockdev fails.
        // Panic can occur for a the usual IO reasons, but also:
        // 1. If the timestamp is older than a previously written timestamp.
        // 2. If the variable length metadata is too large.
        for mut bd in self.block_devs.iter_mut() {
            bd.save_state(time, metadata).unwrap();
        }
        Ok(())
    }
}

impl Recordable<HashMap<String, BlockDevSave>> for BlockDevMgr {
    fn record(&self) -> EngineResult<HashMap<String, BlockDevSave>> {
        self.block_devs
            .iter()
            .map(|bd| {
                     bd.record()
                         .and_then(|bdsave| Ok((bd.uuid().simple().to_string(), bdsave)))
                 })
            .collect()
    }
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {

    /// Get device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the device's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    pub fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            EngineError::Engine(ErrorEnum::NotFound,
                                format!("could not get device node from dev {}", dev.dstr()))
        }));

        let mut f = try!(OpenOptions::new().read(true).write(true).open(&devnode));
        let dev_size = try!(blkdev_size(&f));
        let ownership = try!(StaticHeader::determine_ownership(&mut f));

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let err_str = format!("Device {} appears to belong to another application",
                                              devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, err_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        // Already in this pool (according to its header)
                        // TODO: Check we already know about it
                        // if yes, ignore. If no, add it w/o initializing?
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    let mut bds: Vec<BlockDev> = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = BDA::initialize(&mut f,
                                  pool_uuid,
                                  &Uuid::new_v4(),
                                  mda_size,
                                  dev_size.sectors());
        if bda.is_err() {
            let mut unerased_devnodes = Vec::new();
            BDA::wipe(&mut f).unwrap_or_else(|_| unerased_devnodes.push(devnode.clone()));
            for bd in bds.drain(..) {
                let bd_devnode = bd.devnode.clone();
                bd.wipe_metadata()
                    .unwrap_or_else(|_| unerased_devnodes.push(bd_devnode));
            }

            let err_msg = format!("Failed to initialize {:?}", devnode);
            if unerased_devnodes.is_empty() {
                return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
            } else {
                let err_msg = format!("{}, then failed to wipe already initialized devnodes: {:?}",
                                      err_msg,
                                      unerased_devnodes);
                return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
            }
        }

        let bda = bda.expect("!bda.is_err()");
        let allocator = RangeAllocator::new(bda.dev_size(), &[(Sectors(0), bda.size())])
            .expect("bda.size() < bda.dev_size() and single range");

        bds.push(BlockDev::new(dev, devnode, bda, allocator));
    }
    Ok(bds)
}
<commit_msg>Take advantage of FromIterator trait for iters of Results<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Code to handle a collection of block devices.

use std::io;
use std::collections::{HashMap, HashSet};
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::str::FromStr;

use devicemapper::{Bytes, Device, Sectors, Segment};
use time::Timespec;
use uuid::Uuid;

use super::super::consts::IEC;
use super::super::errors::{EngineError, EngineResult, ErrorEnum};
use super::super::types::{DevUuid, PoolUuid};

use super::blockdev::BlockDev;
use super::device::blkdev_size;
use super::engine::DevOwnership;
use super::metadata::{BDA, MIN_MDA_SECTORS, StaticHeader, validate_mda_size};
use super::range_alloc::RangeAllocator;
use super::serde_structs::{BlockDevSave, Recordable};

const MIN_DEV_SIZE: Bytes = Bytes(IEC::Gi);

/// Resolve a list of Paths of some sort to a set of unique Devices.
/// Return an IOError if there was a problem resolving any particular device.
pub fn resolve_devices(paths: &[&Path]) -> io::Result<HashSet<Device>> {
    paths
        .iter()
        .map(|p| Device::from_str(&p.to_string_lossy()))
        .collect()
}

#[derive(Debug)]
pub struct BlockDevMgr {
    block_devs: Vec<BlockDev>,
}

impl BlockDevMgr {
    pub fn new(block_devs: Vec<BlockDev>) -> BlockDevMgr {
        BlockDevMgr { block_devs: block_devs }
    }

    /// Initialize a new BlockDevMgr with specified pool and devices.
    pub fn initialize(pool_uuid: &PoolUuid,
                      paths: &[&Path],
                      mda_size: Sectors,
                      force: bool)
                      -> EngineResult<BlockDevMgr> {
        let devices = try!(resolve_devices(paths));
        Ok(BlockDevMgr::new(try!(initialize(pool_uuid, devices, mda_size, force))))
    }

    /// Obtain a BlockDev by its Device.
    pub fn get_by_device(&self, device: Device) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.device() == &device)
    }

    // Obtain a BlockDev by its UUID.
    pub fn get_by_uuid(&self, uuid: &DevUuid) -> Option<&BlockDev> {
        self.block_devs.iter().find(|d| d.uuid() == uuid)
    }

    pub fn add(&mut self,
               pool_uuid: &PoolUuid,
               paths: &[&Path],
               force: bool)
               -> EngineResult<Vec<PathBuf>> {
        let devices = try!(resolve_devices(paths));
        let bds = try!(initialize(pool_uuid, devices, MIN_MDA_SECTORS, force));
        let bdev_paths = bds.iter().map(|p| p.devnode.clone()).collect();
        for bd in bds {
            self.block_devs.push(bd);
        }
        Ok(bdev_paths)
    }

    pub fn destroy_all(mut self) -> EngineResult<()> {
        for bd in self.block_devs.drain(..) {
            try!(bd.wipe_metadata());
        }
        Ok(())
    }

    // Unused space left on blockdevs
    pub fn avail_space(&self) -> Sectors {
        self.block_devs.iter().map(|bd| bd.available()).sum()
    }

    /// If available space is less than size, return None, else return
    /// the segments allocated.
    pub fn alloc_space(&mut self, size: Sectors) -> Option<Vec<Segment>> {
        let mut needed: Sectors = size;
        let mut segs = Vec::new();

        if self.avail_space() < size {
            return None;
        }

        for mut bd in self.block_devs.iter_mut() {
            if needed == Sectors(0) {
                break;
            }

            let (gotten, r_segs) = bd.request_space(needed);
            segs.extend(r_segs);
            needed = needed - gotten;
        }

        assert_eq!(needed, Sectors(0));

        Some(segs)
    }

    pub fn devnodes(&self) -> Vec<PathBuf> {
        self.block_devs
            .iter()
            .map(|d| d.devnode.clone())
            .collect()
    }

    /// Write the given data to all blockdevs marking with specified time.
    // TODO: Cap # of blockdevs written to, as described in SWDD
    pub fn save_state(&mut self, time: &Timespec, metadata: &[u8]) -> EngineResult<()> {
        // TODO: Do something better than panic when saving to blockdev fails.
        // Panic can occur for a the usual IO reasons, but also:
        // 1. If the timestamp is older than a previously written timestamp.
        // 2. If the variable length metadata is too large.
        for mut bd in self.block_devs.iter_mut() {
            bd.save_state(time, metadata).unwrap();
        }
        Ok(())
    }
}

impl Recordable<HashMap<String, BlockDevSave>> for BlockDevMgr {
    fn record(&self) -> EngineResult<HashMap<String, BlockDevSave>> {
        self.block_devs
            .iter()
            .map(|bd| {
                     bd.record()
                         .and_then(|bdsave| Ok((bd.uuid().simple().to_string(), bdsave)))
                 })
            .collect()
    }
}

/// Initialize multiple blockdevs at once. This allows all of them
/// to be checked for usability before writing to any of them.
pub fn initialize(pool_uuid: &PoolUuid,
                  devices: HashSet<Device>,
                  mda_size: Sectors,
                  force: bool)
                  -> EngineResult<Vec<BlockDev>> {

    /// Get device information, returns an error if problem with obtaining
    /// that information.
    /// Returns a tuple with the device's path, its size in bytes,
    /// its ownership as determined by calling determine_ownership(),
    /// and an open File handle, all of which are needed later.
    pub fn dev_info(dev: &Device) -> EngineResult<(PathBuf, Bytes, DevOwnership, File)> {
        let devnode = try!(dev.devnode().ok_or_else(|| {
            EngineError::Engine(ErrorEnum::NotFound,
                                format!("could not get device node from dev {}", dev.dstr()))
        }));

        let mut f = try!(OpenOptions::new().read(true).write(true).open(&devnode));
        let dev_size = try!(blkdev_size(&f));
        let ownership = try!(StaticHeader::determine_ownership(&mut f));

        Ok((devnode, dev_size, ownership, f))
    }

    /// Filter devices for admission to pool based on dev_infos.
    /// If there is an error finding out the info, return that error.
    /// Also, return an error if a device is not appropriate for this pool.
    fn filter_devs<I>(dev_infos: I,
                      pool_uuid: &PoolUuid,
                      force: bool)
                      -> EngineResult<Vec<(Device, (PathBuf, Bytes, File))>>
        where I: Iterator<Item = (Device, EngineResult<(PathBuf, Bytes, DevOwnership, File)>)>
    {
        let mut add_devs = Vec::new();
        for (dev, dev_result) in dev_infos {
            let (devnode, dev_size, ownership, f) = try!(dev_result);
            if dev_size < MIN_DEV_SIZE {
                let error_message = format!("{} too small, minimum {} bytes",
                                            devnode.display(),
                                            MIN_DEV_SIZE);
                return Err(EngineError::Engine(ErrorEnum::Invalid, error_message));
            };
            match ownership {
                DevOwnership::Unowned => add_devs.push((dev, (devnode, dev_size, f))),
                DevOwnership::Theirs => {
                    if !force {
                        let err_str = format!("Device {} appears to belong to another application",
                                              devnode.display());
                        return Err(EngineError::Engine(ErrorEnum::Invalid, err_str));
                    } else {
                        add_devs.push((dev, (devnode, dev_size, f)))
                    }
                }
                DevOwnership::Ours(uuid) => {
                    if *pool_uuid != uuid {
                        let error_str = format!("Device {} already belongs to Stratis pool {}",
                                                devnode.display(),
                                                uuid);
                        return Err(EngineError::Engine(ErrorEnum::Invalid, error_str));
                    } else {
                        // Already in this pool (according to its header)
                        // TODO: Check we already know about it
                        // if yes, ignore. If no, add it w/o initializing?
                    }
                }
            }
        }
        Ok(add_devs)
    }

    try!(validate_mda_size(mda_size));

    let dev_infos = devices.into_iter().map(|d: Device| (d, dev_info(&d)));

    let add_devs = try!(filter_devs(dev_infos, pool_uuid, force));

    let mut bds: Vec<BlockDev> = Vec::new();
    for (dev, (devnode, dev_size, mut f)) in add_devs {

        let bda = BDA::initialize(&mut f,
                                  pool_uuid,
                                  &Uuid::new_v4(),
                                  mda_size,
                                  dev_size.sectors());
        if bda.is_err() {
            let mut unerased_devnodes = Vec::new();
            BDA::wipe(&mut f).unwrap_or_else(|_| unerased_devnodes.push(devnode.clone()));
            for bd in bds.drain(..) {
                let bd_devnode = bd.devnode.clone();
                bd.wipe_metadata()
                    .unwrap_or_else(|_| unerased_devnodes.push(bd_devnode));
            }

            let err_msg = format!("Failed to initialize {:?}", devnode);
            if unerased_devnodes.is_empty() {
                return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
            } else {
                let err_msg = format!("{}, then failed to wipe already initialized devnodes: {:?}",
                                      err_msg,
                                      unerased_devnodes);
                return Err(EngineError::Engine(ErrorEnum::Error, err_msg));
            }
        }

        let bda = bda.expect("!bda.is_err()");
        let allocator = RangeAllocator::new(bda.dev_size(), &[(Sectors(0), bda.size())])
            .expect("bda.size() < bda.dev_size() and single range");

        bds.push(BlockDev::new(dev, devnode, bda, allocator));
    }
    Ok(bds)
}
<|endoftext|>


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

/// Methods present on all expressions, except tuples
pub trait ExpressionMethods: Expression + Sized {
    /// Creates a SQL `=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.eq("Sean"));
    /// assert_eq!(Ok(1), data.first(&connection));
    /// # }
    /// ```
    fn eq<T>(self, other: T) -> Eq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Eq::new(self, other.as_expression())
    }

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

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

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

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

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

    /// Creates a SQL `>` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.gt(1))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Tess", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn gt<T>(self, other: T) -> Gt<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Gt::new(self, other.as_expression())
    }

    /// Creates a SQL `>=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.ge(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Tess", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn ge<T>(self, other: T) -> GtEq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        GtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `<` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.lt(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Sean", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn lt<T>(self, other: T) -> Lt<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Lt::new(self, other.as_expression())
    }

    /// Creates a SQL `<=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.le(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Sean", data);
    /// #     Ok(())
    /// # }
    fn le<T>(self, other: T) -> LtEq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        LtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `BETWEEN` expression using the given lower and upper
    /// bounds.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.between(2, 6))
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("dog".to_string()), data);
    /// # }
    /// ```
    fn between<T, U>(self, lower: T, upper: U) -> Between<Self, And<T::Expression, U::Expression>>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
        U: AsExpression<Self::SqlType>,
    {
        Between::new(self, And::new(lower.as_expression(), upper.as_expression()))
    }

    /// Creates a SQL `NOT BETWEEN` expression using the given lower and upper
    /// bounds.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.not_between(2, 6))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("spider", data);
    /// #     Ok(())
    /// # }
    fn not_between<T, U>(
        self,
        lower: T,
        upper: U,
    ) -> NotBetween<Self, And<T::Expression, U::Expression>>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
        U: AsExpression<Self::SqlType>,
    {
        NotBetween::new(self, And::new(lower.as_expression(), upper.as_expression()))
    }

    /// Creates a SQL `DESC` expression, representing this expression in
    /// descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let names = users
    ///     .select(name)
    ///     .order(name.desc())
    ///     .load::<String>(&connection)?;
    /// assert_eq!(vec!["Tess", "Sean"], names);
    /// #     Ok(())
    /// # }
    /// ```
    fn desc(self) -> Desc<Self> {
        Desc::new(self)
    }

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

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

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

impl<T: Expression> NullableExpressionMethods for T {}
<commit_msg>Clarify `eq_any` caching behavior<commit_after>use crate::expression::array_comparison::{AsInExpression, In, NotIn};
use crate::expression::operators::*;
use crate::expression::{nullable, AsExpression, Expression};
use crate::sql_types::{SingleValue, SqlType};

/// Methods present on all expressions, except tuples
pub trait ExpressionMethods: Expression + Sized {
    /// Creates a SQL `=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users.select(id).filter(name.eq("Sean"));
    /// assert_eq!(Ok(1), data.first(&connection));
    /// # }
    /// ```
    fn eq<T>(self, other: T) -> Eq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Eq::new(self, other.as_expression())
    }

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

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

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

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

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

    /// Creates a SQL `>` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.gt(1))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Tess", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn gt<T>(self, other: T) -> Gt<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Gt::new(self, other.as_expression())
    }

    /// Creates a SQL `>=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.ge(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Tess", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn ge<T>(self, other: T) -> GtEq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        GtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `<` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.lt(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Sean", data);
    /// #     Ok(())
    /// # }
    /// ```
    fn lt<T>(self, other: T) -> Lt<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        Lt::new(self, other.as_expression())
    }

    /// Creates a SQL `<=` expression.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// let data = users
    ///     .select(name)
    ///     .filter(id.le(2))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("Sean", data);
    /// #     Ok(())
    /// # }
    fn le<T>(self, other: T) -> LtEq<Self, T::Expression>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
    {
        LtEq::new(self, other.as_expression())
    }

    /// Creates a SQL `BETWEEN` expression using the given lower and upper
    /// bounds.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.between(2, 6))
    ///     .first(&connection);
    /// #
    /// assert_eq!(Ok("dog".to_string()), data);
    /// # }
    /// ```
    fn between<T, U>(self, lower: T, upper: U) -> Between<Self, And<T::Expression, U::Expression>>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
        U: AsExpression<Self::SqlType>,
    {
        Between::new(self, And::new(lower.as_expression(), upper.as_expression()))
    }

    /// Creates a SQL `NOT BETWEEN` expression using the given lower and upper
    /// bounds.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::animals::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let data = animals
    ///     .select(species)
    ///     .filter(legs.not_between(2, 6))
    ///     .first::<String>(&connection)?;
    /// assert_eq!("spider", data);
    /// #     Ok(())
    /// # }
    fn not_between<T, U>(
        self,
        lower: T,
        upper: U,
    ) -> NotBetween<Self, And<T::Expression, U::Expression>>
    where
        Self::SqlType: SqlType,
        T: AsExpression<Self::SqlType>,
        U: AsExpression<Self::SqlType>,
    {
        NotBetween::new(self, And::new(lower.as_expression(), upper.as_expression()))
    }

    /// Creates a SQL `DESC` expression, representing this expression in
    /// descending order.
    ///
    /// # Example
    ///
    /// ```rust
    /// # include!("../doctest_setup.rs");
    /// #
    /// # fn main() {
    /// #     run_test().unwrap();
    /// # }
    /// #
    /// # fn run_test() -> QueryResult<()> {
    /// #     use schema::users::dsl::*;
    /// #     let connection = establish_connection();
    /// #
    /// let names = users
    ///     .select(name)
    ///     .order(name.desc())
    ///     .load::<String>(&connection)?;
    /// assert_eq!(vec!["Tess", "Sean"], names);
    /// #     Ok(())
    /// # }
    /// ```
    fn desc(self) -> Desc<Self> {
        Desc::new(self)
    }

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

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

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

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


<commit_before>use ::cairo;
use ::cairo_sys;
use ::glib_sys;
use ::glib::translate::*;
use ::libc;

use color::*;
use error::*;
use opacity::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_free (state: *mut RsvgState);
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity (state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_free (state: *mut RsvgState) {
    unsafe { rsvg_state_free (state); }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            Ok (None)
        } else {
            Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
        }
    }
}

pub fn state_get_stop_opacity (state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity (state);

        if opacity_ptr.is_null () {
            Ok (None)
        } else {
            Opacity::from_opacity_spec (&*opacity_ptr).map (|opacity| Some (opacity))
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color (state) };

    Color::from (argb)
}
<commit_msg>drawing_ctx.rs: Bind rsvg_render_surface()<commit_after>use ::cairo;
use ::cairo_sys;
use ::glib_sys;
use ::glib::translate::*;
use ::libc;

use color::*;
use error::*;
use opacity::*;
use node::RsvgNode;
use node::NodeType;
use path_builder::RsvgPathBuilder;
use state::RsvgState;

pub enum RsvgDrawingCtx {}

extern "C" {
    fn rsvg_drawing_ctx_get_dpi (draw_ctx: *const RsvgDrawingCtx,
                                 out_dpi_x: *mut f64,
                                 out_dpi_y: *mut f64);

    fn rsvg_drawing_ctx_get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64;

    fn rsvg_drawing_ctx_get_view_box_size (draw_ctx: *const RsvgDrawingCtx,
                                           out_x: *mut f64,
                                           out_y: *mut f64);

    fn rsvg_drawing_ctx_push_view_box (draw_ctx: *const RsvgDrawingCtx,
                                       width:     f64,
                                       height:    f64);

    fn rsvg_drawing_ctx_pop_view_box (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_drawing_ctx_acquire_node (draw_ctx: *const RsvgDrawingCtx,
                                      url:      *const libc::c_char) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                                              url:       *const libc::c_char,
                                              node_type: NodeType) -> *mut RsvgNode;

    fn rsvg_drawing_ctx_release_node (draw_ctx: *const RsvgDrawingCtx,
                                      node:     *mut RsvgNode);

    fn rsvg_drawing_ctx_get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix;

    fn rsvg_drawing_ctx_set_current_state_affine (draw_ctx: *const RsvgDrawingCtx,
                                                  affine:   *const cairo::Matrix);

    fn rsvg_drawing_ctx_add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                                           x: f64,
                                           y: f64,
                                           w: f64,
                                           h: f64);

    fn rsvg_drawing_ctx_draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                                              node:     *const RsvgNode,
                                              dominate: i32);

    fn rsvg_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState;
    fn rsvg_state_new () -> *mut RsvgState;
    fn rsvg_state_free (state: *mut RsvgState);
    fn rsvg_state_reinit (state: *mut RsvgState);
    fn rsvg_state_reconstruct (state: *mut RsvgState, node: *const RsvgNode);
    fn rsvg_state_is_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_has_overflow (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_cond_true (state: *const RsvgState) -> glib_sys::gboolean;
    fn rsvg_state_get_stop_color (state: *const RsvgState) -> *const ColorSpec;
    fn rsvg_state_get_stop_opacity (state: *const RsvgState) -> *const OpacitySpec;
    fn rsvg_state_get_current_color (state: *const RsvgState) -> u32;

    fn rsvg_state_push (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_state_pop (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                                 state: *mut RsvgState,
                                 dominate: libc::c_int);

    fn rsvg_push_discrete_layer (draw_ctx: *const RsvgDrawingCtx);
    fn rsvg_pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx);

    fn rsvg_render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                                 builder: *const RsvgPathBuilder);
    fn rsvg_render_surface (draw_ctx: *const RsvgDrawingCtx,
                            surface: *const cairo_sys::cairo_surface_t,
                            x: f64,
                            y: f64,
                            w: f64,
                            h: f64);

    fn rsvg_cairo_get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> *mut cairo_sys::cairo_t;
    fn rsvg_cairo_set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: *const cairo_sys::cairo_t);
}

pub fn get_dpi (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut dpi_x: f64 = 0.0;
    let mut dpi_y: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_dpi (draw_ctx, &mut dpi_x, &mut dpi_y); }

    (dpi_x, dpi_y)
}

pub fn get_normalized_font_size (draw_ctx: *const RsvgDrawingCtx) -> f64 {
    unsafe { rsvg_drawing_ctx_get_normalized_font_size (draw_ctx) }
}

pub fn get_view_box_size (draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
    let mut w: f64 = 0.0;
    let mut h: f64 = 0.0;

    unsafe { rsvg_drawing_ctx_get_view_box_size (draw_ctx, &mut w, &mut h); }

    (w, h)
}

pub fn push_view_box (draw_ctx: *const RsvgDrawingCtx,
                      width:     f64,
                      height:    f64)
{
    unsafe { rsvg_drawing_ctx_push_view_box (draw_ctx, width, height); }
}

pub fn pop_view_box (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_drawing_ctx_pop_view_box (draw_ctx); }
}

pub fn acquire_node (draw_ctx: *const RsvgDrawingCtx,
                     url:      &str) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node (draw_ctx, str::to_glib_none (url).0) }
}

pub fn acquire_node_of_type (draw_ctx:  *const RsvgDrawingCtx,
                             url:       &str,
                             node_type: NodeType) -> *mut RsvgNode {
    unsafe { rsvg_drawing_ctx_acquire_node_of_type (draw_ctx, str::to_glib_none (url).0, node_type) }
}

pub fn release_node (draw_ctx: *const RsvgDrawingCtx,
                     node:     *mut RsvgNode) {
    unsafe { rsvg_drawing_ctx_release_node (draw_ctx, node); }
}

pub fn state_reinherit_top (draw_ctx: *const RsvgDrawingCtx,
                            state: *mut RsvgState,
                            dominate: i32) {
    unsafe { rsvg_state_reinherit_top (draw_ctx, state, dominate); }
}

pub fn push_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_push_discrete_layer (draw_ctx); }
}

pub fn pop_discrete_layer (draw_ctx: *const RsvgDrawingCtx) {
    unsafe { rsvg_pop_discrete_layer (draw_ctx); }
}

pub fn render_path_builder (draw_ctx: *const RsvgDrawingCtx,
                            builder: &RsvgPathBuilder) {
    unsafe { rsvg_render_path_builder (draw_ctx, builder); }
}

pub fn render_surface (draw_ctx: *const RsvgDrawingCtx,
                       surface: &cairo::ImageSurface,
                       x: f64,
                       y: f64,
                       w: f64,
                       h: f64) {
    unsafe { rsvg_render_surface (draw_ctx, surface.to_raw_none(), x, y, w, h); }
}

pub fn get_cairo_context (draw_ctx: *const RsvgDrawingCtx) -> cairo::Context {
    unsafe {
        let raw_cr = rsvg_cairo_get_cairo_context (draw_ctx);

        let cr = cairo::Context::from_glib_none (raw_cr);

        cr
    }
}

pub fn set_cairo_context (draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) {
    unsafe {
        let raw_cr = cr.to_glib_none ().0;

        rsvg_cairo_set_cairo_context (draw_ctx, raw_cr);
    }
}

pub fn get_current_state_affine (draw_ctx: *const RsvgDrawingCtx) -> cairo::Matrix {
    unsafe {
        rsvg_drawing_ctx_get_current_state_affine (draw_ctx)
    }
}

pub fn set_current_state_affine (draw_ctx: *const RsvgDrawingCtx, affine: cairo::Matrix) {
    unsafe {
        rsvg_drawing_ctx_set_current_state_affine (draw_ctx, &affine);
    }
}

pub fn add_clipping_rect (draw_ctx: *const RsvgDrawingCtx,
                          x: f64,
                          y: f64,
                          w: f64,
                          h: f64) {
    unsafe { rsvg_drawing_ctx_add_clipping_rect (draw_ctx, x, y, w, h); }
}

pub fn draw_node_from_stack (draw_ctx: *const RsvgDrawingCtx,
                             node:     *const RsvgNode,
                             dominate: i32) {
    unsafe { rsvg_drawing_ctx_draw_node_from_stack (draw_ctx, node, dominate); }
}

pub fn get_current_state (draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgState {
    unsafe { rsvg_current_state (draw_ctx) }
}

pub fn state_new () -> *mut RsvgState {
    unsafe { rsvg_state_new () }
}

pub fn state_free (state: *mut RsvgState) {
    unsafe { rsvg_state_free (state); }
}

pub fn state_reinit (state: *mut RsvgState) {
    unsafe { rsvg_state_reinit (state); }
}

pub fn state_reconstruct (state: *mut RsvgState, node: *const RsvgNode) {
    unsafe { rsvg_state_reconstruct (state, node); }
}

pub fn state_is_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_is_overflow (state)) }
}

pub fn state_has_overflow (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_has_overflow (state)) }
}

pub fn state_get_cond_true (state: *const RsvgState) -> bool {
    unsafe { from_glib (rsvg_state_get_cond_true (state)) }
}

pub fn state_push (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_push (draw_ctx);
    }
}

pub fn state_pop (draw_ctx: *const RsvgDrawingCtx) {
    unsafe {
        rsvg_state_pop (draw_ctx);
    }
}

pub fn state_get_stop_color (state: *const RsvgState) -> Result<Option<Color>, AttributeError> {
    unsafe {
        let spec_ptr = rsvg_state_get_stop_color (state);

        if spec_ptr.is_null () {
            Ok (None)
        } else {
            Color::from_color_spec (&*spec_ptr).map (|color| Some (color))
        }
    }
}

pub fn state_get_stop_opacity (state: *const RsvgState) -> Result<Option<Opacity>, AttributeError> {
    unsafe {
        let opacity_ptr = rsvg_state_get_stop_opacity (state);

        if opacity_ptr.is_null () {
            Ok (None)
        } else {
            Opacity::from_opacity_spec (&*opacity_ptr).map (|opacity| Some (opacity))
        }
    }
}

pub fn state_get_current_color (state: *const RsvgState) -> Color {
    let argb = unsafe { rsvg_state_get_current_color (state) };

    Color::from (argb)
}
<|endoftext|>