<commit_before>// Copyright 2017-2018 int08h LLC
//
// 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.

//!
//! Protect the server's long-term key with envelope encryption and a key management system.
//!
//! ## Motivation
//!
//! The seed for the server's [long-term key](../key/struct.LongTermKey.html) is subject to
//! contradictory requirements:
//!
//!   1. The seed must be kept secret, but
//!   2. The seed must be available at server start-up to create the
//!      [delegated on-line key](../key/struct.OnlineKey.html)
//!
//! ## Plaintext seed
//!
//! The default option is to store the seed in plaintext as part of the server's configuration.
//! This usually means the seed is present in the clear: on disk, in a repository, or otherwise
//! durably persisted where it can be compromised (accidentally or maliciously).
//!
//! ## Encrypting the seed
//!
//! Using envelope encryption the seed is protected by encrypting it with a locally generated
//! Data Encryption Key (DEK) and then encrypting the DEK using a cloud key management system
//! (KMS). See [`EnvelopeEncryption`](struct.EnvelopeEncryption.html) for the implementation.
//!
//! The resulting opaque encrypted "blob" (encrypted seed + encrypted DEK) is safely stored
//! in the Roughenough configuration. At server start-up the KMS is used to decrypt the DEK,
//! and the DEK is used to (temporarily in memory) decrypt the seed. The seed is used to
//! generate the [delegated on-line key](../key/struct.OnlineKey.html) after which the seed
//! is erased.
//!
//! For details see explanations from
//! [Google](https://cloud.google.com/kms/docs/envelope-encryption) or
//! [Amazon](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping).
//!

mod envelope;

pub use self::envelope::EnvelopeEncryption;

use std;
use std::error::Error;
use ring;

use config::ServerConfig;
use error;
use key::KeyProtection;

/// Errors generated by KMS operations
#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub enum KmsError {
    OperationFailed(String),
    InvalidConfiguration(String),
    InvalidData(String),
    InvalidKey(String),
}

impl From<std::io::Error> for KmsError {
    fn from(error: std::io::Error) -> Self {
        KmsError::OperationFailed(error.description().to_string())
    }
}

impl From<ring::error::Unspecified> for KmsError {
    fn from(_: ring::error::Unspecified) -> Self {
        KmsError::OperationFailed("unspecified ring cryptographic failure".to_string())
    }
}

// Size of the AEAD nonce in bytes.
const NONCE_SIZE_BYTES: usize = 12;

// Size of the AEAD authentication tag in bytes.
const TAG_SIZE_BYTES: usize = 16;

/// Size of the 256-bit Data Encryption Key (DEK) in bytes.
pub const DEK_SIZE_BYTES: usize = 32;

/// An unencrypted (plaintext) 256-bit Data Encryption Key (DEK).
pub type PlaintextDEK = Vec<u8>;

/// A Data Encryption Key (DEK) that has been encrypted (wrapped) by a Key Management System (KMS).
///
/// This is an opaque value and the size of the encrypted DEK is implementation specific.
/// Things like AEAD tag size, nonce size, provider metadata, and so on will vary between
/// [`KmsProvider`](trait.KmsProvider.html) implementations.
pub type EncryptedDEK = Vec<u8>;

///
/// A key management system that wraps/unwraps a data encryption key (DEK).
///
pub trait KmsProvider {
    /// Make a blocking request to encrypt (wrap) the provided plaintext data encryption key.
    fn encrypt_dek(&self, plaintext_dek: &PlaintextDEK) -> Result<EncryptedDEK, KmsError>;

    /// Make a blocking request to decrypt (unwrap) a previously encrypted data encryption key.
    fn decrypt_dek(&self, encrypted_dek: &EncryptedDEK) -> Result<PlaintextDEK, KmsError>;
}

#[cfg(feature = "kms")]
mod awskms;

#[cfg(feature = "kms")]
pub use kms::awskms::AwsKms;

#[cfg(feature = "kms")]
pub fn load_seed(config: &Box<ServerConfig>) -> Result<Vec<u8>, error::Error> {
    use kms::envelope::EnvelopeEncryption;

    match config.key_protection() {
        KeyProtection::Plaintext => Ok(config.seed()),
        KeyProtection::AwsKmsEnvelope(key_id) => {
            info!("Unwrapping seed via AWS KMS key '{}'", key_id);
            let kms = AwsKms::from_arn(key_id)?;
            let seed = EnvelopeEncryption::decrypt_seed(&kms, &config.seed())?;
            Ok(seed)
        }
        _ => Err(error::Error::InvalidConfiguration(
            "Google KMS not supported".to_string(),
        )),
    }
}

#[cfg(not(feature = "kms"))]
pub fn load_seed(config: &Box<ServerConfig>) -> Result<Vec<u8>, error::Error> {
    match config.key_protection() {
        KeyProtection::Plaintext => Ok(config.seed()),
        v => Err(error::Error::InvalidConfiguration(format!(
            "key_protection '{}' implies KMS but server was not compiled with KMS support", v
        ))),
    }
}
<commit_msg>documentation enhancements<commit_after>// Copyright 2017-2018 int08h LLC
//
// 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.

//!
//! Protect the server's long-term key with envelope encryption and a key management system.
//!
//! ## Motivation
//!
//! The seed for the server's [long-term key](../key/struct.LongTermKey.html) is subject to
//! contradictory requirements:
//!
//!   1. The seed must be kept secret, but
//!   2. The seed must be available at server start-up to create the
//!      [delegated on-line key](../key/struct.OnlineKey.html)
//!
//! ## Plaintext seed
//!
//! The default option is to store the seed in plaintext as part of the server's configuration.
//! This usually means the seed is present in the clear: on disk, in a repository, or otherwise
//! durably persisted where it can be compromised (accidentally or maliciously).
//!
//! ## Encrypting the seed
//!
//! Envelope encryption protects the seed by encrypting it with a locally generated 256-bit
//! Data Encryption Key (DEK). The DEK itself is then encrypted using a cloud key management
//! system (KMS). The resulting opaque encrypted "blob" (encrypted seed + encrypted DEK) is safe
//! to store in the Roughenough configuration.
//!
//! At server start-up the KMS is used to decrypt the DEK, which is then used to (in memory)
//! decrypt the seed. The seed is used to generate the
//! [delegated on-line key](../key/struct.OnlineKey.html) after which the seed and DEK are erased
//! from memory.
//!
//! See
//!   * [`EnvelopeEncryption`](struct.EnvelopeEncryption.html) for Roughenough's implementation.
//!   * [Google](https://cloud.google.com/kms/docs/envelope-encryption) or
//!     [Amazon](https://docs.aws.amazon.com/kms/latest/developerguide/concepts.html#enveloping)
//!     for more in-depth explanations of envelope encryption.
//!

mod envelope;

pub use self::envelope::EnvelopeEncryption;

use std;
use std::error::Error;
use ring;

use config::ServerConfig;
use error;
use key::KeyProtection;

/// Errors generated by KMS operations
#[derive(Debug, PartialEq, Eq, PartialOrd, Hash, Clone)]
pub enum KmsError {
    OperationFailed(String),
    InvalidConfiguration(String),
    InvalidData(String),
    InvalidKey(String),
}

impl From<std::io::Error> for KmsError {
    fn from(error: std::io::Error) -> Self {
        KmsError::OperationFailed(error.description().to_string())
    }
}

impl From<ring::error::Unspecified> for KmsError {
    fn from(_: ring::error::Unspecified) -> Self {
        KmsError::OperationFailed("unspecified ring cryptographic failure".to_string())
    }
}

// Size of the AEAD nonce in bytes.
const NONCE_SIZE_BYTES: usize = 12;

// Size of the AEAD authentication tag in bytes.
const TAG_SIZE_BYTES: usize = 16;

/// Size of the 256-bit Data Encryption Key (DEK) in bytes.
pub const DEK_SIZE_BYTES: usize = 32;

/// An unencrypted (plaintext) 256-bit Data Encryption Key (DEK).
pub type PlaintextDEK = Vec<u8>;

/// A Data Encryption Key (DEK) that has been encrypted (wrapped) by a Key Management System (KMS).
///
/// This is an opaque, implementation-specific value. AEAD tag size, nonce size,
/// provider metadata, and so on will vary between [`KmsProvider`](trait.KmsProvider.html)
/// implementations.
pub type EncryptedDEK = Vec<u8>;

///
/// A key management system that wraps/unwraps a data encryption key (DEK).
///
pub trait KmsProvider {
    /// Make a blocking request to encrypt (wrap) the provided plaintext data encryption key.
    fn encrypt_dek(&self, plaintext_dek: &PlaintextDEK) -> Result<EncryptedDEK, KmsError>;

    /// Make a blocking request to decrypt (unwrap) a previously encrypted data encryption key.
    fn decrypt_dek(&self, encrypted_dek: &EncryptedDEK) -> Result<PlaintextDEK, KmsError>;
}

#[cfg(feature = "kms")]
mod awskms;

#[cfg(feature = "kms")]
pub use kms::awskms::AwsKms;

