<commit_before>use std::collections::BTreeMap;
use serde_json;

pub mod legacy;

pub use self::legacy::*;

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ClaimsV2 {
    #[serde(flatten)]
    pub registered: RegisteredClaims,
    #[serde(flatten)]
    pub private: BTreeMap<String, serde_json::Value>,
}

pub type SecondsSinceEpoch = u64;

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct RegisteredClaims {
    #[serde(rename="iss", skip_serializing_if = "Option::is_none")]
    pub issuer: Option<String>,

    #[serde(rename="sub", skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,

    #[serde(rename="aud", skip_serializing_if = "Option::is_none")]
    pub audience: Option<String>,

    #[serde(rename="exp", skip_serializing_if = "Option::is_none")]
    pub expiration: Option<SecondsSinceEpoch>,

    #[serde(rename="nbf", skip_serializing_if = "Option::is_none")]
    pub not_before: Option<SecondsSinceEpoch>,

    #[serde(rename="nbf", skip_serializing_if = "Option::is_none")]
    pub issued_at: Option<SecondsSinceEpoch>,

    #[serde(rename="jti", skip_serializing_if = "Option::is_none")]
    pub json_web_token_id: Option<String>,
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use crate::claims::ClaimsV2;
    use crate::Component;
    use serde_json::Value;

    // {"iss":"mikkyang.com","exp":1302319100,"custom_claim":true}
    const ENCODED_PAYLOAD: &'static str = "eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";

    #[test]
    fn registered_claims() {
        let claims = ClaimsV2::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.registered.issuer.unwrap(), "mikkyang.com");
        assert_eq!(claims.registered.expiration.unwrap(), 1302319100);
    }

    #[test]
    fn private_claims() {
        let claims = ClaimsV2::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.private["custom_claim"], Value::Bool(true));
    }

    #[test]
    fn roundtrip() {
        let mut claims: ClaimsV2 = Default::default();
        claims.registered.issuer = Some("mikkyang.com".into());
        claims.registered.expiration = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, ClaimsV2::from_base64(&*enc).unwrap());
    }
}
<commit_msg>Add new function<commit_after>use std::collections::BTreeMap;
use serde_json;

pub mod legacy;

pub use self::legacy::*;

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ClaimsV2 {
    #[serde(flatten)]
    pub registered: RegisteredClaims,
    #[serde(flatten)]
    pub private: BTreeMap<String, serde_json::Value>,
}

impl ClaimsV2 {
    pub fn new(registered: RegisteredClaims) -> Self {
        ClaimsV2 {
            registered,
            private: BTreeMap::new(),
        }
    }
}

pub type SecondsSinceEpoch = u64;

#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct RegisteredClaims {
    #[serde(rename="iss", skip_serializing_if = "Option::is_none")]
    pub issuer: Option<String>,

    #[serde(rename="sub", skip_serializing_if = "Option::is_none")]
    pub subject: Option<String>,

    #[serde(rename="aud", skip_serializing_if = "Option::is_none")]
    pub audience: Option<String>,

    #[serde(rename="exp", skip_serializing_if = "Option::is_none")]
    pub expiration: Option<SecondsSinceEpoch>,

    #[serde(rename="nbf", skip_serializing_if = "Option::is_none")]
    pub not_before: Option<SecondsSinceEpoch>,

    #[serde(rename="nbf", skip_serializing_if = "Option::is_none")]
    pub issued_at: Option<SecondsSinceEpoch>,

    #[serde(rename="jti", skip_serializing_if = "Option::is_none")]
    pub json_web_token_id: Option<String>,
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use crate::claims::ClaimsV2;
    use crate::Component;
    use serde_json::Value;

    // {"iss":"mikkyang.com","exp":1302319100,"custom_claim":true}
    const ENCODED_PAYLOAD: &'static str = "eyJpc3MiOiJtaWtreWFuZy5jb20iLCJleHAiOjEzMDIzMTkxMDAsImN1c3RvbV9jbGFpbSI6dHJ1ZX0K";

    #[test]
    fn registered_claims() {
        let claims = ClaimsV2::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.registered.issuer.unwrap(), "mikkyang.com");
        assert_eq!(claims.registered.expiration.unwrap(), 1302319100);
    }

    #[test]
    fn private_claims() {
        let claims = ClaimsV2::from_base64(ENCODED_PAYLOAD).unwrap();

        assert_eq!(claims.private["custom_claim"], Value::Bool(true));
    }

    #[test]
    fn roundtrip() {
        let mut claims: ClaimsV2 = Default::default();
        claims.registered.issuer = Some("mikkyang.com".into());
        claims.registered.expiration = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, ClaimsV2::from_base64(&*enc).unwrap());
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::buffer::TypedBufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::format::IncompatiblePixelsType;
use crate::format::Pixel;
use crate::image::ImageAccess;
use crate::image::SampleCount;
use crate::DeviceSize;
use crate::VulkanObject;
use std::error;
use std::fmt;

/// Type of operation to check.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum CheckCopyBufferImageTy {
    BufferToImage,
    ImageToBuffer,
}

/// Checks whether a copy buffer-image command is valid. Can check both buffer-to-image copies and
/// image-to-buffer copies.
///
/// # Panic
///
/// - Panics if the buffer and image were not created with `device`.
///
pub fn check_copy_buffer_image<B, I, Px>(
    device: &Device,
    buffer: &B,
    image: &I,
    ty: CheckCopyBufferImageTy,
    image_offset: [u32; 3],
    image_size: [u32; 3],
    image_first_layer: u32,
    image_num_layers: u32,
    image_mipmap: u32,
) -> Result<(), CheckCopyBufferImageError>
where
    I: ?Sized + ImageAccess,
    B: ?Sized + TypedBufferAccess<Content = [Px]>,
    Px: Pixel, // TODO: use a trait on the image itself instead
{
    let buffer_inner = buffer.inner();
    let image_inner = image.inner();

    assert_eq!(
        buffer_inner.buffer.device().internal_object(),
        device.internal_object()
    );
    assert_eq!(
        image_inner.image.device().internal_object(),
        device.internal_object()
    );

    match ty {
        CheckCopyBufferImageTy::BufferToImage => {
            if !buffer_inner.buffer.usage().transfer_source {
                return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
            }
            if !image_inner.image.usage().transfer_destination {
                return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
            }
        }
        CheckCopyBufferImageTy::ImageToBuffer => {
            if !image_inner.image.usage().transfer_source {
                return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
            }
            if !buffer_inner.buffer.usage().transfer_destination {
                return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
            }
        }
    }

    if image.samples() != SampleCount::Sample1 {
        return Err(CheckCopyBufferImageError::UnexpectedMultisampled);
    }

    let image_dimensions = match image.dimensions().mipmap_dimensions(image_mipmap) {
        Some(d) => d,
        None => return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange),
    };

    if image_first_layer + image_num_layers > image_dimensions.array_layers() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[0] + image_size[0] > image_dimensions.width() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[1] + image_size[1] > image_dimensions.height() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[2] + image_size[2] > image_dimensions.depth() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    Px::ensure_accepts(image.format())?;

    {
        let required_len =
            required_len_for_format::<Px>(image.format(), image_size, image_num_layers);
        if required_len > buffer.len() {
            return Err(CheckCopyBufferImageError::BufferTooSmall {
                required_len,
                actual_len: buffer.len(),
            });
        }
    }

    // TODO: check memory overlap?

    Ok(())
}

/// Computes the minimum required len in elements for buffer with image data in specified
/// format of specified size.
fn required_len_for_format<Px>(
    format: Format,
    image_size: [u32; 3],
    image_num_layers: u32,
) -> DeviceSize
where
    Px: Pixel,
{
    let [block_width, block_height] = format.block_dimensions();
    let num_blocks = (image_size[0] + block_width - 1) / block_width
        * ((image_size[1] + block_height - 1) / block_height)
        * image_size[2]
        * image_num_layers;
    let required_len = num_blocks as DeviceSize * Px::rate(format) as DeviceSize;

    return required_len;
}

#[cfg(test)]
mod tests {
    use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
    use crate::format::Format;

    #[test]
    fn test_required_len_for_format() {
        // issue #1292
        assert_eq!(
            required_len_for_format::<u8>(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
            2097152
        );
        // other test cases
        assert_eq!(
            required_len_for_format::<u8>(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
            16777216
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
            262144
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R8G8B8_USCALED, [512, 512, 1], 1),
            786432
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R32G32_UINT, [512, 512, 1], 1),
            2097152
        );
        assert_eq!(
            required_len_for_format::<u32>(Format::R32G32_UINT, [512, 512, 1], 1),
            524288
        );
        assert_eq!(
            required_len_for_format::<[u32; 2]>(Format::R32G32_UINT, [512, 512, 1], 1),
            262144
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
            65536
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
            29584
        );
    }
}

/// Error that can happen from `check_copy_buffer_image`.
#[derive(Debug, Copy, Clone)]
pub enum CheckCopyBufferImageError {
    /// The source buffer or image is missing the transfer source usage.
    SourceMissingTransferUsage,
    /// The destination buffer or image is missing the transfer destination usage.
    DestinationMissingTransferUsage,
    /// The source and destination are overlapping.
    OverlappingRanges,
    /// The image must not be multisampled.
    UnexpectedMultisampled,
    /// The image coordinates are out of range.
    ImageCoordinatesOutOfRange,
    /// The type of pixels in the buffer isn't compatible with the image format.
    WrongPixelType(IncompatiblePixelsType),
    /// The buffer is too small for the copy operation.
    BufferTooSmall {
        /// Required number of elements in the buffer.
        required_len: DeviceSize,
        /// Actual number of elements in the buffer.
        actual_len: DeviceSize,
    },
}

impl error::Error for CheckCopyBufferImageError {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            CheckCopyBufferImageError::WrongPixelType(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for CheckCopyBufferImageError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                CheckCopyBufferImageError::SourceMissingTransferUsage => {
                    "the source buffer is missing the transfer source usage"
                }
                CheckCopyBufferImageError::DestinationMissingTransferUsage => {
                    "the destination buffer is missing the transfer destination usage"
                }
                CheckCopyBufferImageError::OverlappingRanges => {
                    "the source and destination are overlapping"
                }
                CheckCopyBufferImageError::UnexpectedMultisampled => {
                    "the image must not be multisampled"
                }
                CheckCopyBufferImageError::ImageCoordinatesOutOfRange => {
                    "the image coordinates are out of range"
                }
                CheckCopyBufferImageError::WrongPixelType(_) => {
                    "the type of pixels in the buffer isn't compatible with the image format"
                }
                CheckCopyBufferImageError::BufferTooSmall { .. } => {
                    "the buffer is too small for the copy operation"
                }
            }
        )
    }
}

impl From<IncompatiblePixelsType> for CheckCopyBufferImageError {
    #[inline]
    fn from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError {
        CheckCopyBufferImageError::WrongPixelType(err)
    }
}
<commit_msg>Additional check_copy_buffer_image checks (#1703)<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use crate::buffer::TypedBufferAccess;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::Format;
use crate::format::IncompatiblePixelsType;
use crate::format::Pixel;
use crate::image::ImageAccess;
use crate::image::ImageDimensions;
use crate::image::SampleCount;
use crate::DeviceSize;
use crate::VulkanObject;
use std::error;
use std::fmt;

/// Type of operation to check.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum CheckCopyBufferImageTy {
    BufferToImage,
    ImageToBuffer,
}

/// Checks whether a copy buffer-image command is valid. Can check both buffer-to-image copies and
/// image-to-buffer copies.
///
/// # Panic
///
/// - Panics if the buffer and image were not created with `device`.
///
pub fn check_copy_buffer_image<B, I, Px>(
    device: &Device,
    buffer: &B,
    image: &I,
    ty: CheckCopyBufferImageTy,
    image_offset: [u32; 3],
    image_size: [u32; 3],
    image_first_layer: u32,
    image_num_layers: u32,
    image_mipmap: u32,
) -> Result<(), CheckCopyBufferImageError>
where
    I: ?Sized + ImageAccess,
    B: ?Sized + TypedBufferAccess<Content = [Px]>,
    Px: Pixel, // TODO: use a trait on the image itself instead
{
    let buffer_inner = buffer.inner();
    let image_inner = image.inner();

    assert_eq!(
        buffer_inner.buffer.device().internal_object(),
        device.internal_object()
    );
    assert_eq!(
        image_inner.image.device().internal_object(),
        device.internal_object()
    );

    match ty {
        CheckCopyBufferImageTy::BufferToImage => {
            if !buffer_inner.buffer.usage().transfer_source {
                return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
            }
            if !image_inner.image.usage().transfer_destination {
                return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
            }
        }
        CheckCopyBufferImageTy::ImageToBuffer => {
            if !image_inner.image.usage().transfer_source {
                return Err(CheckCopyBufferImageError::SourceMissingTransferUsage);
            }
            if !buffer_inner.buffer.usage().transfer_destination {
                return Err(CheckCopyBufferImageError::DestinationMissingTransferUsage);
            }
        }
    }

    if image.samples() != SampleCount::Sample1 {
        return Err(CheckCopyBufferImageError::UnexpectedMultisampled);
    }

    let image_dimensions = match image.dimensions().mipmap_dimensions(image_mipmap) {
        Some(d) => d,
        None => return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange),
    };

    if image_first_layer + image_num_layers > image_dimensions.array_layers() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[0] + image_size[0] > image_dimensions.width() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[1] + image_size[1] > image_dimensions.height() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    if image_offset[2] + image_size[2] > image_dimensions.depth() {
        return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
    }

    match image.dimensions() {
        ImageDimensions::Dim1d { .. } => {
            // VUID-vkCmdCopyBufferToImage-srcImage-00199
            if image_offset[1] != 0 || image_size[1] != 1 {
                return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
            }

            // VUID-vkCmdCopyBufferToImage-srcImage-00201
            if image_offset[2] != 0 || image_size[2] != 1 {
                return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
            }
        }
        ImageDimensions::Dim2d { .. } => {
            // VUID-vkCmdCopyBufferToImage-srcImage-00201
            if image_offset[2] != 0 || image_size[2] != 1 {
                return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
            }
        }
        ImageDimensions::Dim3d { .. } => {
            // VUID-vkCmdCopyBufferToImage-baseArrayLayer-00213
            if image_first_layer != 0 || image_num_layers != 1 {
                return Err(CheckCopyBufferImageError::ImageCoordinatesOutOfRange);
            }
        }
    }

    Px::ensure_accepts(image.format())?;

    {
        let required_len =
            required_len_for_format::<Px>(image.format(), image_size, image_num_layers);
        if required_len > buffer.len() {
            return Err(CheckCopyBufferImageError::BufferTooSmall {
                required_len,
                actual_len: buffer.len(),
            });
        }
    }

    // TODO: check memory overlap?

    Ok(())
}

/// Computes the minimum required len in elements for buffer with image data in specified
/// format of specified size.
fn required_len_for_format<Px>(
    format: Format,
    image_size: [u32; 3],
    image_num_layers: u32,
) -> DeviceSize
where
    Px: Pixel,
{
    let [block_width, block_height] = format.block_dimensions();
    let num_blocks = (image_size[0] + block_width - 1) / block_width
        * ((image_size[1] + block_height - 1) / block_height)
        * image_size[2]
        * image_num_layers;
    let required_len = num_blocks as DeviceSize * Px::rate(format) as DeviceSize;

    return required_len;
}

#[cfg(test)]
mod tests {
    use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
    use crate::format::Format;