/// Load the seed value for the long-term key.
///
/// Loading behavior depends on the value of `config.key_protection()`:
///
///  * If `config.key_protection() == Plaintext` then the value returned from `config.seed()`
///    is used as-is and assumed to be a 32-byte hexadecimal value.
///
///  * Otherwise `config.seed()` is assumed to be an encrypted opaque blob generated from
///    a prior `EnvelopeEncryption::encrypt_seed` call. The value of `config.key_protection()`
///    is parsed as a KMS key id and `EnvelopeEncryption::decrypt_seed` is called to obtain
///    the plaintext seed value.
///
#[cfg(feature = "kms")]
pub fn load_seed(config: &Box<ServerConfig>) -> Result<Vec<u8>, error::Error> {
    use kms::envelope::EnvelopeEncryption;

    match config.key_protection() {
        KeyProtection::Plaintext => Ok(config.seed()),
        KeyProtection::AwsKmsEnvelope(key_id) => {
            info!("Unwrapping seed via AWS KMS key '{}'", key_id);
            let kms = AwsKms::from_arn(key_id)?;
            let seed = EnvelopeEncryption::decrypt_seed(&kms, &config.seed())?;
            Ok(seed)
        }
        _ => Err(error::Error::InvalidConfiguration(
            "Google KMS not supported".to_string(),
        )),
    }
}

///
/// Load the seed value for the long-term key.
///
/// The KMS feature was disabled in this build of Roughenough. The only supported `key_protection`
/// value is `plaintext`. Any other value is an error.
///
#[cfg(not(feature = "kms"))]
pub fn load_seed(config: &Box<ServerConfig>) -> Result<Vec<u8>, error::Error> {
    match config.key_protection() {
        KeyProtection::Plaintext => Ok(config.seed()),
        v => Err(error::Error::InvalidConfiguration(format!(
            "key_protection '{}' implies KMS but server was not compiled with KMS support", v
        ))),
    }
}
<|endoftext|>


<commit_before>/// Program header table entry unused
pub const PT_NULL: u32 = 0;
/// Loadable program segment
pub const PT_LOAD: u32 = 1;
/// Dynamic linking information
pub const PT_DYNAMIC: u32 = 2;
/// Program interpreter
pub const PT_INTERP: u32 = 3;
/// Auxiliary information
pub const PT_NOTE: u32 = 4;
/// Reserved
pub const PT_SHLIB: u32 = 5;
/// Entry for header table itself
pub const PT_PHDR: u32 = 6;
/// Thread-local storage segment
pub const PT_TLS: u32 = 7;
/// Number of defined types
pub const PT_NUM: u32 = 8;
/// Start of OS-specific
pub const PT_LOOS: u32 = 0x60000000;
/// GCC .eh_frame_hdr segment
pub const PT_GNU_EH_FRAME: u32 = 0x6474e550;
/// Indicates stack executability
pub const PT_GNU_STACK: u32 = 0x6474e551;
/// Read-only after relocation
pub const PT_GNU_RELRO: u32 = 0x6474e552;
/// Sun Specific segment
pub const PT_LOSUNW: u32 = 0x6ffffffa;
/// Sun Specific segment
pub const PT_SUNWBSS: u32 = 0x6ffffffa;
/// Stack segment
pub const PT_SUNWSTACK: u32 = 0x6ffffffb;
/// End of OS-specific
pub const PT_HISUNW: u32 = 0x6fffffff;
/// End of OS-specific
pub const PT_HIOS: u32 = 0x6fffffff;
/// Start of processor-specific
pub const PT_LOPROC: u32 = 0x70000000;
/// ARM unwind segment
pub const PT_ARM_EXIDX: u32 = 0x70000001;
/// End of processor-specific
pub const PT_HIPROC: u32 = 0x7fffffff;

/// Segment is executable
pub const PF_X: u32 = 1 << 0;

/// Segment is writable
pub const PF_W: u32 = 1 << 1;

/// Segment is readable
pub const PF_R: u32 = 1 << 2;

pub fn pt_to_str(pt: u32) -> &'static str {
    match pt {
        PT_NULL => "PT_NULL",
        PT_LOAD => "PT_LOAD",
        PT_DYNAMIC => "PT_DYNAMIC",
        PT_INTERP => "PT_INTERP",
        PT_NOTE => "PT_NOTE",
        PT_SHLIB => "PT_SHLIB",
        PT_PHDR => "PT_PHDR",
        PT_TLS => "PT_TLS",
        PT_NUM => "PT_NUM",
        PT_LOOS => "PT_LOOS",
        PT_GNU_EH_FRAME => "PT_GNU_EH_FRAME",
        PT_GNU_STACK => "PT_GNU_STACK",
        PT_GNU_RELRO => "PT_GNU_RELRO",
        PT_SUNWBSS => "PT_SUNWBSS",
        PT_SUNWSTACK => "PT_SUNWSTACK",
        PT_HIOS => "PT_HIOS",
        PT_LOPROC => "PT_LOPROC",
        PT_HIPROC => "PT_HIPROC",
        PT_ARM_EXIDX => "PT_ARM_EXIDX",
        _ => "UNKNOWN_PT",
    }
}

#[cfg(feature = "std")]
pub use self::std::*;

#[cfg(feature = "std")]
mod std {
    use super::*;
    use core::fmt;
    use scroll::ctx;
    use core::result;
    use core::ops::Range;
    use container::{Ctx, Container};

    #[cfg(feature = "std")]
    #[derive(Default, PartialEq, Clone)]
    /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants
    pub struct ProgramHeader {
        pub p_type  : u32,
        pub p_flags : u32,
        pub p_offset: u64,
        pub p_vaddr : u64,
        pub p_paddr : u64,
        pub p_filesz: u64,
        pub p_memsz : u64,
        pub p_align : u64,
    }

    impl ProgramHeader {
        /// Return the size of the underlying program header, given a `Ctx`
        #[inline]
        pub fn size(ctx: &Ctx) -> usize {
            use scroll::ctx::SizeWith;
            Self::size_with(&ctx)
        }
        /// Create a new `PT_LOAD` ELF program header
        pub fn new() -> Self {
            ProgramHeader {
                p_type  : PT_LOAD,
                p_flags : 0,
                p_offset: 0,
                p_vaddr : 0,
                p_paddr : 0,
                p_filesz: 0,
                p_memsz : 0,
                //TODO: check if this is true for 32-bit pt_load
                p_align : 2 << 20,
            }
        }
        pub fn to_range(&self) -> Range<usize> {
            (self.p_offset as usize..self.p_offset as usize + self.p_filesz as usize)
        }
        /// Sets the executable flag
        pub fn executable(&mut self) {
            self.p_flags = self.p_flags | PF_X;
        }
        /// Sets the write flag
        pub fn write(&mut self) {
            self.p_flags = self.p_flags | PF_W;
        }
        /// Sets the read flag
        pub fn read(&mut self) {
            self.p_flags = self.p_flags | PF_R;
        }

        #[cfg(feature = "endian_fd")]
        pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> ::error::Result<Vec<ProgramHeader>> {
            use scroll::Pread;
            let mut program_headers = Vec::with_capacity(count);
            for _ in 0..count {
                let phdr = bytes.gread_with(&mut offset, ctx)?;
                program_headers.push(phdr);
            }
            Ok(program_headers)
        }
    }

    impl fmt::Debug for ProgramHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f,
                   "p_type: {} p_flags 0x{:x} p_offset: 0x{:x} p_vaddr: 0x{:x} p_paddr: 0x{:x} \
                    p_filesz: 0x{:x} p_memsz: 0x{:x} p_align: {}",
                   pt_to_str(self.p_type),
                   self.p_flags,
                   self.p_offset,
                   self.p_vaddr,
                   self.p_paddr,
                   self.p_filesz,
                   self.p_memsz,
                   self.p_align)
        }
    }

    impl ctx::SizeWith<Ctx> for ProgramHeader {
        type Units = usize;
        fn size_with(ctx: &Ctx) -> usize {
            match ctx.container {
                Container::Little => {
                    program_header32::SIZEOF_PHDR
                },
                Container::Big => {
                    program_header64::SIZEOF_PHDR
                },
            }
        }
    }

    impl<'a> ctx::TryFromCtx<'a, Ctx> for ProgramHeader {
        type Error = ::error::Error;
        type Size = usize;
        fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, Self::Size), Self::Error> {
            use scroll::Pread;
            let res = match container {
                Container::Little => {
                    (bytes.pread_with::<program_header32::ProgramHeader>(0, le)?.into(), program_header32::SIZEOF_PHDR)
                },
                Container::Big => {
                    (bytes.pread_with::<program_header64::ProgramHeader>(0, le)?.into(), program_header64::SIZEOF_PHDR)
                }
            };
            Ok(res)
        }
    }

    impl ctx::TryIntoCtx<Ctx> for ProgramHeader {
        type Error = ::error::Error;
        type Size = usize;
        fn try_into_ctx(self, mut bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<Self::Size, Self::Error> {
            use scroll::Pwrite;
            match container {
                Container::Little => {
                    let phdr: program_header32::ProgramHeader = self.into();
                    Ok(bytes.pwrite_with(phdr, 0, le)?)
                },
                Container::Big => {
                    let phdr: program_header64::ProgramHeader = self.into();
                    Ok(bytes.pwrite_with(phdr, 0, le)?)
                }
            }
        }
    }
}