    #[test]
    fn test_required_len_for_format() {
        // issue #1292
        assert_eq!(
            required_len_for_format::<u8>(Format::BC1_RGB_UNORM_BLOCK, [2048, 2048, 1], 1),
            2097152
        );
        // other test cases
        assert_eq!(
            required_len_for_format::<u8>(Format::R8G8B8A8_UNORM, [2048, 2048, 1], 1),
            16777216
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R4G4_UNORM_PACK8, [512, 512, 1], 1),
            262144
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R8G8B8_USCALED, [512, 512, 1], 1),
            786432
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::R32G32_UINT, [512, 512, 1], 1),
            2097152
        );
        assert_eq!(
            required_len_for_format::<u32>(Format::R32G32_UINT, [512, 512, 1], 1),
            524288
        );
        assert_eq!(
            required_len_for_format::<[u32; 2]>(Format::R32G32_UINT, [512, 512, 1], 1),
            262144
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::ASTC_8x8_UNORM_BLOCK, [512, 512, 1], 1),
            65536
        );
        assert_eq!(
            required_len_for_format::<u8>(Format::ASTC_12x12_SRGB_BLOCK, [512, 512, 1], 1),
            29584
        );
    }
}

/// Error that can happen from `check_copy_buffer_image`.
#[derive(Debug, Copy, Clone)]
pub enum CheckCopyBufferImageError {
    /// The source buffer or image is missing the transfer source usage.
    SourceMissingTransferUsage,
    /// The destination buffer or image is missing the transfer destination usage.
    DestinationMissingTransferUsage,
    /// The source and destination are overlapping.
    OverlappingRanges,
    /// The image must not be multisampled.
    UnexpectedMultisampled,
    /// The image coordinates are out of range.
    ImageCoordinatesOutOfRange,
    /// The type of pixels in the buffer isn't compatible with the image format.
    WrongPixelType(IncompatiblePixelsType),
    /// The buffer is too small for the copy operation.
    BufferTooSmall {
        /// Required number of elements in the buffer.
        required_len: DeviceSize,
        /// Actual number of elements in the buffer.
        actual_len: DeviceSize,
    },
}

impl error::Error for CheckCopyBufferImageError {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match *self {
            CheckCopyBufferImageError::WrongPixelType(ref err) => Some(err),
            _ => None,
        }
    }
}

impl fmt::Display for CheckCopyBufferImageError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(
            fmt,
            "{}",
            match *self {
                CheckCopyBufferImageError::SourceMissingTransferUsage => {
                    "the source buffer is missing the transfer source usage"
                }
                CheckCopyBufferImageError::DestinationMissingTransferUsage => {
                    "the destination buffer is missing the transfer destination usage"
                }
                CheckCopyBufferImageError::OverlappingRanges => {
                    "the source and destination are overlapping"
                }
                CheckCopyBufferImageError::UnexpectedMultisampled => {
                    "the image must not be multisampled"
                }
                CheckCopyBufferImageError::ImageCoordinatesOutOfRange => {
                    "the image coordinates are out of range"
                }
                CheckCopyBufferImageError::WrongPixelType(_) => {
                    "the type of pixels in the buffer isn't compatible with the image format"
                }
                CheckCopyBufferImageError::BufferTooSmall { .. } => {
                    "the buffer is too small for the copy operation"
                }
            }
        )
    }
}

impl From<IncompatiblePixelsType> for CheckCopyBufferImageError {
    #[inline]
    fn from(err: IncompatiblePixelsType) -> CheckCopyBufferImageError {
        CheckCopyBufferImageError::WrongPixelType(err)
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The xi-editor 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.

use std::collections::HashMap;
use std::path::PathBuf;

use serde_json::{self, Value};

use crate::core_proxy::CoreProxy;
use crate::xi_core::plugin_rpc::{HostNotification, HostRequest, PluginBufferInfo, PluginUpdate};
use crate::xi_core::{ConfigTable, LanguageId, PluginPid, ViewId};
use xi_rpc::{Handler as RpcHandler, RemoteError, RpcCtx};
use xi_trace::{self, trace, trace_block, trace_block_payload};

use super::{Plugin, View};

/// Convenience for unwrapping a view, when handling RPC notifications.
macro_rules! bail {
    ($opt:expr, $method:expr, $pid:expr, $view:expr) => {
        match $opt {
            Some(t) => t,
            None => {
                warn!("{:?} missing {:?} for {:?}", $pid, $view, $method);
                return;
            }
        }
    };
}

/// Convenience for unwrapping a view when handling RPC requests.
/// Prints an error if the view is missing, and returns an appropriate error.
macro_rules! bail_err {
    ($opt:expr, $method:expr, $pid:expr, $view:expr) => {
        match $opt {
            Some(t) => t,
            None => {
                warn!("{:?} missing {:?} for {:?}", $pid, $view, $method);
                return Err(RemoteError::custom(404, "missing view", None));
            }
        }
    };
}

/// Handles raw RPCs from core, updating state and forwarding calls
/// to the plugin,
pub struct Dispatcher<'a, P: 'a + Plugin> {
    //TODO: when we add multi-view, this should be an Arc+Mutex/Rc+RefCell
    views: HashMap<ViewId, View<P::Cache>>,
    pid: Option<PluginPid>,
    plugin: &'a mut P,
}

impl<'a, P: 'a + Plugin> Dispatcher<'a, P> {
    pub(crate) fn new(plugin: &'a mut P) -> Self {
        Dispatcher { views: HashMap::new(), pid: None, plugin }
    }

    fn do_initialize(
        &mut self,
        ctx: &RpcCtx,
        plugin_id: PluginPid,
        buffers: Vec<PluginBufferInfo>,
    ) {
        assert!(self.pid.is_none(), "initialize rpc received with existing pid");
        info!("Initializing plugin {:?}", plugin_id);
        self.pid = Some(plugin_id);

        let core_proxy = CoreProxy::new(self.pid.unwrap(), ctx);
        self.plugin.initialize(core_proxy);

        self.do_new_buffer(ctx, buffers);
    }

    fn do_did_save(&mut self, view_id: ViewId, path: PathBuf) {
        let v = bail!(self.views.get_mut(&view_id), "did_save", self.pid, view_id);
        let prev_path = v.path.take();
        v.path = Some(path);
        self.plugin.did_save(v, prev_path.as_ref().map(PathBuf::as_path));
    }

    fn do_config_changed(&mut self, view_id: ViewId, changes: &ConfigTable) {
        let v = bail!(self.views.get_mut(&view_id), "config_changed", self.pid, view_id);
        self.plugin.config_changed(v, &changes);
        for (key, value) in changes.iter() {
            v.config_table.insert(key.to_owned(), value.to_owned());
        }
        let conf = serde_json::from_value(Value::Object(v.config_table.clone()));
        v.config = conf.unwrap();
    }

    fn do_language_changed(&mut self, view_id: ViewId, new_lang: LanguageId) {
        let v = bail!(self.views.get_mut(&view_id), "language_changed", self.pid, view_id);
        let old_lang = v.language_id.clone();
        v.set_language(new_lang);
        self.plugin.language_changed(v, old_lang);
    }

    fn do_custom_command(&mut self, view_id: ViewId, method: &str, params: Value) {
        let v = bail!(self.views.get_mut(&view_id), method, self.pid, view_id);
        self.plugin.custom_command(v, method, params);
    }

    fn do_new_buffer(&mut self, ctx: &RpcCtx, buffers: Vec<PluginBufferInfo>) {
        let plugin_id = self.pid.unwrap();
        buffers
            .into_iter()
            .map(|info| View::new(ctx.get_peer().clone(), plugin_id, info))
            .for_each(|view| {
                let mut view = view;
                self.plugin.new_view(&mut view);
                self.views.insert(view.view_id, view);
            });
    }

    fn do_close(&mut self, view_id: ViewId) {
        {
            let v = bail!(self.views.get(&view_id), "close", self.pid, view_id);
            self.plugin.did_close(v);
        }
        self.views.remove(&view_id);
    }

    fn do_shutdown(&mut self) {
        info!("rust plugin lib does not shutdown");
        //TODO: handle shutdown
    }

    fn do_get_hover(&mut self, view_id: ViewId, request_id: usize, position: usize) {
        let v = bail!(self.views.get_mut(&view_id), "get_hover", self.pid, view_id);
        self.plugin.get_hover(v, request_id, position)
    }

    fn do_tracing_config(&mut self, enabled: bool) {
        use xi_trace;

        if enabled {
            xi_trace::enable_tracing();
            info!("Enabling tracing in global plugin {:?}", self.pid);
            trace("enable tracing", &["plugin"]);
        } else {
            xi_trace::disable_tracing();
            info!("Disabling tracing in global plugin {:?}", self.pid);
            trace("enable tracing", &["plugin"]);
        }
    }

    fn do_update(&mut self, update: PluginUpdate) -> Result<Value, RemoteError> {
        let _t = trace_block("Dispatcher::do_update", &["plugin"]);
        let PluginUpdate {
            view_id,
            delta,
            new_len,
            new_line_count,
            rev,
            undo_group,
            edit_type,
            author,
        } = update;
        let v = bail_err!(self.views.get_mut(&view_id), "update", self.pid, view_id);
        v.update(delta.as_ref(), new_len, new_line_count, rev, undo_group);
        self.plugin.update(v, delta.as_ref(), edit_type, author);

        Ok(Value::from(1))
    }

    fn do_collect_trace(&self) -> Result<Value, RemoteError> {
        use xi_trace::chrome_trace_dump;

        let samples = xi_trace::samples_cloned_unsorted();
        chrome_trace_dump::to_value(&samples).map_err(|e| RemoteError::Custom {
            code: 0,
            message: format!("Could not serialize trace: {:?}", e),
            data: None,
        })
    }
}

impl<'a, P: Plugin> RpcHandler for Dispatcher<'a, P> {
    type Notification = HostNotification;
    type Request = HostRequest;

    fn handle_notification(&mut self, ctx: &RpcCtx, rpc: Self::Notification) {
        use self::HostNotification::*;
        let _t = trace_block("Dispatcher::handle_notif", &["plugin"]);
        match rpc {
            Initialize { plugin_id, buffer_info } => {
                self.do_initialize(ctx, plugin_id, buffer_info)
            }
            DidSave { view_id, path } => self.do_did_save(view_id, path),
            ConfigChanged { view_id, changes } => self.do_config_changed(view_id, &changes),
            NewBuffer { buffer_info } => self.do_new_buffer(ctx, buffer_info),
            DidClose { view_id } => self.do_close(view_id),
            Shutdown(..) => self.do_shutdown(),
            TracingConfig { enabled } => self.do_tracing_config(enabled),
            GetHover { view_id, request_id, position } => {
                self.do_get_hover(view_id, request_id, position)
            }
            LanguageChanged { view_id, new_lang } => self.do_language_changed(view_id, new_lang),
            CustomCommand { view_id, method, params } => {
                self.do_custom_command(view_id, &method, params)
            }
            Ping(..) => (),
        }
    }

    fn handle_request(&mut self, _ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError> {
        use self::HostRequest::*;
        let _t = trace_block("Dispatcher::handle_request", &["plugin"]);
        match rpc {
            Update(params) => self.do_update(params),
            CollectTrace(..) => self.do_collect_trace(),
        }
    }

    fn idle(&mut self, _ctx: &RpcCtx, token: usize) {
        let _t = trace_block_payload("Dispatcher::idle", &["plugin"], format!("token: {}", token));
        let view_id: ViewId = token.into();
        let v = bail!(self.views.get_mut(&view_id), "idle", self.pid, view_id);
        self.plugin.idle(v);
    }
}
<commit_msg>remove redundant import<commit_after>// Copyright 2018 The xi-editor 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.

use std::collections::HashMap;
use std::path::PathBuf;

use serde_json::{self, Value};

use crate::core_proxy::CoreProxy;
use crate::xi_core::plugin_rpc::{HostNotification, HostRequest, PluginBufferInfo, PluginUpdate};
use crate::xi_core::{ConfigTable, LanguageId, PluginPid, ViewId};
use xi_rpc::{Handler as RpcHandler, RemoteError, RpcCtx};
use xi_trace::{self, trace, trace_block, trace_block_payload};

use super::{Plugin, View};

/// Convenience for unwrapping a view, when handling RPC notifications.
macro_rules! bail {
    ($opt:expr, $method:expr, $pid:expr, $view:expr) => {
        match $opt {
            Some(t) => t,
            None => {
                warn!("{:?} missing {:?} for {:?}", $pid, $view, $method);
                return;
            }
        }
    };
}

/// Convenience for unwrapping a view when handling RPC requests.
/// Prints an error if the view is missing, and returns an appropriate error.
macro_rules! bail_err {
    ($opt:expr, $method:expr, $pid:expr, $view:expr) => {
        match $opt {
            Some(t) => t,
            None => {
                warn!("{:?} missing {:?} for {:?}", $pid, $view, $method);
                return Err(RemoteError::custom(404, "missing view", None));
            }
        }
    };
}

/// Handles raw RPCs from core, updating state and forwarding calls
/// to the plugin,
pub struct Dispatcher<'a, P: 'a + Plugin> {
    //TODO: when we add multi-view, this should be an Arc+Mutex/Rc+RefCell
    views: HashMap<ViewId, View<P::Cache>>,
    pid: Option<PluginPid>,
    plugin: &'a mut P,
}

impl<'a, P: 'a + Plugin> Dispatcher<'a, P> {
    pub(crate) fn new(plugin: &'a mut P) -> Self {
        Dispatcher { views: HashMap::new(), pid: None, plugin }
    }

    fn do_initialize(
        &mut self,
        ctx: &RpcCtx,
        plugin_id: PluginPid,
        buffers: Vec<PluginBufferInfo>,
    ) {
        assert!(self.pid.is_none(), "initialize rpc received with existing pid");
        info!("Initializing plugin {:?}", plugin_id);
        self.pid = Some(plugin_id);

        let core_proxy = CoreProxy::new(self.pid.unwrap(), ctx);
        self.plugin.initialize(core_proxy);

        self.do_new_buffer(ctx, buffers);
    }

    fn do_did_save(&mut self, view_id: ViewId, path: PathBuf) {
        let v = bail!(self.views.get_mut(&view_id), "did_save", self.pid, view_id);
        let prev_path = v.path.take();
        v.path = Some(path);
        self.plugin.did_save(v, prev_path.as_ref().map(PathBuf::as_path));
    }

    fn do_config_changed(&mut self, view_id: ViewId, changes: &ConfigTable) {
        let v = bail!(self.views.get_mut(&view_id), "config_changed", self.pid, view_id);
        self.plugin.config_changed(v, &changes);
        for (key, value) in changes.iter() {
            v.config_table.insert(key.to_owned(), value.to_owned());
        }
        let conf = serde_json::from_value(Value::Object(v.config_table.clone()));
        v.config = conf.unwrap();
    }

    fn do_language_changed(&mut self, view_id: ViewId, new_lang: LanguageId) {
        let v = bail!(self.views.get_mut(&view_id), "language_changed", self.pid, view_id);
        let old_lang = v.language_id.clone();
        v.set_language(new_lang);
        self.plugin.language_changed(v, old_lang);
    }

    fn do_custom_command(&mut self, view_id: ViewId, method: &str, params: Value) {
        let v = bail!(self.views.get_mut(&view_id), method, self.pid, view_id);
        self.plugin.custom_command(v, method, params);
    }

    fn do_new_buffer(&mut self, ctx: &RpcCtx, buffers: Vec<PluginBufferInfo>) {
        let plugin_id = self.pid.unwrap();
        buffers
            .into_iter()
            .map(|info| View::new(ctx.get_peer().clone(), plugin_id, info))
            .for_each(|view| {
                let mut view = view;
                self.plugin.new_view(&mut view);
                self.views.insert(view.view_id, view);
            });
    }

    fn do_close(&mut self, view_id: ViewId) {
        {
            let v = bail!(self.views.get(&view_id), "close", self.pid, view_id);
            self.plugin.did_close(v);
        }
        self.views.remove(&view_id);
    }

    fn do_shutdown(&mut self) {
        info!("rust plugin lib does not shutdown");
        //TODO: handle shutdown
    }