macro_rules! elf_program_header_std_impl { ($size:ty) => {

    #[cfg(test)]
    mod test {
        use super::*;
        #[test]
        fn size_of() {
            assert_eq!(::std::mem::size_of::<ProgramHeader>(), SIZEOF_PHDR);
        }
    }

    #[cfg(feature = "std")]
    pub use self::std::*;

    #[cfg(feature = "std")]
    mod std {

        use elf::program_header::ProgramHeader as ElfProgramHeader;
        use super::*;
        use error::Result;

        use core::slice;
        use core::fmt;

        use std::fs::File;
        use std::io::{Seek, Read};
        use std::io::SeekFrom::Start;

        use plain::Plain;

        impl From<ProgramHeader> for ElfProgramHeader {
            fn from(ph: ProgramHeader) -> Self {
                ElfProgramHeader {
                    p_type   : ph.p_type,
                    p_flags  : ph.p_flags,
                    p_offset : ph.p_offset as u64,
                    p_vaddr  : ph.p_vaddr as u64,
                    p_paddr  : ph.p_paddr as u64,
                    p_filesz : ph.p_filesz as u64,
                    p_memsz  : ph.p_memsz as u64,
                    p_align  : ph.p_align as u64,
                }
            }
        }

        impl From<ElfProgramHeader> for ProgramHeader {
            fn from(ph: ElfProgramHeader) -> Self {
                ProgramHeader {
                    p_type   : ph.p_type,
                    p_flags  : ph.p_flags,
                    p_offset : ph.p_offset as $size,
                    p_vaddr  : ph.p_vaddr  as $size,
                    p_paddr  : ph.p_paddr  as $size,
                    p_filesz : ph.p_filesz as $size,
                    p_memsz  : ph.p_memsz  as $size,
                    p_align  : ph.p_align  as $size,
                }
            }
        }

        impl fmt::Debug for ProgramHeader {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f,
                       "p_type: {} p_flags 0x{:x} p_offset: 0x{:x} p_vaddr: 0x{:x} p_paddr: 0x{:x} \
                        p_filesz: 0x{:x} p_memsz: 0x{:x} p_align: {}",
                       pt_to_str(self.p_type),
                       self.p_flags,
                       self.p_offset,
                       self.p_vaddr,
                       self.p_paddr,
                       self.p_filesz,
                       self.p_memsz,
                       self.p_align)
            }
        }

        impl ProgramHeader {
            #[cfg(feature = "endian_fd")]
            pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: ::scroll::Endian) -> Result<Vec<ProgramHeader>> {
                use scroll::Pread;
                let mut program_headers = vec![ProgramHeader::default(); count];
                let mut offset = &mut offset;
                bytes.gread_inout_with(offset, &mut program_headers, ctx)?;
                Ok(program_headers)
            }

            pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec<ProgramHeader> {
                let mut phdrs = vec![ProgramHeader::default(); phnum];
                phdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries");
                phdrs
            }

            pub unsafe fn from_raw_parts<'a>(phdrp: *const ProgramHeader,
                                             phnum: usize)
                                             -> &'a [ProgramHeader] {
                slice::from_raw_parts(phdrp, phnum)
            }

            pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result<Vec<ProgramHeader>> {
                let mut phdrs = vec![ProgramHeader::default(); count];
                try!(fd.seek(Start(offset)));
                unsafe {
                    try!(fd.read(plain::as_mut_bytes(&mut *phdrs)));
                }
                Ok(phdrs)
            }
        }
    }
};}

pub mod program_header32 {
    pub use elf::program_header::*;

    #[repr(C)]
    #[derive(Copy, Clone, PartialEq, Default)]
    #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
    /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory
    pub struct ProgramHeader {
        /// Segment type
        pub p_type: u32,
        /// Segment file offset
        pub p_offset: u32,
        /// Segment virtual address
        pub p_vaddr: u32,
        /// Segment physical address
        pub p_paddr: u32,
        /// Segment size in file
        pub p_filesz: u32,
        /// Segment size in memory
        pub p_memsz: u32,
        /// Segment flags
        pub p_flags: u32,
        /// Segment alignment
        pub p_align: u32,
    }

    pub const SIZEOF_PHDR: usize = 32;

    use plain;
    // Declare that this is a plain type.
    unsafe impl plain::Plain for ProgramHeader {}

    elf_program_header_std_impl!(u32);
}

pub mod program_header64 {
    pub use elf::program_header::*;

    #[repr(C)]
    #[derive(Copy, Clone, PartialEq, Default)]
    #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
    /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory
    pub struct ProgramHeader {
        /// Segment type
        pub p_type: u32,
        /// Segment flags
        pub p_flags: u32,
        /// Segment file offset
        pub p_offset: u64,
        /// Segment virtual address
        pub p_vaddr: u64,
        /// Segment physical address
        pub p_paddr: u64,
        /// Segment size in file
        pub p_filesz: u64,
        /// Segment size in memory
        pub p_memsz: u64,
        /// Segment alignment
        pub p_align: u64,
    }

    pub const SIZEOF_PHDR: usize = 56;

    use plain;
    // Declare that this is a plain type.
    unsafe impl plain::Plain for ProgramHeader {}

    elf_program_header_std_impl!(u64);
}
<commit_msg>elf.program_header: use if_std macro for great good<commit_after>/// Program header table entry unused
pub const PT_NULL: u32 = 0;
/// Loadable program segment
pub const PT_LOAD: u32 = 1;
/// Dynamic linking information
pub const PT_DYNAMIC: u32 = 2;
/// Program interpreter
pub const PT_INTERP: u32 = 3;
/// Auxiliary information
pub const PT_NOTE: u32 = 4;
/// Reserved
pub const PT_SHLIB: u32 = 5;
/// Entry for header table itself
pub const PT_PHDR: u32 = 6;
/// Thread-local storage segment
pub const PT_TLS: u32 = 7;
/// Number of defined types
pub const PT_NUM: u32 = 8;
/// Start of OS-specific
pub const PT_LOOS: u32 = 0x60000000;
/// GCC .eh_frame_hdr segment
pub const PT_GNU_EH_FRAME: u32 = 0x6474e550;
/// Indicates stack executability
pub const PT_GNU_STACK: u32 = 0x6474e551;
/// Read-only after relocation
pub const PT_GNU_RELRO: u32 = 0x6474e552;
/// Sun Specific segment
pub const PT_LOSUNW: u32 = 0x6ffffffa;
/// Sun Specific segment
pub const PT_SUNWBSS: u32 = 0x6ffffffa;
/// Stack segment
pub const PT_SUNWSTACK: u32 = 0x6ffffffb;
/// End of OS-specific
pub const PT_HISUNW: u32 = 0x6fffffff;
/// End of OS-specific
pub const PT_HIOS: u32 = 0x6fffffff;
/// Start of processor-specific
pub const PT_LOPROC: u32 = 0x70000000;
/// ARM unwind segment
pub const PT_ARM_EXIDX: u32 = 0x70000001;
/// End of processor-specific
pub const PT_HIPROC: u32 = 0x7fffffff;

/// Segment is executable
pub const PF_X: u32 = 1 << 0;

/// Segment is writable
pub const PF_W: u32 = 1 << 1;

/// Segment is readable
pub const PF_R: u32 = 1 << 2;

pub fn pt_to_str(pt: u32) -> &'static str {
    match pt {
        PT_NULL => "PT_NULL",
        PT_LOAD => "PT_LOAD",
        PT_DYNAMIC => "PT_DYNAMIC",
        PT_INTERP => "PT_INTERP",
        PT_NOTE => "PT_NOTE",
        PT_SHLIB => "PT_SHLIB",
        PT_PHDR => "PT_PHDR",
        PT_TLS => "PT_TLS",
        PT_NUM => "PT_NUM",
        PT_LOOS => "PT_LOOS",
        PT_GNU_EH_FRAME => "PT_GNU_EH_FRAME",
        PT_GNU_STACK => "PT_GNU_STACK",
        PT_GNU_RELRO => "PT_GNU_RELRO",
        PT_SUNWBSS => "PT_SUNWBSS",
        PT_SUNWSTACK => "PT_SUNWSTACK",
        PT_HIOS => "PT_HIOS",
        PT_LOPROC => "PT_LOPROC",
        PT_HIPROC => "PT_HIPROC",
        PT_ARM_EXIDX => "PT_ARM_EXIDX",
        _ => "UNKNOWN_PT",
    }
}

if_std! {
    use core::fmt;
    use scroll::ctx;
    use core::result;
    use core::ops::Range;
    use container::{Ctx, Container};

    #[derive(Default, PartialEq, Clone)]
    /// A unified ProgramHeader - convertable to and from 32-bit and 64-bit variants
    pub struct ProgramHeader {
        pub p_type  : u32,
        pub p_flags : u32,
        pub p_offset: u64,
        pub p_vaddr : u64,
        pub p_paddr : u64,
        pub p_filesz: u64,
        pub p_memsz : u64,
        pub p_align : u64,
    }

    impl ProgramHeader {
        /// Return the size of the underlying program header, given a `Ctx`
        #[inline]
        pub fn size(ctx: &Ctx) -> usize {
            use scroll::ctx::SizeWith;
            Self::size_with(&ctx)
        }
        /// Create a new `PT_LOAD` ELF program header
        pub fn new() -> Self {
            ProgramHeader {
                p_type  : PT_LOAD,
                p_flags : 0,
                p_offset: 0,
                p_vaddr : 0,
                p_paddr : 0,
                p_filesz: 0,
                p_memsz : 0,
                //TODO: check if this is true for 32-bit pt_load
                p_align : 2 << 20,
            }
        }
        pub fn to_range(&self) -> Range<usize> {
            (self.p_offset as usize..self.p_offset as usize + self.p_filesz as usize)
        }
        /// Sets the executable flag
        pub fn executable(&mut self) {
            self.p_flags = self.p_flags | PF_X;
        }
        /// Sets the write flag
        pub fn write(&mut self) {
            self.p_flags = self.p_flags | PF_W;
        }
        /// Sets the read flag
        pub fn read(&mut self) {
            self.p_flags = self.p_flags | PF_R;
        }

        #[cfg(feature = "endian_fd")]
        pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: Ctx) -> ::error::Result<Vec<ProgramHeader>> {
            use scroll::Pread;
            let mut program_headers = Vec::with_capacity(count);
            for _ in 0..count {
                let phdr = bytes.gread_with(&mut offset, ctx)?;
                program_headers.push(phdr);
            }
            Ok(program_headers)
        }
    }

    impl fmt::Debug for ProgramHeader {
        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f,
                   "p_type: {} p_flags 0x{:x} p_offset: 0x{:x} p_vaddr: 0x{:x} p_paddr: 0x{:x} \
                    p_filesz: 0x{:x} p_memsz: 0x{:x} p_align: {}",
                   pt_to_str(self.p_type),
                   self.p_flags,
                   self.p_offset,
                   self.p_vaddr,
                   self.p_paddr,
                   self.p_filesz,
                   self.p_memsz,
                   self.p_align)
        }
    }

    impl ctx::SizeWith<Ctx> for ProgramHeader {
        type Units = usize;
        fn size_with(ctx: &Ctx) -> usize {
            match ctx.container {
                Container::Little => {
                    program_header32::SIZEOF_PHDR
                },
                Container::Big => {
                    program_header64::SIZEOF_PHDR
                },
            }
        }
    }

    impl<'a> ctx::TryFromCtx<'a, Ctx> for ProgramHeader {
        type Error = ::error::Error;
        type Size = usize;
        fn try_from_ctx(bytes: &'a [u8], Ctx { container, le}: Ctx) -> result::Result<(Self, Self::Size), Self::Error> {
            use scroll::Pread;
            let res = match container {
                Container::Little => {
                    (bytes.pread_with::<program_header32::ProgramHeader>(0, le)?.into(), program_header32::SIZEOF_PHDR)
                },
                Container::Big => {
                    (bytes.pread_with::<program_header64::ProgramHeader>(0, le)?.into(), program_header64::SIZEOF_PHDR)
                }
            };
            Ok(res)
        }
    }

    impl ctx::TryIntoCtx<Ctx> for ProgramHeader {
        type Error = ::error::Error;
        type Size = usize;
        fn try_into_ctx(self, mut bytes: &mut [u8], Ctx {container, le}: Ctx) -> result::Result<Self::Size, Self::Error> {
            use scroll::Pwrite;
            match container {
                Container::Little => {
                    let phdr: program_header32::ProgramHeader = self.into();
                    Ok(bytes.pwrite_with(phdr, 0, le)?)
                },
                Container::Big => {
                    let phdr: program_header64::ProgramHeader = self.into();
                    Ok(bytes.pwrite_with(phdr, 0, le)?)
                }
            }
        }
    }
}

macro_rules! elf_program_header_std_impl { ($size:ty) => {

    #[cfg(test)]
    mod test {
        use super::*;
        #[test]
        fn size_of() {
            assert_eq!(::std::mem::size_of::<ProgramHeader>(), SIZEOF_PHDR);
        }
    }

    if_std! {

        use elf::program_header::ProgramHeader as ElfProgramHeader;
        use error::Result;

        use core::slice;
        use core::fmt;

        use std::fs::File;
        use std::io::{Seek, Read};
        use std::io::SeekFrom::Start;

        use plain::Plain;

        impl From<ProgramHeader> for ElfProgramHeader {
            fn from(ph: ProgramHeader) -> Self {
                ElfProgramHeader {
                    p_type   : ph.p_type,
                    p_flags  : ph.p_flags,
                    p_offset : ph.p_offset as u64,
                    p_vaddr  : ph.p_vaddr as u64,
                    p_paddr  : ph.p_paddr as u64,
                    p_filesz : ph.p_filesz as u64,
                    p_memsz  : ph.p_memsz as u64,
                    p_align  : ph.p_align as u64,
                }
            }
        }

        impl From<ElfProgramHeader> for ProgramHeader {
            fn from(ph: ElfProgramHeader) -> Self {
                ProgramHeader {
                    p_type   : ph.p_type,
                    p_flags  : ph.p_flags,
                    p_offset : ph.p_offset as $size,
                    p_vaddr  : ph.p_vaddr  as $size,
                    p_paddr  : ph.p_paddr  as $size,
                    p_filesz : ph.p_filesz as $size,
                    p_memsz  : ph.p_memsz  as $size,
                    p_align  : ph.p_align  as $size,
                }
            }
        }

        impl fmt::Debug for ProgramHeader {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f,
                       "p_type: {} p_flags 0x{:x} p_offset: 0x{:x} p_vaddr: 0x{:x} p_paddr: 0x{:x} \
                        p_filesz: 0x{:x} p_memsz: 0x{:x} p_align: {}",
                       pt_to_str(self.p_type),
                       self.p_flags,
                       self.p_offset,
                       self.p_vaddr,
                       self.p_paddr,
                       self.p_filesz,
                       self.p_memsz,
                       self.p_align)
            }
        }

        impl ProgramHeader {
            #[cfg(feature = "endian_fd")]
            pub fn parse(bytes: &[u8], mut offset: usize, count: usize, ctx: ::scroll::Endian) -> Result<Vec<ProgramHeader>> {
                use scroll::Pread;
                let mut program_headers = vec![ProgramHeader::default(); count];
                let mut offset = &mut offset;
                bytes.gread_inout_with(offset, &mut program_headers, ctx)?;
                Ok(program_headers)
            }

            pub fn from_bytes(bytes: &[u8], phnum: usize) -> Vec<ProgramHeader> {
                let mut phdrs = vec![ProgramHeader::default(); phnum];
                phdrs.copy_from_bytes(bytes).expect("buffer is too short for given number of entries");
                phdrs
            }

            pub unsafe fn from_raw_parts<'a>(phdrp: *const ProgramHeader,
                                             phnum: usize)
                                             -> &'a [ProgramHeader] {
                slice::from_raw_parts(phdrp, phnum)
            }

            pub fn from_fd(fd: &mut File, offset: u64, count: usize) -> Result<Vec<ProgramHeader>> {
                let mut phdrs = vec![ProgramHeader::default(); count];
                try!(fd.seek(Start(offset)));
                unsafe {
                    try!(fd.read(plain::as_mut_bytes(&mut *phdrs)));
                }
                Ok(phdrs)
            }
        }
    }
};}

pub mod program_header32 {
    pub use elf::program_header::*;

    #[repr(C)]
    #[derive(Copy, Clone, PartialEq, Default)]
    #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
    /// A 64-bit ProgramHeader typically specifies how to map executable and data segments into memory
    pub struct ProgramHeader {
        /// Segment type
        pub p_type: u32,
        /// Segment file offset
        pub p_offset: u32,
        /// Segment virtual address
        pub p_vaddr: u32,
        /// Segment physical address
        pub p_paddr: u32,
        /// Segment size in file
        pub p_filesz: u32,
        /// Segment size in memory
        pub p_memsz: u32,
        /// Segment flags
        pub p_flags: u32,
        /// Segment alignment
        pub p_align: u32,
    }

    pub const SIZEOF_PHDR: usize = 32;

    use plain;
    // Declare that this is a plain type.
    unsafe impl plain::Plain for ProgramHeader {}

    elf_program_header_std_impl!(u32);
}

pub mod program_header64 {
    pub use elf::program_header::*;

    #[repr(C)]
    #[derive(Copy, Clone, PartialEq, Default)]
    #[cfg_attr(feature = "std", derive(Pread, Pwrite, SizeWith))]
    /// A 32-bit ProgramHeader typically specifies how to map executable and data segments into memory
    pub struct ProgramHeader {
        /// Segment type
        pub p_type: u32,
        /// Segment flags
        pub p_flags: u32,
        /// Segment file offset
        pub p_offset: u64,
        /// Segment virtual address
        pub p_vaddr: u64,
        /// Segment physical address
        pub p_paddr: u64,
        /// Segment size in file
        pub p_filesz: u64,
        /// Segment size in memory
        pub p_memsz: u64,
        /// Segment alignment
        pub p_align: u64,
    }

    pub const SIZEOF_PHDR: usize = 56;

    use plain;
    // Declare that this is a plain type.
    unsafe impl plain::Plain for ProgramHeader {}

    elf_program_header_std_impl!(u64);
}
<|endoftext|>


<commit_before>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::thread;

use std::fs::{File};
use std::path::Path;
use std::io::Write;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaQuery>>> = Mutex::new(None);

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Option<Receiver<LuaResponse>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdentifier = Vec<AnyLuaValue>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdentifier),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdentifier, Vec<AnyLuaValue>),
    /// Set a value
    SetValue {
        /// The name of the thing to stuff
        name: LuaIdentifier,
        /// The value to store.
        val: Json
    },
    /// Create a new table
    NewTable(LuaIdentifier),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