    fn do_get_hover(&mut self, view_id: ViewId, request_id: usize, position: usize) {
        let v = bail!(self.views.get_mut(&view_id), "get_hover", self.pid, view_id);
        self.plugin.get_hover(v, request_id, position)
    }

    fn do_tracing_config(&mut self, enabled: bool) {
        if enabled {
            xi_trace::enable_tracing();
            info!("Enabling tracing in global plugin {:?}", self.pid);
            trace("enable tracing", &["plugin"]);
        } else {
            xi_trace::disable_tracing();
            info!("Disabling tracing in global plugin {:?}", self.pid);
            trace("enable tracing", &["plugin"]);
        }
    }

    fn do_update(&mut self, update: PluginUpdate) -> Result<Value, RemoteError> {
        let _t = trace_block("Dispatcher::do_update", &["plugin"]);
        let PluginUpdate {
            view_id,
            delta,
            new_len,
            new_line_count,
            rev,
            undo_group,
            edit_type,
            author,
        } = update;
        let v = bail_err!(self.views.get_mut(&view_id), "update", self.pid, view_id);
        v.update(delta.as_ref(), new_len, new_line_count, rev, undo_group);
        self.plugin.update(v, delta.as_ref(), edit_type, author);

        Ok(Value::from(1))
    }

    fn do_collect_trace(&self) -> Result<Value, RemoteError> {
        use xi_trace::chrome_trace_dump;

        let samples = xi_trace::samples_cloned_unsorted();
        chrome_trace_dump::to_value(&samples).map_err(|e| RemoteError::Custom {
            code: 0,
            message: format!("Could not serialize trace: {:?}", e),
            data: None,
        })
    }
}

impl<'a, P: Plugin> RpcHandler for Dispatcher<'a, P> {
    type Notification = HostNotification;
    type Request = HostRequest;

    fn handle_notification(&mut self, ctx: &RpcCtx, rpc: Self::Notification) {
        use self::HostNotification::*;
        let _t = trace_block("Dispatcher::handle_notif", &["plugin"]);
        match rpc {
            Initialize { plugin_id, buffer_info } => {
                self.do_initialize(ctx, plugin_id, buffer_info)
            }
            DidSave { view_id, path } => self.do_did_save(view_id, path),
            ConfigChanged { view_id, changes } => self.do_config_changed(view_id, &changes),
            NewBuffer { buffer_info } => self.do_new_buffer(ctx, buffer_info),
            DidClose { view_id } => self.do_close(view_id),
            Shutdown(..) => self.do_shutdown(),
            TracingConfig { enabled } => self.do_tracing_config(enabled),
            GetHover { view_id, request_id, position } => {
                self.do_get_hover(view_id, request_id, position)
            }
            LanguageChanged { view_id, new_lang } => self.do_language_changed(view_id, new_lang),
            CustomCommand { view_id, method, params } => {
                self.do_custom_command(view_id, &method, params)
            }
            Ping(..) => (),
        }
    }

    fn handle_request(&mut self, _ctx: &RpcCtx, rpc: Self::Request) -> Result<Value, RemoteError> {
        use self::HostRequest::*;
        let _t = trace_block("Dispatcher::handle_request", &["plugin"]);
        match rpc {
            Update(params) => self.do_update(params),
            CollectTrace(..) => self.do_collect_trace(),
        }
    }

    fn idle(&mut self, _ctx: &RpcCtx, token: usize) {
        let _t = trace_block_payload("Dispatcher::idle", &["plugin"], format!("token: {}", token));
        let view_id: ViewId = token.into();
        let v = bail!(self.views.get_mut(&view_id), "idle", self.pid, view_id);
        self.plugin.idle(v);
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use libnum::{Zero};
use std::ops::{Add, Mul};

pub fn dot<T: Copy + Zero + Add<T, Output=T> + Mul<T, Output=T>>(u: &[T], v: &[T]) -> T {
    	let len = cmp::min(u.len(), v.len());
        let mut xs = &u[..len];
        let mut ys = &v[..len];

        let mut s = T::zero();
        let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
            (T::zero(), T::zero(), T::zero(), T::zero(),
                T::zero(), T::zero(), T::zero(), T::zero());

        while xs.len() >= 8 {
            p0 = p0 + xs[0] * ys[0];
            p1 = p1 + xs[1] * ys[1];
            p2 = p2 + xs[2] * ys[2];
            p3 = p3 + xs[3] * ys[3];
            p4 = p4 + xs[4] * ys[4];
            p5 = p5 + xs[5] * ys[5];
            p6 = p6 + xs[6] * ys[6];
            p7 = p7 + xs[7] * ys[7];

            xs = &xs[8..];
            ys = &ys[8..];
        }
        s = s + p0 + p4;
        s = s + p1 + p5;
        s = s + p2 + p6;
        s = s + p3 + p7;

        for i in 0..xs.len() {
            s = s + xs[i] * ys[i];
        }
        s
    }

pub fn argmax<T: Copy + PartialOrd>(u: &[T]) -> usize {
    assert!(u.len() != 0);

    let mut max_index = 0;
    let mut max = u[max_index];

    for (i, v) in (u.into_iter()).enumerate() {
        if max < *v {
            max_index = i;
            max = *v;
        }
    }

    max_index
}<commit_msg>Began implementation of vectorized vector sum.<commit_after>use std::cmp;
use libnum::{Zero};
use std::ops::{Add, Mul};

pub fn dot<T: Copy + Zero + Add<T, Output=T> + Mul<T, Output=T>>(u: &[T], v: &[T]) -> T {
    let len = cmp::min(u.len(), v.len());
    let mut xs = &u[..len];
    let mut ys = &v[..len];

    let mut s = T::zero();
    let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) =
        (T::zero(), T::zero(), T::zero(), T::zero(),
            T::zero(), T::zero(), T::zero(), T::zero());

    while xs.len() >= 8 {
        p0 = p0 + xs[0] * ys[0];
        p1 = p1 + xs[1] * ys[1];
        p2 = p2 + xs[2] * ys[2];
        p3 = p3 + xs[3] * ys[3];
        p4 = p4 + xs[4] * ys[4];
        p5 = p5 + xs[5] * ys[5];
        p6 = p6 + xs[6] * ys[6];
        p7 = p7 + xs[7] * ys[7];

        xs = &xs[8..];
        ys = &ys[8..];
    }
    s = s + p0 + p4;
    s = s + p1 + p5;
    s = s + p2 + p6;
    s = s + p3 + p7;

    for i in 0..xs.len() {
        s = s + xs[i] * ys[i];
    }
    s
 }

pub fn sum<T: Copy + Zero + Add<T, Output=T>> (u: &[T], v: &[T]) -> Vec<T> {
    let len = cmp::min(u.len(), v.len());
    let mut xs = &u[..len];
    let mut ys = &v[..len];

    let mut sum_data = vec![T::zero(); len];
    let mut holder = 0;

    while xs.len() >= 8 {
        sum_data[0+holder] = xs[0] + ys[0];
        sum_data[1+holder] = xs[1] + ys[1];
        sum_data[2+holder] = xs[2] + ys[2];
        sum_data[3+holder] = xs[3] + ys[3];
        sum_data[4+holder] = xs[4] + ys[4];
        sum_data[5+holder] = xs[5] + ys[5];
        sum_data[6+holder] = xs[6] + ys[6];
        sum_data[7+holder] = xs[7] + ys[7];

        xs = &xs[8..];
        ys = &ys[8..];

        holder += 8;
    }

    for i in 0..xs.len() {
        sum_data[0+holder] = xs[i] + ys[i];
    }
    sum_data
}

pub fn argmax<T: Copy + PartialOrd>(u: &[T]) -> usize {
    assert!(u.len() != 0);

    let mut max_index = 0;
    let mut max = u[max_index];

    for (i, v) in (u.into_iter()).enumerate() {
        if max < *v {
            max_index = i;
            max = *v;
        }
    }

    max_index
}<|endoftext|>


<commit_before>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;
mod types;

use crate::load::read_bytes;
pub use crate::{
    compiler::{Compiler, CompilerBuilder, CpuFeatures, OptLevel, SpecificFeature, TargetCpu},
    error::Error,
    heap::HeapSettings,
    load::read_module,
};
pub use lucet_module::bindings::Bindings;
pub use lucet_validate::Validator;
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use target_lexicon::Triple;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    builder: CompilerBuilder,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
    translate_wat: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn target(&mut self, target: Triple);
    fn with_target(self, target: Triple) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn cpu_features(&mut self, cpu_features: CpuFeatures);
    fn with_cpu_features(self, cpu_features: CpuFeatures) -> Self;