unsafe impl Send for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaQuery { }
unsafe impl Sync for LuaResponse { }

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked
    Sender
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<(), LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(ref sender) = *SENDER.lock().unwrap() {
        match sender.send(query) {
            Ok(_) => Ok(()),
            Err(_) => Err(LuaSendError::Sender)
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaQuery>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = Some(query_tx);
        *receiver = Some(answer_rx);
    }

    thread::spawn(move || {
        thread_init(answer_tx, query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(sender, receiver, &mut lua);
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>,
                         request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);
            let var_result = lua.get(format!("{:?}", varname));

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {:?}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: _name, val: _val } => {
            panic!("thread: unimplemented LuaQuery::SetValue!");
        },

        LuaQuery::NewTable(_name) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            panic!("thread: unimplemented LuaQuery::Ping!");
        },
        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(_) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<commit_msg>Update try_send to async receive (break build)<commit_after>//! Lua functionality

use hlua;
use hlua::{Lua, LuaError};
use hlua::any::AnyLuaValue;

use rustc_serialize::json::Json;

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::io::Write;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;

use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

#[macro_use]
mod funcs;
#[cfg(test)]
mod tests;

lazy_static! {
    /// Sends requests to the lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Receives data back from the lua thread
    /// This should only be accessed by the lua thread itself.
    static ref RECEIVER: Mutex<Option<Receiver<LuaResponse>>> = Mutex::new(None);

    /// Whether the lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

/// Represents an identifier for dealing with nested tables.
///
/// To access foo.bar.baz, use vec!["foo", "bar", "baz"].
///
/// To access foo[2], use vec!["foo", 2].
pub type LuaIdentifier = Vec<AnyLuaValue>;

/// Messages sent to the lua thread
#[derive(Debug)]
pub enum LuaQuery {
    /// Pings the lua thread
    Ping,
    /// Halt the lua thread
    Terminate,
    // Restart the lua thread
    Restart,

    /// Execute a string
    Execute(String),
    /// Execute a file
    ExecFile(String),

    /// Get a variable, expecting an AnyLuaValue
    GetValue(LuaIdentifier),
    /// Invoke a function found at the position,
    /// with the specified arguments.
    Invoke(LuaIdentifier, Vec<AnyLuaValue>),
    /// Set a value
    SetValue {
        /// The name of the thing to stuff
        name: LuaIdentifier,
        /// The value to store.
        val: Json
    },
    /// Create a new table
    NewTable(LuaIdentifier),
}

/// Messages received from lua thread
pub enum LuaResponse {
    /// Lua variable obtained
    Variable(Option<AnyLuaValue>),
    /// Lua error
    Error(hlua::LuaError),
    /// A function is returned
    Function(hlua::functions_read::LuaFunction<String>),
    /// Pong response from lua ping
    Pong,
}

#[derive(Debug)]
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaQuery { }
unsafe impl Sync for LuaQuery { }
unsafe impl Send for LuaResponse { }
unsafe impl Sync for LuaResponse { }
unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaResponse {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        match *self {
            LuaResponse::Variable(ref var) =>
                write!(f, "LuaResponse::Variable({:?})", var),
            LuaResponse::Error(ref err) =>
                write!(f, "LuaResponse::Error({:?})", err),
            LuaResponse::Function(_) =>
                write!(f, "LuaResponse::Function"),
            LuaResponse::Pong =>
                write!(f, "LuaResponse::Pong")
        }
    }
}

/// Whether the lua thread is currently available
pub fn thread_running() -> bool {
    *RUNNING.read().unwrap()
}

/// Errors which may arise from attempting
/// to sending a message to the lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

/// Attemps to send a LuaQuery to the lua thread.
pub fn try_send(query: LuaQuery) -> Result<Receiver<LuaResponse>,LuaSendError> {
    if !thread_running() {
        Err(LuaSendError::ThreadClosed)
    }
    else if let Some(ref sender) = *SENDER.lock().unwrap() {
        let (tx, rx) = channel();
        let message = LuaMessage { reply: tx, query: query };
        match sender.send(message) {
            Ok(_) => Ok(rx),
            Err(e) => Err(LuaSendError::Sender(e.0.query))
        }
    }
    else {
        Err(LuaSendError::ThreadUninitialized)
    }
}

/// Initialize the lua thread
pub fn init() {
    trace!("Initializing...");
    let (query_tx, query_rx) = channel::<LuaMessage>();
    let (answer_tx, answer_rx) = channel::<LuaResponse>();
    {
        let mut sender = SENDER.lock().unwrap();
        let mut receiver = RECEIVER.lock().unwrap();

        *sender = Some(query_tx);
        *receiver = Some(answer_rx);
    }

    thread::spawn(move || {
        thread_init(answer_tx, query_rx);
    });
    trace!("Created thread. Init finished.");
}

fn thread_init(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>) {
    trace!("thread: initializing.");
    let mut lua = Lua::new();
    //unsafe {
    //    hlua_ffi::lua_atpanic(&mut lua.as_mut_lua().0, thread_on_panic);
    //}
    debug!("thread: Loading Lua libraries...");
    lua.openlibs();
    trace!("thread: Loading way-cooler lua extensions...");
    // We should have some good file handling, read files from /usr by default,
    // but for now we're reading directly from the source.
    lua.execute_from_reader::<(), File>(
        File::open("lib/lua/init.lua").unwrap()
    ).unwrap();
    trace!("thread: loading way-cooler libraries...");
    funcs::register_libraries(&mut lua);
    // Only ready after loading libs
    *RUNNING.write().unwrap() = true;
    debug!("thread: entering main loop...");
    thread_main_loop(sender, receiver, &mut lua);
}

fn thread_main_loop(sender: Sender<LuaResponse>, receiver: Receiver<LuaQuery>,
                    lua: &mut Lua) {
    loop {
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().unwrap() = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                thread_handle_message(&sender, message, lua);
            }
        }
    }
}