    fn validator(&mut self, validator: Validator);
    fn with_validator(self, validator: Validator) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
    fn count_instructions(&mut self, enable_count: bool);
    fn with_count_instructions(self, enable_count: bool) -> Self;
    fn canonicalize_nans(&mut self, enable_canonicalize_nans: bool);
    fn with_canonicalize_nans(self, enable_canonicalize_nans: bool) -> Self;
    fn translate_wat(&mut self, enable_translate_wat: bool);
    fn with_translate_wat(self, enable_translate_wat: bool) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn target(&mut self, target: Triple) {
        self.as_lucetc().builder.target(target);
    }

    fn with_target(mut self, target: Triple) -> Self {
        self.target(target);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().builder.opt_level(opt_level);
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn cpu_features(&mut self, cpu_features: CpuFeatures) {
        self.as_lucetc().builder.cpu_features(cpu_features);
    }

    fn with_cpu_features(mut self, cpu_features: CpuFeatures) -> Self {
        self.cpu_features(cpu_features);
        self
    }

    fn validator(&mut self, validator: Validator) {
        self.as_lucetc().builder.validator(Some(validator));
    }

    fn with_validator(mut self, validator: Validator) -> Self {
        self.validator(validator);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = reserved_size;
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().builder.heap_settings_mut().guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }

    fn count_instructions(&mut self, count_instructions: bool) {
        self.as_lucetc()
            .builder
            .count_instructions(count_instructions);
    }

    fn with_count_instructions(mut self, count_instructions: bool) -> Self {
        self.count_instructions(count_instructions);
        self
    }

    fn canonicalize_nans(&mut self, enable_nans_canonicalization: bool) {
        self.as_lucetc()
            .builder
            .canonicalize_nans(enable_nans_canonicalization);
    }

    fn with_canonicalize_nans(mut self, enable_nans_canonicalization: bool) -> Self {
        self.canonicalize_nans(enable_nans_canonicalization);
        self
    }
    fn translate_wat(&mut self, enable_translate_wat: bool) {
        self.as_lucetc().translate_wat = enable_translate_wat;
    }

    fn with_translate_wat(mut self, enable_translate_wat: bool) -> Self {
        self.translate_wat(enable_translate_wat);
        self
    }
}

impl Lucetc {
    pub fn new(input: impl AsRef<Path>) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: true,
        }
    }

    pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        let module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => {
                read_module(&path, &self.pk, self.verify, self.translate_wat)?
            }
        };

        // Collect set of Bindings into a single Bindings:
        let mut bindings = Bindings::empty();
        for binding in self.bindings.iter() {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;
        let compiler = self.builder.create(&module_contents, &bindings)?;
        let obj = compiler.object_file()?;
        obj.write(output.as_ref())?;

        Ok(())
    }

    pub fn clif_ir(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = self.builder.create(&module_contents, &bindings)?;

        compiler.cranelift_funcs()?.write(&output)?;

        Ok(())
    }

    pub fn shared_object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, self.builder.target_ref(), &output)?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(Error::Signature(
                "signing requires a secret key".to_string(),
            ))?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

fn link_so(
    objpath: impl AsRef<Path>,
    target: &Triple,
    sopath: impl AsRef<Path>,
) -> Result<(), Error> {
    // Let `LD` be something like "clang --target=... ..." for convenience.
    let env_ld = env::var("LD").unwrap_or(LD_DEFAULT.into());
    let mut ld_iter = env_ld.split_whitespace();
    let ld_prog = ld_iter.next().expect("LD must not be empty");
    let mut cmd_ld = Command::new(ld_prog);
    for flag in ld_iter {
        cmd_ld.arg(flag);
    }

    cmd_ld.arg(objpath.as_ref());
    let env_ldflags = env::var("LDFLAGS").unwrap_or_else(|_| ldflags_default(target));
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }

    output_arg_for(&mut cmd_ld, target, sopath);

    let run_ld = cmd_ld.output()?;

    if !run_ld.status.success() {
        let message = format!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        );
        return Err(Error::LdError(message));
    }
    Ok(())
}

fn output_arg_for(cmd_ld: &mut Command, target: &Triple, sopath: impl AsRef<Path>) {
    use target_lexicon::{Environment, OperatingSystem};

    if target.operating_system != OperatingSystem::Windows || target.environment == Environment::Gnu
    {
        cmd_ld.arg("-o");
        cmd_ld.arg(sopath.as_ref());
        return;
    }

    assert!(target.environment == Environment::Msvc);

    cmd_ld.arg(format!("/out:{:?}", sopath.as_ref()));
}

fn ldflags_default(target: &Triple) -> String {
    use target_lexicon::OperatingSystem;

    match target.operating_system {
        OperatingSystem::Linux => "-shared",
        OperatingSystem::Darwin | OperatingSystem::MacOSX { .. } => {
            "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"
        }
        _ => panic!(
            "Cannot determine default flags for {}.

Please define the LDFLAGS environment variable with the necessary command-line
flags for generating shared libraries.",
            target
        ),
    }
    .into()
}
<commit_msg>[lucetc] Use -shared linker flag on BSD platforms<commit_after>#![deny(bare_trait_objects)]

mod compiler;
mod decls;
mod error;
mod function;
mod heap;
mod load;
mod module;
mod name;
mod output;
mod pointer;
mod runtime;
pub mod signature;
mod sparsedata;
mod stack_probe;
mod table;
mod traps;
mod types;

use crate::load::read_bytes;
pub use crate::{
    compiler::{Compiler, CompilerBuilder, CpuFeatures, OptLevel, SpecificFeature, TargetCpu},
    error::Error,
    heap::HeapSettings,
    load::read_module,
};
pub use lucet_module::bindings::Bindings;
pub use lucet_validate::Validator;
use signature::{PublicKey, SecretKey};
use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use target_lexicon::Triple;

enum LucetcInput {
    Bytes(Vec<u8>),
    Path(PathBuf),
}

pub struct Lucetc {
    input: LucetcInput,
    bindings: Vec<Bindings>,
    builder: CompilerBuilder,
    sk: Option<SecretKey>,
    pk: Option<PublicKey>,
    sign: bool,
    verify: bool,
    translate_wat: bool,
}

pub trait AsLucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc;
}

impl AsLucetc for Lucetc {
    fn as_lucetc(&mut self) -> &mut Lucetc {
        self
    }
}

pub trait LucetcOpts {
    fn bindings(&mut self, bindings: Bindings);
    fn with_bindings(self, bindings: Bindings) -> Self;

    fn target(&mut self, target: Triple);
    fn with_target(self, target: Triple) -> Self;

    fn opt_level(&mut self, opt_level: OptLevel);
    fn with_opt_level(self, opt_level: OptLevel) -> Self;

    fn cpu_features(&mut self, cpu_features: CpuFeatures);
    fn with_cpu_features(self, cpu_features: CpuFeatures) -> Self;

    fn validator(&mut self, validator: Validator);
    fn with_validator(self, validator: Validator) -> Self;

    fn min_reserved_size(&mut self, min_reserved_size: u64);
    fn with_min_reserved_size(self, min_reserved_size: u64) -> Self;

    fn max_reserved_size(&mut self, max_reserved_size: u64);
    fn with_max_reserved_size(self, max_reserved_size: u64) -> Self;

    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn reserved_size(&mut self, reserved_size: u64);
    /// Set the reserved size exactly.
    ///
    /// Equivalent to setting the minimum and maximum reserved sizes to the same value.
    fn with_reserved_size(self, reserved_size: u64) -> Self;