fn thread_handle_message(sender: &Sender<LuaResponse>,
                         request: LuaQuery, lua: &mut Lua) {
    match request {
        LuaQuery::Terminate => {
            trace!("thread: Received terminate signal");
            *RUNNING.write().unwrap() = false;

            info!("thread: Lua thread terminating!");
            return;
        },

        LuaQuery::Restart => {
            trace!("thread: Received restart signal!");
            error!("thread: Lua thread restart not supported!");

            *RUNNING.write().unwrap() = false;

            panic!("Lua thread: Restart not supported!");
        },

        LuaQuery::Execute(code) => {
            trace!("thread: Received request to execute code");
            trace!("thread: Executing {:?}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("thread: Error executing code: {:?}", error);
                    let response = LuaResponse::Error(error);

                    thread_send(&sender, response);
                }
                Ok(_) => {
                    // This is gonna be really spammy one day
                    trace!("thread: Code executed okay.");
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            trace!("thread: Received request to execute file {}", name);
            info!("thread: Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("thread: Error executing {}!", name);

                    thread_send(&sender, LuaResponse::Error(err));
                }
                else {
                    trace!("thread: Execution of {} successful.", name);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(&sender, LuaResponse::Error(read_error));
            }
        },

        LuaQuery::GetValue(varname) => {
            trace!("thread: Received request to get variable {:?}", varname);
            let var_result = lua.get(format!("{:?}", varname));

            match var_result {
                Some(var) => {
                    thread_send(&sender, LuaResponse::Variable(Some(var)));
                }
                None => {
                    warn!("thread: Unable to get variable {:?}", varname);

                    thread_send(&sender, LuaResponse::Variable(None));
                }
            }
        },

        LuaQuery::SetValue { name: _name, val: _val } => {
            panic!("thread: unimplemented LuaQuery::SetValue!");
        },

        LuaQuery::NewTable(_name) => {
            panic!("thread: unimplemented LuaQuery::NewTable!");
        },

        LuaQuery::Ping => {
            panic!("thread: unimplemented LuaQuery::Ping!");
        },
        _ => {
            panic!("Unimplemented send type for lua thread!");
        }
    }
}

fn thread_send(sender: &Sender<LuaResponse>, response: LuaResponse) {
    trace!("Called thread_send");
    match sender.send(response) {
        Err(_) => {
            error!("thread: Unable to broadcast response!");
            error!("thread: Shutting down in response to inability \
                    to continue!");
            panic!("Lua thread unable to communicate with main thread, \
                    shutting down!");
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::{
    cell::RefCell,
    rc::Rc,
    sync::{Arc, Mutex},
};

use rand;

use smithay::{
    reexports::wayland_server::{
        protocol::{wl_buffer, wl_pointer::ButtonState, wl_shell_surface, wl_surface},
        Display,
    },
    utils::Rectangle,
    wayland::{
        compositor::{compositor_init, CompositorToken, RegionAttributes, SurfaceAttributes, SurfaceEvent},
        data_device::DnDIconRole,
        seat::{AxisFrame, CursorImageRole, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
        shell::{
            legacy::{
                wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
            },
            xdg::{
                xdg_shell_init, PopupConfigure, ShellState as XdgShellState, ToplevelConfigure, XdgRequest,
                XdgSurfaceRole,
            },
        },
        SERIAL_COUNTER as SCOUNTER,
    },
};

use crate::{
    buffer_utils::BufferUtils,
    window_map::{Kind as SurfaceKind, WindowMap},
};

define_roles!(Roles =>
    [ XdgSurface, XdgSurfaceRole ]
    [ ShellSurface, ShellSurfaceRole]
    [ DnDIcon, DnDIconRole ]
    [ CursorImage, CursorImageRole ]
);

pub type MyWindowMap = WindowMap<
    Roles,
    fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    fn(&SurfaceAttributes, (f64, f64)) -> bool,
>;

pub type MyCompositorToken = CompositorToken<Roles>;

struct MoveSurfaceGrab {
    start_data: GrabStartData,
    window_map: Rc<RefCell<MyWindowMap>>,
    toplevel: SurfaceKind<Roles>,
    initial_window_location: (i32, i32),
}

impl PointerGrab for MoveSurfaceGrab {
    fn motion(
        &mut self,
        _handle: &mut PointerInnerHandle<'_>,
        location: (f64, f64),
        _focus: Option<(wl_surface::WlSurface, (f64, f64))>,
        _serial: u32,
        _time: u32,
    ) {
        let dx = location.0 - self.start_data.location.0;
        let dy = location.1 - self.start_data.location.1;
        let new_window_x = (self.initial_window_location.0 as f64 + dx) as i32;
        let new_window_y = (self.initial_window_location.1 as f64 + dy) as i32;

        self.window_map
            .borrow_mut()
            .set_location(&self.toplevel, (new_window_x, new_window_y));
    }

    fn button(
        &mut self,
        handle: &mut PointerInnerHandle<'_>,
        button: u32,
        state: ButtonState,
        serial: u32,
        time: u32,
    ) {
        handle.button(button, state, serial, time);
        if handle.current_pressed().is_empty() {
            // No more buttons are pressed, release the grab.
            handle.unset_grab(serial, time);
        }
    }

    fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) {
        handle.axis(details)
    }

    fn start_data(&self) -> &GrabStartData {
        &self.start_data
    }
}

pub fn init_shell(
    display: &mut Display,
    buffer_utils: BufferUtils,
    log: ::slog::Logger,
) -> (
    CompositorToken<Roles>,
    Arc<Mutex<XdgShellState<Roles>>>,
    Arc<Mutex<WlShellState<Roles>>>,
    Rc<RefCell<MyWindowMap>>,
) {
    // Create the compositor
    let (compositor_token, _, _) = compositor_init(
        display,
        move |request, surface, ctoken| match request {
            SurfaceEvent::Commit => surface_commit(&surface, ctoken, &buffer_utils),
            SurfaceEvent::Frame { callback } => callback
                .implement_closure(|_, _| unreachable!(), None::<fn(_)>, ())
                .done(0),
        },
        log.clone(),
    );

    // Init a window map, to track the location of our windows
    let window_map = Rc::new(RefCell::new(WindowMap::new(
        compositor_token,
        get_size as _,
        contains_point as _,
    )));

    // init the xdg_shell
    let xdg_window_map = window_map.clone();
    let (xdg_shell_state, _, _) = xdg_shell_init(
        display,
        compositor_token,
        move |shell_event| match shell_event {
            XdgRequest::NewToplevel { surface } => {
                // place the window at a random location in the [0;800]x[0;800] square
                use rand::distributions::{Distribution, Uniform};
                let range = Uniform::new(0, 800);
                let mut rng = rand::thread_rng();
                let x = range.sample(&mut rng);
                let y = range.sample(&mut rng);
                surface.send_configure(ToplevelConfigure {
                    size: None,
                    states: vec![],
                    serial: 42,
                });
                xdg_window_map
                    .borrow_mut()
                    .insert(SurfaceKind::Xdg(surface), (x, y));
            }
            XdgRequest::NewPopup { surface } => surface.send_configure(PopupConfigure {
                size: (10, 10),
                position: (10, 10),
                serial: 42,
            }),
            XdgRequest::Move {
                surface,
                seat,
                serial,
            } => {
                let seat = Seat::from_resource(&seat).unwrap();
                // TODO: touch move.
                let pointer = seat.get_pointer().unwrap();

                // Check that this surface has a click grab.
                if !pointer.has_grab(serial) {
                    return;
                }

                let start_data = pointer.grab_start_data().unwrap();

                // If the focus was for a different surface, ignore the request.
                if start_data.focus.is_none()
                    || !start_data
                        .focus
                        .as_ref()
                        .unwrap()
                        .0
                        .as_ref()
                        .same_client_as(surface.get_surface().unwrap().as_ref())
                {
                    return;
                }

                let toplevel = SurfaceKind::Xdg(surface);
                let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap();

                let grab = MoveSurfaceGrab {
                    start_data,
                    window_map: xdg_window_map.clone(),
                    toplevel,
                    initial_window_location,
                };

                pointer.set_grab(grab, serial);
            }
            _ => (),
        },
        log.clone(),
    );

    // init the wl_shell
    let shell_window_map = window_map.clone();
    let (wl_shell_state, _) = wl_shell_init(
        display,
        compositor_token,
        move |req: ShellRequest<_>| {
            match req {
                ShellRequest::SetKind {
                    surface,
                    kind: ShellSurfaceKind::Toplevel,
                } => {
                    // place the window at a random location in the [0;800]x[0;800] square
                    use rand::distributions::{Distribution, Uniform};
                    let range = Uniform::new(0, 800);
                    let mut rng = rand::thread_rng();
                    let x = range.sample(&mut rng);
                    let y = range.sample(&mut rng);
                    surface.send_configure((0, 0), wl_shell_surface::Resize::None);
                    shell_window_map
                        .borrow_mut()
                        .insert(SurfaceKind::Wl(surface), (x, y));
                }
                ShellRequest::Move {
                    surface,
                    seat,
                    serial,
                } => {
                    let seat = Seat::from_resource(&seat).unwrap();
                    // TODO: touch move.
                    let pointer = seat.get_pointer().unwrap();

                    // Check that this surface has a click grab.
                    if !pointer.has_grab(serial) {
                        return;
                    }

                    let start_data = pointer.grab_start_data().unwrap();

                    // If the focus was for a different surface, ignore the request.
                    if start_data.focus.is_none()
                        || !start_data
                            .focus
                            .as_ref()
                            .unwrap()
                            .0
                            .as_ref()
                            .same_client_as(surface.get_surface().unwrap().as_ref())
                    {
                        return;
                    }

                    let toplevel = SurfaceKind::Wl(surface);
                    let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap();

                    let grab = MoveSurfaceGrab {
                        start_data,
                        window_map: shell_window_map.clone(),
                        toplevel,
                        initial_window_location,
                    };

                    pointer.set_grab(grab, serial);
                }
                _ => (),
            }
        },
        log.clone(),
    );

    (compositor_token, xdg_shell_state, wl_shell_state, window_map)
}

#[derive(Default)]
pub struct SurfaceData {
    pub buffer: Option<wl_buffer::WlBuffer>,
    pub texture: Option<crate::glium_drawer::TextureMetadata>,
    pub dimensions: Option<(i32, i32)>,
    pub input_region: Option<RegionAttributes>,
}

fn surface_commit(
    surface: &wl_surface::WlSurface,
    token: CompositorToken<Roles>,
    buffer_utils: &BufferUtils,
) {
    token.with_surface_data(surface, |attributes| {
        attributes.user_data.insert_if_missing(SurfaceData::default);
        let data = attributes.user_data.get_mut::<SurfaceData>().unwrap();

        data.input_region = attributes.input_region.clone();

        // we retrieve the contents of the associated buffer and copy it
        match attributes.buffer.take() {
            Some(Some((buffer, (_x, _y)))) => {
                // new contents
                // TODO: handle hotspot coordinates
                if let Some(old_buffer) = data.buffer.replace(buffer) {
                    old_buffer.release();
                }
                data.texture = None;
                // If this fails, the buffer will be discarded later by the drawing code.
                data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap());
            }
            Some(None) => {
                // erase the contents
                if let Some(old_buffer) = data.buffer.take() {
                    old_buffer.release();
                }
                data.texture = None;
                data.dimensions = None;
            }
            None => {}
        }
    });
}

fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> {
    attrs
        .user_data
        .get::<SurfaceData>()
        .and_then(|data| data.dimensions)
}

fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool {
    let (w, h) = match get_size(attrs) {
        None => return false, // If the surface has no size, it can't have an input region.
        Some(wh) => wh,
    };

    let rect = Rectangle {
        x: 0,
        y: 0,
        width: w,
        height: h,
    };

    let point = (point.0 as i32, point.1 as i32);

    // The input region is always within the surface itself, so if the surface itself doesn't contain the
    // point we can return false.
    if !rect.contains(point) {
        return false;
    }

    let input_region = &attrs.user_data.get::<SurfaceData>().unwrap().input_region;

    // If there's no input region, we're done.
    if input_region.is_none() {
        return true;
    }

    input_region.as_ref().unwrap().contains(point)
}
<commit_msg>anvil.shell: don't send first configure to WlShell<commit_after>use std::{
    cell::RefCell,
    rc::Rc,
    sync::{Arc, Mutex},
};

use rand;

use smithay::{
    reexports::wayland_server::{
        protocol::{wl_buffer, wl_pointer::ButtonState, wl_shell_surface, wl_surface},
        Display,
    },
    utils::Rectangle,
    wayland::{
        compositor::{compositor_init, CompositorToken, RegionAttributes, SurfaceAttributes, SurfaceEvent},
        data_device::DnDIconRole,
        seat::{AxisFrame, CursorImageRole, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
        shell::{
            legacy::{
                wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind, ShellSurfaceRole,
            },
            xdg::{
                xdg_shell_init, PopupConfigure, ShellState as XdgShellState, ToplevelConfigure, XdgRequest,
                XdgSurfaceRole,
            },
        },
        SERIAL_COUNTER as SCOUNTER,
    },
};

use crate::{
    buffer_utils::BufferUtils,
    window_map::{Kind as SurfaceKind, WindowMap},
};

define_roles!(Roles =>
    [ XdgSurface, XdgSurfaceRole ]
    [ ShellSurface, ShellSurfaceRole]
    [ DnDIcon, DnDIconRole ]
    [ CursorImage, CursorImageRole ]
);

pub type MyWindowMap = WindowMap<
    Roles,
    fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    fn(&SurfaceAttributes, (f64, f64)) -> bool,
>;

pub type MyCompositorToken = CompositorToken<Roles>;

struct MoveSurfaceGrab {
    start_data: GrabStartData,
    window_map: Rc<RefCell<MyWindowMap>>,
    toplevel: SurfaceKind<Roles>,
    initial_window_location: (i32, i32),
}

impl PointerGrab for MoveSurfaceGrab {
    fn motion(
        &mut self,
        _handle: &mut PointerInnerHandle<'_>,
        location: (f64, f64),
        _focus: Option<(wl_surface::WlSurface, (f64, f64))>,
        _serial: u32,
        _time: u32,
    ) {
        let dx = location.0 - self.start_data.location.0;
        let dy = location.1 - self.start_data.location.1;
        let new_window_x = (self.initial_window_location.0 as f64 + dx) as i32;
        let new_window_y = (self.initial_window_location.1 as f64 + dy) as i32;

        self.window_map
            .borrow_mut()
            .set_location(&self.toplevel, (new_window_x, new_window_y));
    }

    fn button(
        &mut self,
        handle: &mut PointerInnerHandle<'_>,
        button: u32,
        state: ButtonState,
        serial: u32,
        time: u32,
    ) {
        handle.button(button, state, serial, time);
        if handle.current_pressed().is_empty() {
            // No more buttons are pressed, release the grab.
            handle.unset_grab(serial, time);
        }
    }

    fn axis(&mut self, handle: &mut PointerInnerHandle<'_>, details: AxisFrame) {
        handle.axis(details)
    }

    fn start_data(&self) -> &GrabStartData {
        &self.start_data
    }
}

pub fn init_shell(
    display: &mut Display,
    buffer_utils: BufferUtils,
    log: ::slog::Logger,
) -> (
    CompositorToken<Roles>,
    Arc<Mutex<XdgShellState<Roles>>>,
    Arc<Mutex<WlShellState<Roles>>>,
    Rc<RefCell<MyWindowMap>>,
) {
    // Create the compositor
    let (compositor_token, _, _) = compositor_init(
        display,
        move |request, surface, ctoken| match request {
            SurfaceEvent::Commit => surface_commit(&surface, ctoken, &buffer_utils),
            SurfaceEvent::Frame { callback } => callback
                .implement_closure(|_, _| unreachable!(), None::<fn(_)>, ())
                .done(0),
        },
        log.clone(),
    );

    // Init a window map, to track the location of our windows
    let window_map = Rc::new(RefCell::new(WindowMap::new(
        compositor_token,
        get_size as _,
        contains_point as _,
    )));

    // init the xdg_shell
    let xdg_window_map = window_map.clone();
    let (xdg_shell_state, _, _) = xdg_shell_init(
        display,
        compositor_token,
        move |shell_event| match shell_event {
            XdgRequest::NewToplevel { surface } => {
                // place the window at a random location in the [0;800]x[0;800] square
                use rand::distributions::{Distribution, Uniform};
                let range = Uniform::new(0, 800);
                let mut rng = rand::thread_rng();
                let x = range.sample(&mut rng);
                let y = range.sample(&mut rng);
                surface.send_configure(ToplevelConfigure {
                    size: None,
                    states: vec![],
                    serial: 42,
                });
                xdg_window_map
                    .borrow_mut()
                    .insert(SurfaceKind::Xdg(surface), (x, y));
            }
            XdgRequest::NewPopup { surface } => surface.send_configure(PopupConfigure {
                size: (10, 10),
                position: (10, 10),
                serial: 42,
            }),
            XdgRequest::Move {
                surface,
                seat,
                serial,
            } => {
                let seat = Seat::from_resource(&seat).unwrap();
                // TODO: touch move.
                let pointer = seat.get_pointer().unwrap();

                // Check that this surface has a click grab.
                if !pointer.has_grab(serial) {
                    return;
                }

                let start_data = pointer.grab_start_data().unwrap();

                // If the focus was for a different surface, ignore the request.
                if start_data.focus.is_none()
                    || !start_data
                        .focus
                        .as_ref()
                        .unwrap()
                        .0
                        .as_ref()
                        .same_client_as(surface.get_surface().unwrap().as_ref())
                {
                    return;
                }

                let toplevel = SurfaceKind::Xdg(surface);
                let initial_window_location = xdg_window_map.borrow().location(&toplevel).unwrap();

                let grab = MoveSurfaceGrab {
                    start_data,
                    window_map: xdg_window_map.clone(),
                    toplevel,
                    initial_window_location,
                };

                pointer.set_grab(grab, serial);
            }
            _ => (),
        },
        log.clone(),
    );

    // init the wl_shell
    let shell_window_map = window_map.clone();
    let (wl_shell_state, _) = wl_shell_init(
        display,
        compositor_token,
        move |req: ShellRequest<_>| {
            match req {
                ShellRequest::SetKind {
                    surface,
                    kind: ShellSurfaceKind::Toplevel,
                } => {
                    // place the window at a random location in the [0;800]x[0;800] square
                    use rand::distributions::{Distribution, Uniform};
                    let range = Uniform::new(0, 800);
                    let mut rng = rand::thread_rng();
                    let x = range.sample(&mut rng);
                    let y = range.sample(&mut rng);
                    shell_window_map
                        .borrow_mut()
                        .insert(SurfaceKind::Wl(surface), (x, y));
                }
                ShellRequest::Move {
                    surface,
                    seat,
                    serial,
                } => {
                    let seat = Seat::from_resource(&seat).unwrap();
                    // TODO: touch move.
                    let pointer = seat.get_pointer().unwrap();

                    // Check that this surface has a click grab.
                    if !pointer.has_grab(serial) {
                        return;
                    }

                    let start_data = pointer.grab_start_data().unwrap();

                    // If the focus was for a different surface, ignore the request.
                    if start_data.focus.is_none()
                        || !start_data
                            .focus
                            .as_ref()
                            .unwrap()
                            .0
                            .as_ref()
                            .same_client_as(surface.get_surface().unwrap().as_ref())
                    {
                        return;
                    }

                    let toplevel = SurfaceKind::Wl(surface);
                    let initial_window_location = shell_window_map.borrow().location(&toplevel).unwrap();

                    let grab = MoveSurfaceGrab {
                        start_data,
                        window_map: shell_window_map.clone(),
                        toplevel,
                        initial_window_location,
                    };

                    pointer.set_grab(grab, serial);
                }
                _ => (),
            }
        },
        log.clone(),
    );

    (compositor_token, xdg_shell_state, wl_shell_state, window_map)
}

#[derive(Default)]
pub struct SurfaceData {
    pub buffer: Option<wl_buffer::WlBuffer>,
    pub texture: Option<crate::glium_drawer::TextureMetadata>,
    pub dimensions: Option<(i32, i32)>,
    pub input_region: Option<RegionAttributes>,
}

fn surface_commit(
    surface: &wl_surface::WlSurface,
    token: CompositorToken<Roles>,
    buffer_utils: &BufferUtils,
) {
    token.with_surface_data(surface, |attributes| {
        attributes.user_data.insert_if_missing(SurfaceData::default);
        let data = attributes.user_data.get_mut::<SurfaceData>().unwrap();

        data.input_region = attributes.input_region.clone();

        // we retrieve the contents of the associated buffer and copy it
        match attributes.buffer.take() {
            Some(Some((buffer, (_x, _y)))) => {
                // new contents
                // TODO: handle hotspot coordinates
                if let Some(old_buffer) = data.buffer.replace(buffer) {
                    old_buffer.release();
                }
                data.texture = None;
                // If this fails, the buffer will be discarded later by the drawing code.
                data.dimensions = buffer_utils.dimensions(data.buffer.as_ref().unwrap());
            }
            Some(None) => {
                // erase the contents
                if let Some(old_buffer) = data.buffer.take() {
                    old_buffer.release();
                }
                data.texture = None;
                data.dimensions = None;
            }
            None => {}
        }
    });
}

fn get_size(attrs: &SurfaceAttributes) -> Option<(i32, i32)> {
    attrs
        .user_data
        .get::<SurfaceData>()
        .and_then(|data| data.dimensions)
}

fn contains_point(attrs: &SurfaceAttributes, point: (f64, f64)) -> bool {
    let (w, h) = match get_size(attrs) {
        None => return false, // If the surface has no size, it can't have an input region.
        Some(wh) => wh,
    };

    let rect = Rectangle {
        x: 0,
        y: 0,
        width: w,
        height: h,
    };

    let point = (point.0 as i32, point.1 as i32);

    // The input region is always within the surface itself, so if the surface itself doesn't contain the
    // point we can return false.
    if !rect.contains(point) {
        return false;
    }

    let input_region = &attrs.user_data.get::<SurfaceData>().unwrap().input_region;

    // If there's no input region, we're done.
    if input_region.is_none() {
        return true;
    }

    input_region.as_ref().unwrap().contains(point)
}
<|endoftext|>


<commit_before>extern crate zmq;

fn main() {
    let mut context = zmq::Context::new();
    let _poll_item = {
        let socket = context.socket(zmq::PAIR).unwrap();
        socket.as_poll_item(0) //~ ERROR `socket` does not live long enough
    };
}
<commit_msg>Fix compiletest failure on nightly<commit_after>extern crate zmq;

fn main() {
    let mut context = zmq::Context::new();
    let _poll_item = {
        let socket = context.socket(zmq::PAIR).unwrap();
        socket.as_poll_item(0)
    }; //~ ERROR `socket` does not live long enough
}
<|endoftext|>


<commit_before>use crate::zx::constants::BORDER_COLS;
use alloc::{vec, vec::Vec};

/// Immutable type (Builder is not public in outer module)
pub struct ZXSpecs {
    // frequencies
    pub freq_cpu: usize,
    // first_pixel_read_clocks (contention start)
    pub clocks_first_pixel: usize,
    // row clocks
    pub clocks_left_border: usize,
    pub clocks_screen_row: usize,
    pub clocks_right_border: usize,
    pub clocks_retrace: usize,
    pub clocks_line: usize,
    pub clocks_line_base: Vec<usize>,
    // some ula clocks
    pub clocks_ula_read_shift: usize,
    pub clocks_ula_read_origin: usize,
    pub clocks_ula_contention_origin: usize,
    pub clocks_ula_beam_shift: usize,
    // frame
    pub clocks_frame: usize,
    // lines metrics
    pub lines_vsync: usize,
    pub lines_top_border: usize,
    pub lines_screen: usize,
    pub lines_bottom_border: usize,
    pub lines_all: usize,
    // interrupt
    pub interrupt_length: usize,
    // contention
    pub contention_offset: usize,
    pub contention_pattern: [usize; 8],
    pub rom_pages: u8,
}

/// Specs builder, used to make static valiables with machines specs
pub struct ZXSpecsBuilder {
    specs: ZXSpecs,
}
impl ZXSpecsBuilder {
    /// Returns new ZXSpecsBuilder
    pub fn new() -> ZXSpecsBuilder {
        ZXSpecsBuilder {
            specs: ZXSpecs {
                // frequencies
                freq_cpu: 0,
                // first_pixel_clocks
                clocks_first_pixel: 0,
                // row clocks
                clocks_left_border: 0,
                clocks_screen_row: 0,
                clocks_right_border: 0,
                clocks_retrace: 0,
                clocks_line: 0,
                clocks_line_base: vec![],
                // some ula clocks
                clocks_ula_read_shift: 0,
                clocks_ula_read_origin: 0,
                clocks_ula_contention_origin: 0,
                clocks_ula_beam_shift: 0,
                // frame clocks
                clocks_frame: 0,
                // lines metrics
                lines_vsync: 0,
                lines_top_border: 0,
                lines_screen: 0,
                lines_bottom_border: 0,
                lines_all: 0,
                // interrupt
                interrupt_length: 0,
                // contention
                contention_offset: 0,
                contention_pattern: [0; 8],
                // memory
                rom_pages: 0,
            },
        }
    }

    /// Builds new ZXSpecs
    pub fn build(mut self) -> ZXSpecs {
        self.specs.clocks_frame =
            (self.specs.lines_all + self.specs.lines_vsync) * self.specs.clocks_line;
        // 4*4 is 4 border columns * 4 clocks per column
        self.specs.clocks_line_base.push(
            self.specs.clocks_first_pixel
                - self.specs.lines_top_border * self.specs.clocks_line
                - BORDER_COLS * 4,
        );
        // + 1 because TStates in calculations may be > frame length (CHECK)
        let lines_count = self.specs.lines_all + 1;
        for _ in 1..lines_count {
            let last = *self.specs.clocks_line_base.last().unwrap();
            let line_clocks = self.specs.clocks_line;
            self.specs.clocks_line_base.push(last + line_clocks);
        }
        self.specs.clocks_ula_read_origin =
            self.specs.clocks_first_pixel + self.specs.clocks_ula_read_shift;
        self.specs.clocks_ula_contention_origin =
            self.specs.clocks_first_pixel - self.specs.contention_offset;
        self.specs
    }

    /// Changes CPU frequency
    pub fn freq_cpu(mut self, value: usize) -> Self {
        self.specs.freq_cpu = value;
        self
    }

    /// Changes Clocks per left border, screen render, left border and retrace
    pub fn clocks_row(
        mut self,
        lborder: usize,
        screen: usize,
        rborder: usize,
        retrace: usize,
    ) -> Self {
        self.specs.clocks_left_border = lborder;
        self.specs.clocks_screen_row = screen;
        self.specs.clocks_right_border = rborder;
        self.specs.clocks_retrace = retrace;
        self.specs.clocks_line = lborder + screen + rborder + retrace;
        self
    }

    /// Changes first pixel clocks
    pub fn clocks_first_pixel(mut self, value: usize) -> Self {
        self.specs.clocks_first_pixel = value;
        self
    }

    /// Changes shift of time, when ula reads data from memory
    pub fn clocks_ula_read_shift(mut self, value: usize) -> Self {
        self.specs.clocks_ula_read_shift = value;
        self
    }

    /// Changes shift of electron beam pixel rendering
    pub fn clocks_ula_beam_shift(mut self, value: usize) -> Self {
        self.specs.clocks_ula_beam_shift = value;
        self
    }

    /// Changes lines per top border, screen, bottom border and vsync
    pub fn lines(mut self, tborder: usize, screen: usize, bborder: usize, vsync: usize) -> Self {
        self.specs.lines_vsync = vsync;
        self.specs.lines_top_border = tborder;
        self.specs.lines_screen = screen;
        self.specs.lines_bottom_border = bborder;
        self.specs.lines_all = tborder + screen + bborder;
        self
    }

    /// Changes contention pattern
    pub fn contention(mut self, pattern: [usize; 8], offset: usize) -> Self {
        self.specs.contention_pattern = pattern;
        self.specs.contention_offset = offset;
        self
    }

    /// changes interrupt length
    pub fn interrupt_length(mut self, value: usize) -> Self {
        self.specs.interrupt_length = value;
        self
    }

    pub fn rom_pages(mut self, value: u8) -> Self {
        self.specs.rom_pages = value;
        self
    }
}
<commit_msg>Removed redundant dynamic allocation from ZXSpecs<commit_after>pub struct ZXSpecs {
    // frequencies
    pub freq_cpu: usize,
    // first_pixel_read_clocks (contention start)
    pub clocks_first_pixel: usize,
    // row clocks
    pub clocks_left_border: usize,
    pub clocks_screen_row: usize,
    pub clocks_right_border: usize,
    pub clocks_retrace: usize,
    pub clocks_line: usize,
    // some ula clocks
    pub clocks_ula_read_shift: usize,
    pub clocks_ula_read_origin: usize,
    pub clocks_ula_contention_origin: usize,
    pub clocks_ula_beam_shift: usize,
    // frame
    pub clocks_frame: usize,
    // lines metrics
    pub lines_vsync: usize,
    pub lines_top_border: usize,
    pub lines_screen: usize,
    pub lines_bottom_border: usize,
    pub lines_all: usize,
    // interrupt
    pub interrupt_length: usize,
    // contention
    pub contention_offset: usize,
    pub contention_pattern: [usize; 8],
    pub rom_pages: u8,
}

/// Specs builder, used to make static valiables with machines specs
pub struct ZXSpecsBuilder {
    specs: ZXSpecs,
}
impl ZXSpecsBuilder {
    /// Returns new ZXSpecsBuilder
    pub fn new() -> ZXSpecsBuilder {
        ZXSpecsBuilder {
            specs: ZXSpecs {
                // frequencies
                freq_cpu: 0,
                // first_pixel_clocks
                clocks_first_pixel: 0,
                // row clocks
                clocks_left_border: 0,
                clocks_screen_row: 0,
                clocks_right_border: 0,
                clocks_retrace: 0,
                clocks_line: 0,
                // some ula clocks
                clocks_ula_read_shift: 0,
                clocks_ula_read_origin: 0,
                clocks_ula_contention_origin: 0,
                clocks_ula_beam_shift: 0,
                // frame clocks
                clocks_frame: 0,
                // lines metrics
                lines_vsync: 0,
                lines_top_border: 0,
                lines_screen: 0,
                lines_bottom_border: 0,
                lines_all: 0,
                // interrupt
                interrupt_length: 0,
                // contention
                contention_offset: 0,
                contention_pattern: [0; 8],
                // memory
                rom_pages: 0,
            },
        }
    }

    /// Builds new ZXSpecs
    pub fn build(mut self) -> ZXSpecs {
        self.specs.clocks_frame =
            (self.specs.lines_all + self.specs.lines_vsync) * self.specs.clocks_line;
        self.specs.clocks_ula_read_origin =
            self.specs.clocks_first_pixel + self.specs.clocks_ula_read_shift;
        self.specs.clocks_ula_contention_origin =
            self.specs.clocks_first_pixel - self.specs.contention_offset;
        self.specs
    }

    /// Changes CPU frequency
    pub fn freq_cpu(mut self, value: usize) -> Self {
        self.specs.freq_cpu = value;
        self
    }

    /// Changes Clocks per left border, screen render, left border and retrace
    pub fn clocks_row(
        mut self,
        lborder: usize,
        screen: usize,
        rborder: usize,
        retrace: usize,
    ) -> Self {
        self.specs.clocks_left_border = lborder;
        self.specs.clocks_screen_row = screen;
        self.specs.clocks_right_border = rborder;
        self.specs.clocks_retrace = retrace;
        self.specs.clocks_line = lborder + screen + rborder + retrace;
        self
    }

    /// Changes first pixel clocks
    pub fn clocks_first_pixel(mut self, value: usize) -> Self {
        self.specs.clocks_first_pixel = value;
        self
    }

    /// Changes shift of time, when ula reads data from memory
    pub fn clocks_ula_read_shift(mut self, value: usize) -> Self {
        self.specs.clocks_ula_read_shift = value;
        self
    }

    /// Changes shift of electron beam pixel rendering
    pub fn clocks_ula_beam_shift(mut self, value: usize) -> Self {
        self.specs.clocks_ula_beam_shift = value;
        self
    }

    /// Changes lines per top border, screen, bottom border and vsync
    pub fn lines(mut self, tborder: usize, screen: usize, bborder: usize, vsync: usize) -> Self {
        self.specs.lines_vsync = vsync;
        self.specs.lines_top_border = tborder;
        self.specs.lines_screen = screen;
        self.specs.lines_bottom_border = bborder;
        self.specs.lines_all = tborder + screen + bborder;
        self
    }

    /// Changes contention pattern
    pub fn contention(mut self, pattern: [usize; 8], offset: usize) -> Self {
        self.specs.contention_pattern = pattern;
        self.specs.contention_offset = offset;
        self
    }

    /// changes interrupt length
    pub fn interrupt_length(mut self, value: usize) -> Self {
        self.specs.interrupt_length = value;
        self
    }

    pub fn rom_pages(mut self, value: u8) -> Self {
        self.specs.rom_pages = value;
        self
    }
}
<|endoftext|>