    fn guard_size(&mut self, guard_size: u64);
    fn with_guard_size(self, guard_size: u64) -> Self;

    fn pk(&mut self, pk: PublicKey);
    fn with_pk(self, pk: PublicKey) -> Self;
    fn sk(&mut self, sk: SecretKey);
    fn with_sk(self, sk: SecretKey) -> Self;
    fn verify(&mut self);
    fn with_verify(self) -> Self;
    fn sign(&mut self);
    fn with_sign(self) -> Self;
    fn count_instructions(&mut self, enable_count: bool);
    fn with_count_instructions(self, enable_count: bool) -> Self;
    fn canonicalize_nans(&mut self, enable_canonicalize_nans: bool);
    fn with_canonicalize_nans(self, enable_canonicalize_nans: bool) -> Self;
    fn translate_wat(&mut self, enable_translate_wat: bool);
    fn with_translate_wat(self, enable_translate_wat: bool) -> Self;
}

impl<T: AsLucetc> LucetcOpts for T {
    fn bindings(&mut self, bindings: Bindings) {
        self.as_lucetc().bindings.push(bindings);
    }

    fn with_bindings(mut self, bindings: Bindings) -> Self {
        self.bindings(bindings);
        self
    }

    fn target(&mut self, target: Triple) {
        self.as_lucetc().builder.target(target);
    }

    fn with_target(mut self, target: Triple) -> Self {
        self.target(target);
        self
    }

    fn opt_level(&mut self, opt_level: OptLevel) {
        self.as_lucetc().builder.opt_level(opt_level);
    }

    fn with_opt_level(mut self, opt_level: OptLevel) -> Self {
        self.opt_level(opt_level);
        self
    }

    fn cpu_features(&mut self, cpu_features: CpuFeatures) {
        self.as_lucetc().builder.cpu_features(cpu_features);
    }

    fn with_cpu_features(mut self, cpu_features: CpuFeatures) -> Self {
        self.cpu_features(cpu_features);
        self
    }

    fn validator(&mut self, validator: Validator) {
        self.as_lucetc().builder.validator(Some(validator));
    }

    fn with_validator(mut self, validator: Validator) -> Self {
        self.validator(validator);
        self
    }

    fn min_reserved_size(&mut self, min_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = min_reserved_size;
    }

    fn with_min_reserved_size(mut self, min_reserved_size: u64) -> Self {
        self.min_reserved_size(min_reserved_size);
        self
    }

    fn max_reserved_size(&mut self, max_reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = max_reserved_size;
    }

    fn with_max_reserved_size(mut self, max_reserved_size: u64) -> Self {
        self.max_reserved_size(max_reserved_size);
        self
    }

    fn reserved_size(&mut self, reserved_size: u64) {
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .min_reserved_size = reserved_size;
        self.as_lucetc()
            .builder
            .heap_settings_mut()
            .max_reserved_size = reserved_size;
    }

    fn with_reserved_size(mut self, reserved_size: u64) -> Self {
        self.reserved_size(reserved_size);
        self
    }

    fn guard_size(&mut self, guard_size: u64) {
        self.as_lucetc().builder.heap_settings_mut().guard_size = guard_size;
    }

    fn with_guard_size(mut self, guard_size: u64) -> Self {
        self.guard_size(guard_size);
        self
    }

    fn pk(&mut self, pk: PublicKey) {
        self.as_lucetc().pk = Some(pk);
    }

    fn with_pk(mut self, pk: PublicKey) -> Self {
        self.pk(pk);
        self
    }

    fn sk(&mut self, sk: SecretKey) {
        self.as_lucetc().sk = Some(sk);
    }

    fn with_sk(mut self, sk: SecretKey) -> Self {
        self.sk(sk);
        self
    }

    fn verify(&mut self) {
        self.as_lucetc().verify = true;
    }

    fn with_verify(mut self) -> Self {
        self.verify();
        self
    }

    fn sign(&mut self) {
        self.as_lucetc().sign = true;
    }

    fn with_sign(mut self) -> Self {
        self.sign();
        self
    }

    fn count_instructions(&mut self, count_instructions: bool) {
        self.as_lucetc()
            .builder
            .count_instructions(count_instructions);
    }

    fn with_count_instructions(mut self, count_instructions: bool) -> Self {
        self.count_instructions(count_instructions);
        self
    }

    fn canonicalize_nans(&mut self, enable_nans_canonicalization: bool) {
        self.as_lucetc()
            .builder
            .canonicalize_nans(enable_nans_canonicalization);
    }

    fn with_canonicalize_nans(mut self, enable_nans_canonicalization: bool) -> Self {
        self.canonicalize_nans(enable_nans_canonicalization);
        self
    }
    fn translate_wat(&mut self, enable_translate_wat: bool) {
        self.as_lucetc().translate_wat = enable_translate_wat;
    }

    fn with_translate_wat(mut self, enable_translate_wat: bool) -> Self {
        self.translate_wat(enable_translate_wat);
        self
    }
}

impl Lucetc {
    pub fn new(input: impl AsRef<Path>) -> Self {
        let input = input.as_ref();
        Self {
            input: LucetcInput::Path(input.to_owned()),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: true,
        }
    }

    pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
        let input = read_bytes(bytes.as_ref().to_vec())?;
        Ok(Self {
            input: LucetcInput::Bytes(input),
            bindings: vec![],
            builder: Compiler::builder(),
            pk: None,
            sk: None,
            sign: false,
            verify: false,
            translate_wat: false,
        })
    }

    fn build(&self) -> Result<(Vec<u8>, Bindings), Error> {
        let module_binary = match &self.input {
            LucetcInput::Bytes(bytes) => bytes.clone(),
            LucetcInput::Path(path) => {
                read_module(&path, &self.pk, self.verify, self.translate_wat)?
            }
        };

        // Collect set of Bindings into a single Bindings:
        let mut bindings = Bindings::empty();
        for binding in self.bindings.iter() {
            bindings.extend(binding)?;
        }

        Ok((module_binary, bindings))
    }

    pub fn object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;
        let compiler = self.builder.create(&module_contents, &bindings)?;
        let obj = compiler.object_file()?;
        obj.write(output.as_ref())?;

        Ok(())
    }

    pub fn clif_ir(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let (module_contents, bindings) = self.build()?;

        let compiler = self.builder.create(&module_contents, &bindings)?;

        compiler.cranelift_funcs()?.write(&output)?;

        Ok(())
    }

    pub fn shared_object_file(&self, output: impl AsRef<Path>) -> Result<(), Error> {
        let dir = tempfile::Builder::new().prefix("lucetc").tempdir()?;
        let objpath = dir.path().join("tmp.o");
        self.object_file(objpath.clone())?;
        link_so(objpath, self.builder.target_ref(), &output)?;
        if self.sign {
            let sk = self.sk.as_ref().ok_or(Error::Signature(
                "signing requires a secret key".to_string(),
            ))?;
            signature::sign_module(&output, sk)?;
        }
        Ok(())
    }
}

const LD_DEFAULT: &str = "ld";

fn link_so(
    objpath: impl AsRef<Path>,
    target: &Triple,
    sopath: impl AsRef<Path>,
) -> Result<(), Error> {
    // Let `LD` be something like "clang --target=... ..." for convenience.
    let env_ld = env::var("LD").unwrap_or(LD_DEFAULT.into());
    let mut ld_iter = env_ld.split_whitespace();
    let ld_prog = ld_iter.next().expect("LD must not be empty");
    let mut cmd_ld = Command::new(ld_prog);
    for flag in ld_iter {
        cmd_ld.arg(flag);
    }

    cmd_ld.arg(objpath.as_ref());
    let env_ldflags = env::var("LDFLAGS").unwrap_or_else(|_| ldflags_default(target));
    for flag in env_ldflags.split_whitespace() {
        cmd_ld.arg(flag);
    }

    output_arg_for(&mut cmd_ld, target, sopath);

    let run_ld = cmd_ld.output()?;

    if !run_ld.status.success() {
        let message = format!(
            "ld of {} failed: {}",
            objpath.as_ref().to_str().unwrap(),
            String::from_utf8_lossy(&run_ld.stderr)
        );
        return Err(Error::LdError(message));
    }
    Ok(())
}

fn output_arg_for(cmd_ld: &mut Command, target: &Triple, sopath: impl AsRef<Path>) {
    use target_lexicon::{Environment, OperatingSystem};

    if target.operating_system != OperatingSystem::Windows || target.environment == Environment::Gnu
    {
        cmd_ld.arg("-o");
        cmd_ld.arg(sopath.as_ref());
        return;
    }

    assert!(target.environment == Environment::Msvc);

    cmd_ld.arg(format!("/out:{:?}", sopath.as_ref()));
}

fn ldflags_default(target: &Triple) -> String {
    use target_lexicon::OperatingSystem;

    match target.operating_system {
        OperatingSystem::Linux
        | OperatingSystem::Freebsd
        | OperatingSystem::Dragonfly
        | OperatingSystem::Netbsd
        | OperatingSystem::Openbsd => "-shared",
        OperatingSystem::Darwin | OperatingSystem::MacOSX { .. } => {
            "-dylib -dead_strip -export_dynamic -undefined dynamic_lookup"
        }
        _ => panic!(
            "Cannot determine default flags for {}.

Please define the LDFLAGS environment variable with the necessary command-line
flags for generating shared libraries.",
            target
        ),
    }
    .into()
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - connect");

    78 as c_int

    // let mut r_address;
    // unsafe {
    //     r_address = CStr::from_ptr(address);
    // }
    // let s_address = r_address.to_bytes();
    // let host_address = match str::from_utf8(s_address) {
    //     Ok(safe_str) => safe_str,
    //     Err(_) => {
    //         println!("Invalid host address");
    //         return -1 as c_int;
    //     }
    // };
    //
    // // Create and register a way to kill this client
    // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    // let kill_tx = k_tx.clone();
    // let mut k_tx_ptr = Box::new(k_tx);
    // unsafe {
    //     register_stop_tx(&mut *k_tx_ptr);
    // }
    //
    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // println!("Attempting connect to: {}", host_address);
    //
    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();
    //
    // // Exit out in standard C fashion
    // 0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// 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/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

#[no_mangle]
pub extern "C" fn testing_fn() -> c_int {
    78 as c_int
}

/// Connects to the provided address, (eg "123.123.123.123:3000") and registers
/// the on data received handler
#[no_mangle]
pub extern "C" fn connect(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - connect");

    78 as c_int

    // let mut r_address;
    // unsafe {
    //     r_address = CStr::from_ptr(address);
    // }
    // let s_address = r_address.to_bytes();
    // let host_address = match str::from_utf8(s_address) {
    //     Ok(safe_str) => safe_str,
    //     Err(_) => {
    //         println!("Invalid host address");
    //         return -1 as c_int;
    //     }
    // };
    //
    // // Create and register a way to kill this client
    // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    // let kill_tx = k_tx.clone();
    // let mut k_tx_ptr = Box::new(k_tx);
    // unsafe {
    //     register_stop_tx(&mut *k_tx_ptr);
    // }
    //
    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // println!("Attempting connect to: {}", host_address);
    //
    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();
    //
    // // Exit out in standard C fashion
    // 0 as c_int
}

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>extern crate thrussh;
extern crate thrussh_keys;
extern crate futures;
extern crate tokio;
extern crate env_logger;
use std::sync::Arc;
use thrussh::*;
use thrussh::server::{Auth, Session};
use thrussh_keys::*;
use futures::Future;
use std::io::Read;

struct Client {
}

impl client::Handler for Client {
   type Error = anyhow::Error;
   type FutureUnit = futures::future::Ready<Result<(Self, client::Session), anyhow::Error>>;
   type FutureBool = futures::future::Ready<Result<(Self, bool), anyhow::Error>>;

   fn finished_bool(self, b: bool) -> Self::FutureBool {
       futures::future::ready(Ok((self, b)))
   }
   fn finished(self, session: client::Session) -> Self::FutureUnit {
       futures::future::ready(Ok((self, session)))
   }
   fn check_server_key(self, server_public_key: &key::PublicKey) -> Self::FutureBool {
       println!("check_server_key: {:?}", server_public_key);
       self.finished_bool(true)
   }
   fn channel_open_confirmation(self, channel: ChannelId, max_packet_size: u32, window_size: u32, session: client::Session) -> Self::FutureUnit {
       println!("channel_open_confirmation: {:?}", channel);
       self.finished(session)
   }
   fn data(self, channel: ChannelId, data: &[u8], session: client::Session) -> Self::FutureUnit {
       println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data));
       self.finished(session)
   }
}

#[tokio::main]
pub async fn ssh() {
  let config = thrussh::client::Config::default();
  let config = Arc::new(config);
  let sh = Client{};

  let key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
  let mut agent = thrussh_keys::agent::client::AgentClient::connect_env().await.unwrap();
  agent.add_identity(&key, &[]).await.unwrap();
  let mut session = thrussh::client::connect(config, "localhost:22", sh).await.unwrap();
  if session.authenticate_future(std::env::var("USER").unwrap(), key.clone_public_key(), agent).await.1.unwrap() {
    let mut channel = session.channel_open_session().await.unwrap();
    channel.data(&b"Hello, world!"[..]).await.unwrap();
    if let Some(msg) = channel.wait().await {
        println!("{:?}", msg)
    }
  }
}
<commit_msg>client/mod.rs: be a bit more tolerant of unset USER<commit_after>extern crate thrussh;
extern crate thrussh_keys;
extern crate futures;
extern crate tokio;
extern crate env_logger;
use std::sync::Arc;
use thrussh::*;
use thrussh::server::{Auth, Session};
use thrussh_keys::*;
use futures::Future;
use std::io::Read;

struct Client {
}

impl client::Handler for Client {
   type Error = anyhow::Error;
   type FutureUnit = futures::future::Ready<Result<(Self, client::Session), anyhow::Error>>;
   type FutureBool = futures::future::Ready<Result<(Self, bool), anyhow::Error>>;

   fn finished_bool(self, b: bool) -> Self::FutureBool {
       futures::future::ready(Ok((self, b)))
   }
   fn finished(self, session: client::Session) -> Self::FutureUnit {
       futures::future::ready(Ok((self, session)))
   }
   fn check_server_key(self, server_public_key: &key::PublicKey) -> Self::FutureBool {
       println!("check_server_key: {:?}", server_public_key);
       self.finished_bool(true)
   }
   fn channel_open_confirmation(self, channel: ChannelId, max_packet_size: u32, window_size: u32, session: client::Session) -> Self::FutureUnit {
       println!("channel_open_confirmation: {:?}", channel);
       self.finished(session)
   }
   fn data(self, channel: ChannelId, data: &[u8], session: client::Session) -> Self::FutureUnit {
       println!("data on channel {:?}: {:?}", channel, std::str::from_utf8(data));
       self.finished(session)
   }
}

#[tokio::main]
pub async fn ssh() {
  let config = thrussh::client::Config::default();
  let config = Arc::new(config);
  let sh = Client{};

  let key = thrussh_keys::key::KeyPair::generate_ed25519().unwrap();
  let mut agent = thrussh_keys::agent::client::AgentClient::connect_env().await.unwrap();
  agent.add_identity(&key, &[]).await.unwrap();
  let mut session = thrussh::client::connect(config, "10.0.2.15:23", sh).await.unwrap();
  let user:String;
  match std::env::var("USER") {
    Ok(val) => user = val,
    Err(e) => {
        user = "root".to_string();
        println!("No USER set({}); going with {}", e, user);
    },
}
  if session.authenticate_future(user, key.clone_public_key(), agent).await.1.unwrap() {
    let mut channel = session.channel_open_session().await.unwrap();
    channel.data(&b"Hello, world!"[..]).await.unwrap();
    if let Some(msg) = channel.wait().await {
        println!("{:?}", msg)
    }
  }
}
<|endoftext|>