<commit_before>use coremidi_sys::{
    MIDITimeStamp, UInt16, MIDIPacketList, MIDIPacket, MIDIPacketListInit, MIDIPacketNext
};

use std::fmt;
use std::ops::Deref;
use std::marker::PhantomData;

use PacketList;

pub type Timestamp = u64;

const MAX_PACKET_DATA_LENGTH: usize = 0xffffusize;

/// A collection of simultaneous MIDI events.
/// See [MIDIPacket](https://developer.apple.com/reference/coremidi/midipacket).
///
pub struct Packet<'a> {
    inner: *const MIDIPacket,
    _phantom: PhantomData<&'a MIDIPacket>,
}

impl<'a> Packet<'a> {
    /// Get the packet timestamp.
    ///
    pub fn timestamp(&self) -> Timestamp {
        self.packet().timeStamp as Timestamp
    }

    /// Get the packet data. This method just gives raw MIDI bytes. You would need another
    /// library to decode them and work with higher level events.
    ///
    ///
    /// The following example:
    ///
    /// ```
    /// let packet_list = &coremidi::PacketBuffer::from_data(0, vec![0x90, 0x40, 0x7f]);
    /// for packet in packet_list.iter() {
    ///   for byte in packet.data() {
    ///     print!(" {:x}", byte);
    ///   }
    /// }
    /// ```
    ///
    /// will print:
    ///
    /// ```text
    ///  90 40 7f
    /// ```
    pub fn data(&self) -> &[u8] {
        let packet = self.packet();
        let data_ptr = &packet.data as *const u8;
        let data_len = packet.length as usize;
        unsafe { ::std::slice::from_raw_parts(data_ptr, data_len) }
    }

    #[inline]
    fn packet(&self) -> &MIDIPacket {
        unsafe { &*self.inner }
    }
}

impl<'a> fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "Packet(ptr={:x}, ts={:016x}, data=[",
                            self.inner as usize, self.timestamp() as u64);
        let result = self.data().iter().enumerate().fold(result, |prev_result, (i, b)| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => {
                    let sep = if i > 0 { ", " } else { "" };
                    write!(f, "{}{:02x}", sep, b)
                }
            }
        });
        result.and_then(|_| write!(f, "])"))
    }
}

impl<'a> fmt::Display for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "{:016x}:", self.timestamp());
        self.data().iter().fold(result, |prev_result, b| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => write!(f, " {:02x}", b)
            }
        })
    }
}

impl PacketList {

    /// Get the number of packets in the list.
    ///
    pub fn length(&self) -> usize {
        self.packet_list().numPackets as usize
    }

    /// Get an iterator for the packets in the list.
    ///
    pub fn iter<'a>(&'a self) -> PacketListIterator<'a> {
        PacketListIterator {
            count: self.length(),
            packet_ptr: &self.packet_list().packet[0],
            _phantom: ::std::marker::PhantomData::default(),
        }
    }

    #[inline]
    fn packet_list(&self) -> &MIDIPacketList {
        unsafe { &*self.0 }
    }
}

impl fmt::Debug for PacketList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "PacketList(ptr={:x}, packets=[", &self.0 as *const _ as usize);
        self.iter().enumerate().fold(result, |prev_result, (i, packet)| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => {
                    let sep = if i != 0 { ", " } else { "" };
                    write!(f, "{}{:?}", sep, packet)
                }
            }
        }).and_then(|_| write!(f, "])"))
    }
}

impl fmt::Display for PacketList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "PacketList(len={})", self.packet_list().numPackets);
        self.iter().fold(result, |prev_result, packet| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => write!(f, "\n  {}", packet)
            }
        })
    }
}

pub struct PacketListIterator<'a> {
    count: usize,
    packet_ptr: *const MIDIPacket,
    _phantom: ::std::marker::PhantomData<&'a MIDIPacket>,
}

impl<'a> Iterator for PacketListIterator<'a> {
    type Item = Packet<'a>;

    fn next(&mut self) -> Option<Packet<'a>> {
        if self.count > 0 {
            let packet = Packet { inner: self.packet_ptr, _phantom: PhantomData::default() };
            self.count -= 1;
            self.packet_ptr = unsafe { MIDIPacketNext(self.packet_ptr) };
            Some(packet)
        }
        else {
            None
        }
    }
}

const PACKET_LIST_SIZE: usize = 4;  // MIDIPacketList::numPackets: UInt32
const PACKET_SIZE: usize = 8 +      // MIDIPacket::timeStamp: MIDITimeStamp/UInt64
                           2;       // MIDIPacket::length: UInt16

/// A mutable `PacketList` builder.
///
/// A `PacketList` is an inmmutable reference to a [MIDIPacketList](https://developer.apple.com/reference/coremidi/midipacketlist) structure,
/// while a `PacketBuffer` is a mutable structure that allows to build a `PacketList` by adding packets.
/// It dereferences to a `PacketList`, so it can be used whenever a `PacketList` is needed.
///
pub struct PacketBuffer {
    data: Vec<u8>,
    packet_list: PacketList
}

impl PacketBuffer {
    /// Create an empty `PacketBuffer`.
    ///
    pub fn new() -> PacketBuffer {
        let capacity = PACKET_LIST_SIZE + PACKET_SIZE + 3;
        let mut data = Vec::<u8>::with_capacity(capacity);
        unsafe { data.set_len(PACKET_LIST_SIZE) };
        let pkt_list_ptr = data.as_mut_ptr() as *mut MIDIPacketList;
        let _ = unsafe { MIDIPacketListInit(pkt_list_ptr) };
        PacketBuffer {
            data: data,
            packet_list: PacketList(pkt_list_ptr)
        }
    }

    /// Create a `PacketBuffer` with a single packet containing the provided timestamp and data.
    ///
    /// According to the official documentation for CoreMIDI, the timestamp represents
    /// the time at which the events are to be played, where zero means "now".
    /// The timestamp applies to the first MIDI byte in the packet.
    ///
    /// Example on how to create a `PacketBuffer` with a single packet for a MIDI note on for C-5:
    ///
    /// ```
    /// let note_on = coremidi::PacketBuffer::from_data(0, vec![0x90, 0x3c, 0x7f]);
    /// ```
    #[inline]
    pub fn from_data(timestamp: Timestamp, data: Vec<u8>) -> PacketBuffer {
        Self::new().with_data(timestamp, data)
    }

    /// Add a new packet containing the provided timestamp and data.
    ///
    /// According to the official documentation for CoreMIDI, the timestamp represents
    /// the time at which the events are to be played, where zero means "now".
    /// The timestamp applies to the first MIDI byte in the packet.
    ///
    /// Example:
    ///
    /// ```
    /// let chord = coremidi::PacketBuffer::new()
    ///   .with_data(0, vec![0x90, 0x3c, 0x7f])
    ///   .with_data(0, vec![0x90, 0x40, 0x7f]);
    /// println!("{}", &chord as &coremidi::PacketList);
    /// ```
    ///
    /// The previous example should print:
    ///
    /// ```text
    /// PacketList(len=2)
    ///   0000000000000000: 90 3c 7f
    ///   0000000000000000: 90 40 7f
    /// ```
    pub fn with_data(mut self, timestamp: Timestamp, data: Vec<u8>) -> Self {
        let data_len = data.len();
        assert!(data_len < MAX_PACKET_DATA_LENGTH,
                "The maximum allowed size for a packet is {}, but found {}.",
                MAX_PACKET_DATA_LENGTH, data_len);

        let additional_size = PACKET_SIZE + data_len;
        self.data.reserve(additional_size);

        let mut pkt = unsafe {
            let total_len = self.data.len();
            self.data.set_len(total_len + additional_size);
            &mut *(&self.data[total_len] as *const _ as *mut MIDIPacket)
        };

        pkt.timeStamp = timestamp as MIDITimeStamp;
        pkt.length = data_len as UInt16;
        pkt.data[0..data_len].clone_from_slice(&data);

        let mut pkt_list = unsafe { &mut *(self.data.as_mut_ptr() as *mut MIDIPacketList) };
        pkt_list.numPackets += 1;
        self.packet_list = PacketList(pkt_list);

        self
    }
}

impl Deref for PacketBuffer {
    type Target = PacketList;

    fn deref(&self) -> &PacketList {
        &self.packet_list
    }
}

#[cfg(test)]
mod tests {
    use coremidi_sys::{MIDITimeStamp, MIDIPacketList};
    use PacketList;
    use PacketBuffer;

    #[test]
    pub fn packet_buffer_new() {
        let packet_buf = PacketBuffer::new();
        assert_eq!(packet_buf.data.len(), 4);
        assert_eq!(packet_buf.data, vec![0x00, 0x00, 0x00, 0x00]);
    }

    #[test]
    pub fn packet_buffer_with_data() {
        let packet_buf = PacketBuffer::new()
            .with_data(0x0102030405060708 as MIDITimeStamp, vec![0x90u8, 0x40, 0x7f]);
        assert_eq!(packet_buf.data.len(), 17);
        // FIXME This is platform endianess dependent
        assert_eq!(packet_buf.data, vec![
            0x01, 0x00, 0x00, 0x00,
            0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
            0x03, 0x00,
            0x90, 0x40, 0x7f]);
    }

    #[test]
    fn packet_buffer_deref() {
        let packet_buf = PacketBuffer::new();
        let packet_list: &PacketList = &packet_buf;
        assert_eq!(packet_list.0, &packet_buf.data[0] as *const _ as *const MIDIPacketList);
    }

    #[test]
    fn packet_list_length() {
        let packet_buf = PacketBuffer::new()
            .with_data(0, vec![0x90u8, 0x40, 0x7f])
            .with_data(0, vec![0x91u8, 0x40, 0x7f])
            .with_data(0, vec![0x80u8, 0x40, 0x7f])
            .with_data(0, vec![0x81u8, 0x40, 0x7f]);
        assert_eq!(packet_buf.length(), 4);
    }
}
<commit_msg>Add more packet tests<commit_after>use coremidi_sys::{
    MIDITimeStamp, UInt16, MIDIPacketList, MIDIPacket, MIDIPacketListInit, MIDIPacketNext
};

use std::fmt;
use std::ops::Deref;
use std::marker::PhantomData;

use PacketList;

pub type Timestamp = u64;

const MAX_PACKET_DATA_LENGTH: usize = 0xffffusize;

/// A collection of simultaneous MIDI events.
/// See [MIDIPacket](https://developer.apple.com/reference/coremidi/midipacket).
///
pub struct Packet<'a> {
    inner: *const MIDIPacket,
    _phantom: PhantomData<&'a MIDIPacket>,
}

impl<'a> Packet<'a> {
    /// Get the packet timestamp.
    ///
    pub fn timestamp(&self) -> Timestamp {
        self.packet().timeStamp as Timestamp
    }

    /// Get the packet data. This method just gives raw MIDI bytes. You would need another
    /// library to decode them and work with higher level events.
    ///
    ///
    /// The following example:
    ///
    /// ```
    /// let packet_list = &coremidi::PacketBuffer::from_data(0, vec![0x90, 0x40, 0x7f]);
    /// for packet in packet_list.iter() {
    ///   for byte in packet.data() {
    ///     print!(" {:x}", byte);
    ///   }
    /// }
    /// ```
    ///
    /// will print:
    ///
    /// ```text
    ///  90 40 7f
    /// ```
    pub fn data(&self) -> &[u8] {
        let packet = self.packet();
        let data_ptr = &packet.data as *const u8;
        let data_len = packet.length as usize;
        unsafe { ::std::slice::from_raw_parts(data_ptr, data_len) }
    }

    #[inline]
    // TODO: this is wrong, a &MIDIPacket must not exist if the length is smaller than 256 bytes
    fn packet(&self) -> &MIDIPacket {
        unsafe { &*self.inner }
    }
}

impl<'a> fmt::Debug for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "Packet(ptr={:x}, ts={:016x}, data=[",
                            self.inner as usize, self.timestamp() as u64);
        let result = self.data().iter().enumerate().fold(result, |prev_result, (i, b)| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => {
                    let sep = if i > 0 { ", " } else { "" };
                    write!(f, "{}{:02x}", sep, b)
                }
            }
        });
        result.and_then(|_| write!(f, "])"))
    }
}

impl<'a> fmt::Display for Packet<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "{:016x}:", self.timestamp());
        self.data().iter().fold(result, |prev_result, b| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => write!(f, " {:02x}", b)
            }
        })
    }
}

impl PacketList {

    /// Get the number of packets in the list.
    ///
    pub fn length(&self) -> usize {
        self.packet_list().numPackets as usize
    }

    /// Get an iterator for the packets in the list.
    ///
    pub fn iter<'a>(&'a self) -> PacketListIterator<'a> {
        PacketListIterator {
            count: self.length(),
            packet_ptr: &self.packet_list().packet[0],
            _phantom: ::std::marker::PhantomData::default(),
        }
    }

    #[inline]
    fn packet_list(&self) -> &MIDIPacketList {
        unsafe { &*self.0 }
    }
}

impl fmt::Debug for PacketList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "PacketList(ptr={:x}, packets=[", &self.0 as *const _ as usize);
        self.iter().enumerate().fold(result, |prev_result, (i, packet)| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => {
                    let sep = if i != 0 { ", " } else { "" };
                    write!(f, "{}{:?}", sep, packet)
                }
            }
        }).and_then(|_| write!(f, "])"))
    }
}

impl fmt::Display for PacketList {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let result = write!(f, "PacketList(len={})", self.packet_list().numPackets);
        self.iter().fold(result, |prev_result, packet| {
            match prev_result {
                Err(err) => Err(err),
                Ok(()) => write!(f, "\n  {}", packet)
            }
        })
    }
}

pub struct PacketListIterator<'a> {
    count: usize,
    packet_ptr: *const MIDIPacket,
    _phantom: ::std::marker::PhantomData<&'a MIDIPacket>,
}

impl<'a> Iterator for PacketListIterator<'a> {
    type Item = Packet<'a>;

    fn next(&mut self) -> Option<Packet<'a>> {
        if self.count > 0 {
            let packet = Packet { inner: self.packet_ptr, _phantom: PhantomData::default() };
            self.count -= 1;
            self.packet_ptr = unsafe { MIDIPacketNext(self.packet_ptr) };
            Some(packet)
        }
        else {
            None
        }
    }
}

const PACKET_LIST_HEADER_SIZE: usize = 4;  // MIDIPacketList::numPackets: UInt32
const PACKET_HEADER_SIZE: usize = 8 +      // MIDIPacket::timeStamp: MIDITimeStamp/UInt64
                                  2;       // MIDIPacket::length: UInt16

/// A mutable `PacketList` builder.
///
/// A `PacketList` is an inmmutable reference to a [MIDIPacketList](https://developer.apple.com/reference/coremidi/midipacketlist) structure,
/// while a `PacketBuffer` is a mutable structure that allows to build a `PacketList` by adding packets.
/// It dereferences to a `PacketList`, so it can be used whenever a `PacketList` is needed.
///
pub struct PacketBuffer {
    data: Vec<u8>,
    packet_list: PacketList
}

impl PacketBuffer {
    /// Create an empty `PacketBuffer`.
    ///
    pub fn new() -> PacketBuffer {
        let capacity = PACKET_LIST_HEADER_SIZE + PACKET_HEADER_SIZE + 3;
        let mut data = Vec::<u8>::with_capacity(capacity);
        unsafe { data.set_len(PACKET_LIST_HEADER_SIZE) };
        let pkt_list_ptr = data.as_mut_ptr() as *mut MIDIPacketList;
        let _ = unsafe { MIDIPacketListInit(pkt_list_ptr) };
        PacketBuffer {
            data: data,
            packet_list: PacketList(pkt_list_ptr)
        }
    }

    /// Create a `PacketBuffer` with a single packet containing the provided timestamp and data.
    ///
    /// According to the official documentation for CoreMIDI, the timestamp represents
    /// the time at which the events are to be played, where zero means "now".
    /// The timestamp applies to the first MIDI byte in the packet.
    ///
    /// Example on how to create a `PacketBuffer` with a single packet for a MIDI note on for C-5:
    ///
    /// ```
    /// let note_on = coremidi::PacketBuffer::from_data(0, vec![0x90, 0x3c, 0x7f]);
    /// ```
    #[inline]
    pub fn from_data(timestamp: Timestamp, data: Vec<u8>) -> PacketBuffer {
        Self::new().with_data(timestamp, data)
    }

    /// Add a new packet containing the provided timestamp and data.
    ///
    /// According to the official documentation for CoreMIDI, the timestamp represents
    /// the time at which the events are to be played, where zero means "now".
    /// The timestamp applies to the first MIDI byte in the packet.
    ///
    /// Example:
    ///
    /// ```
    /// let chord = coremidi::PacketBuffer::new()
    ///   .with_data(0, vec![0x90, 0x3c, 0x7f])
    ///   .with_data(0, vec![0x90, 0x40, 0x7f]);
    /// println!("{}", &chord as &coremidi::PacketList);
    /// ```
    ///
    /// The previous example should print:
    ///
    /// ```text
    /// PacketList(len=2)
    ///   0000000000000000: 90 3c 7f
    ///   0000000000000000: 90 40 7f
    /// ```
    pub fn with_data(mut self, timestamp: Timestamp, data: Vec<u8>) -> Self {
        let data_len = data.len();
        assert!(data_len < MAX_PACKET_DATA_LENGTH,
                "The maximum allowed size for a packet is {}, but found {}.",
                MAX_PACKET_DATA_LENGTH, data_len);

        let additional_size = PACKET_HEADER_SIZE + data_len;
        self.data.reserve(additional_size);

        let mut pkt = unsafe {
            let total_len = self.data.len();
            self.data.set_len(total_len + additional_size);
            &mut *(&self.data[total_len] as *const _ as *mut MIDIPacket)
        };

        pkt.timeStamp = timestamp as MIDITimeStamp;
        pkt.length = data_len as UInt16;
        pkt.data[0..data_len].clone_from_slice(&data);

        let mut pkt_list = unsafe { &mut *(self.data.as_mut_ptr() as *mut MIDIPacketList) };
        pkt_list.numPackets += 1;
        self.packet_list = PacketList(pkt_list);

        self
    }
}

impl Deref for PacketBuffer {
    type Target = PacketList;

    fn deref(&self) -> &PacketList {
        &self.packet_list
    }
}

#[cfg(test)]
mod tests {
    use coremidi_sys::{MIDITimeStamp, MIDIPacketList};
    use PacketList;
    use PacketBuffer;

    #[test]
    pub fn packet_buffer_new() {
        let packet_buf = PacketBuffer::new();
        assert_eq!(packet_buf.data.len(), 4);
        assert_eq!(packet_buf.data, vec![0x00, 0x00, 0x00, 0x00]);
    }

    #[test]
    pub fn packet_buffer_with_data() {
        let packet_buf = PacketBuffer::new()
            .with_data(0x0102030405060708 as MIDITimeStamp, vec![0x90u8, 0x40, 0x7f]);
        assert_eq!(packet_buf.data.len(), 17);
        // FIXME This is platform endianess dependent
        assert_eq!(packet_buf.data, vec![
            0x01, 0x00, 0x00, 0x00,
            0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01,
            0x03, 0x00,
            0x90, 0x40, 0x7f]);
    }

    #[test]
    fn packet_buffer_deref() {
        let packet_buf = PacketBuffer::new();
        let packet_list: &PacketList = &packet_buf;
        assert_eq!(packet_list.0, &packet_buf.data[0] as *const _ as *const MIDIPacketList);
    }

    #[test]
    fn packet_list_length() {
        let packet_buf = PacketBuffer::new()
            .with_data(0, vec![0x90u8, 0x40, 0x7f])
            .with_data(0, vec![0x91u8, 0x40, 0x7f])
            .with_data(0, vec![0x80u8, 0x40, 0x7f])
            .with_data(0, vec![0x81u8, 0x40, 0x7f]);
        assert_eq!(packet_buf.length(), 4);
    }

    #[test]
    fn compare_with_native1() {
        unsafe { build_packet_list(vec![
            (0, vec![0x90, 0x40, 0x7f]),
            (0, vec![0x90, 0x41, 0x7f]),
            (0, vec![0x90, 0x42, 0x7f])
        ]) }
    }

    #[test]
    fn compare_with_native2() {
        unsafe { build_packet_list(vec![
            (0, vec![0x90, 0x40, 0x7f]),
            (1, vec![0x90, 0x40, 0x7f]),
            (2, vec![0x90, 0x40, 0x7f])
        ]) }
    }

    #[test]
    fn compare_with_native3() {
        let mut sysex = vec![0xF0];
        for _ in 0..300 {
            sysex.push(0x00);
        }
        sysex.push(0xF7);
        unsafe { build_packet_list(vec![
            (0, vec![0x90, 0x40, 0x7f]),
            (0, vec![0x90, 0x41, 0x7f]),
            (0, sysex)
        ]) }
    }

    unsafe fn build_packet_list(packets: Vec<(MIDITimeStamp, Vec<u8>)>) {
        use coremidi_sys::{MIDIPacketList, MIDIPacketListInit, MIDIPacketListAdd};

        // allocate a buffer on the stack for building the list using native methods
        const BUFFER_SIZE: usize = 65536; // maximum allowed size
        let buffer: &mut [u8] = &mut [0; BUFFER_SIZE];
        let pkt_list_ptr = buffer.as_mut_ptr() as *mut MIDIPacketList;

        // build the list
        let mut pkt_ptr = MIDIPacketListInit(pkt_list_ptr);
        for pkt in &packets {
            pkt_ptr = MIDIPacketListAdd(pkt_list_ptr, BUFFER_SIZE as u64, pkt_ptr, pkt.0, pkt.1.len() as u64, pkt.1.as_ptr());
            assert!(!pkt_ptr.is_null());
        }
        let list_native = PacketList(pkt_list_ptr);

        // build the PacketBuffer, containing the same packets
        /*let mut packet_buf = PacketBuffer::new();
        for pkt in &packets {
            packet_buf = packet_buf.with_data(pkt.0, pkt.1.clone());
        }
        let list: &PacketList = &packet_buf;

        // check if the contents match
        assert_eq!(list_native.length(), list.length());
        // TODO: check if data matches
        */

        assert_eq!(packets.len(), list_native.length());
    }
}
<|endoftext|>


<commit_before>//! Plugin which issues vault tokens to services.

use docker_compose::v2 as dc;
use serde_yaml;
#[cfg(test)]
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;
use std::fmt::Debug;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
#[cfg(test)]
use std::rc::Rc;
use vault;
use vault::client::VaultDuration;

use plugins;
use plugins::transform::Operation;
use plugins::transform::{Plugin as PluginTransform, PluginNew};
use project::Project;
use util::{Error, err};

#[cfg(feature = "serde_macros")]
include!(concat!("vault_config.in.rs"));
#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/plugins/transform/vault_config.rs"));

/// Load a vault token from `~/.vault-token`, where the command line client
/// puts it.
fn load_vault_token_from_file() -> Result<String, Error> {
    let path = try!(env::home_dir().ok_or_else(|| {
        err("You do not appear to have a home directory")
    })).join(".vault-token");
    let mut f = try!(fs::File::open(&path).map_err(|e| {
        err!("Error opening {}: {}", path.display(), e)
    }));
    let mut result = String::new();
    try!(f.read_to_string(&mut result).map_err(|e| {
        err!("Error reading {}: {}", path.display(), e)
    }));
    Ok(result.trim().to_owned())
}

/// Find the vault token we'll use to generate new tokens.
fn find_vault_token() -> Result<String, Error> {
    env::var("VAULT_MASTER_TOKEN")
        .or_else(|_| env::var("VAULT_TOKEN"))
        .or_else(|_| load_vault_token_from_file())
        .map_err(|e| err!("{}.  You probably want to log in using the vault \
                           client or set VAULT_MASTER_TOKEN", e))
}

/// The "environment" in which to interpret a configuration file.  We don't
/// want to use the OS environment variables, but rather a fake environment
/// with a few carefully selected values.
#[derive(Debug)]
struct ConfigEnvironment<'a> {
    /// The context for our transformation, including the project, pod,
    /// etc.
    ctx: &'a plugins::Context<'a>,
    /// The name of the current service.
    service: &'a str,
}

impl<'a> dc::Environment for ConfigEnvironment<'a> {
    fn var(&self, key: &str) -> Result<String, env::VarError> {
        let result = match key {
            "PROJECT" => Ok(self.ctx.project.name()),
            "OVERRIDE" => Ok(self.ctx.ovr.name()),
            "POD" => Ok(self.ctx.pod.name()),
            "SERVICE" => Ok(self.service),
            _ => Err(env::VarError::NotPresent),
        };
        result.map(|s| s.to_owned())
    }
}

/// An abstract interface to Vault's token-generation capabilities.  We use
/// this to mock vault during tests.
trait GenerateToken: Debug {
    /// Get a `VAULT_ADDR` value to use along with this token.
    fn addr(&self) -> &str;
    /// Generate a token with the specified parameters.
    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error>;
}

/// A list of calls made to a `MockVault` instance.
#[cfg(test)]
type MockVaultCalls = Rc<RefCell<Vec<(String, Vec<String>, VaultDuration)>>>;

/// A fake interface to vault for testing purposes.
#[derive(Debug)]
#[cfg(test)]
struct MockVault {
    /// The tokens we were asked to generate.  We store these in a RefCell
    /// so that we can have "interior" mutability, because we don't want
    /// `generate_token` to be `&mut self` in the general case.
    calls: MockVaultCalls,
}

#[cfg(test)]
impl MockVault {
    /// Create a new MockVault.
    fn new() -> MockVault {
        MockVault { calls: Rc::new(RefCell::new(vec![])) }
    }

    /// Return a reference to record of calls made to our vault.
    fn calls(&self) -> MockVaultCalls {
        self.calls.clone()
    }
}

#[cfg(test)]
impl GenerateToken for MockVault {
    fn addr(&self) -> &str {
        "http://example.com:8200/"
    }

    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error> {
        self.calls.borrow_mut().push((display_name.to_owned(), policies, ttl));
        Ok("fake_token".to_owned())
    }
}

/// An interface to an actual vault server.
#[derive(Debug)]
struct Vault {
    /// The address of our vault server.
    addr: String,
    /// The master token that we'll use to issue new tokens.
    token: String,
}

impl Vault {
    /// Create a new vault client.
    fn new() -> Result<Vault, Error> {
        let addr = try!(env::var("VAULT_ADDR").map_err(|_| {
            err("Please set the environment variable VAULT_ADDR to the URL of \
                 your vault server")
        }));
        let token = try!(find_vault_token());
        Ok(Vault {
            addr: addr,
            token: token,
        })
    }
}

impl GenerateToken for Vault {
    fn addr(&self) -> &str {
        &self.addr
    }

    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error> {
        // We can't store `client` in `self`, because it has some obnoxious
        // lifetime parameters.  So we'll just recreate it.  This is
        // probably not the worst idea, because it uses `hyper` for HTTP,
        // and `hyper` HTTP connections used to have expiration issues that
        // were tricky for clients to deal with correctly.
        let client = try!(vault::Client::new(&self.addr, &self.token));
        let opts = vault::client::TokenOptions::default()
            .display_name(display_name)
            .renewable(false)
            .ttl(ttl)
            .policies(policies);
        let auth = try!(client.create_token(&opts));
        Ok(auth.client_token)
    }
}

/// Issues `VAULT_TOKEN` values to services.
#[derive(Debug)]
pub struct Plugin {
    /// Our `config/vault.yml` YAML file, parsed and read into memory.
    config: Config,
    /// Our source of tokens.
    generator: Box<GenerateToken>,
}

impl Plugin {
    /// Get the path to this plugin's config file.
    fn config_path(project: &Project) -> PathBuf {
        project.root_dir().join("config/vault.yml")
    }

    /// Create a new plugin, specifying an alternate source for tokens.
    fn new_with_generator<G>(project: &Project, generator: G) -> Result<Plugin, Error>
        where G: GenerateToken + 'static
    {
        let path = Self::config_path(project);
        let f = try!(fs::File::open(&path));
        let config = try!(serde_yaml::from_reader(f).map_err(|e| {
            err!("Error reading {}: {}", path.display(), e)
        }));
        Ok(Plugin {
            config: config,
            generator: Box::new(generator),
        })
    }
}

impl PluginTransform for Plugin {
    fn name(&self) -> &'static str {
        "vault"
    }

    fn transform(&self,
                 _op: Operation,
                 ctx: &plugins::Context,
                 file: &mut dc::File)
                 -> Result<(), Error> {

        for (name, mut service) in &mut file.services {
            // Set up a ConfigEnvironment that we can use to perform
            // interpolations of values like `$SERVICE` in our config file.
            let env = ConfigEnvironment {
                ctx: ctx,
                service: name,
            };

            // Define a local helper function to interpolate
            // `RawOr<String>` values using `env`.
            let interpolated = |raw_val: &dc::RawOr<String>| -> Result<String, Error> {
                let mut val = raw_val.to_owned();
                Ok(try!(val.interpolate_env(&env)).to_owned())
            };

            // Insert our VAULT_ADDR value into the generated files.
            service.environment
                .insert("VAULT_ADDR".to_owned(), self.generator.addr().to_owned());

            // Get a list of policy "patterns" that apply to this service.
            let mut raw_policies = self.config.default_policies.clone();
            raw_policies.extend(self.config
                .pods
                .get(ctx.pod.name())
                .and_then(|pod| pod.get(name))
                .map_or_else(|| vec![], |s| s.policies.clone()));

            // Interpolate the variables found in our policy patterns.
            let mut policies = vec![];
            for result in raw_policies.iter().map(|p| interpolated(p)) {
                // We'd like to use std::result::fold here but it's unstable.
                policies.push(try!(result));
            }

            // Generate a VAULT_TOKEN.
            let display_name = format!("{}-{}-{}-{}",
                                       ctx.project.name(),
                                       ctx.ovr.name(),
                                       ctx.pod.name(),
                                       name);
            let ttl = VaultDuration::seconds(self.config.default_ttl);
            let token = try!(self.generator
                .generate_token(&display_name, policies, ttl));
            service.environment.insert("VAULT_TOKEN".to_owned(), token);

            // Add in any extra environment variables.
            for (var, val) in &self.config.extra_environment {
                service.environment.insert(var.to_owned(), try!(interpolated(val)));
            }
        }
        Ok(())
    }
}

impl PluginNew for Plugin {
    /// Should we enable this plugin for this project?
    fn should_enable_for(project: &Project) -> Result<bool, Error> {
        let path = Self::config_path(project);
        Ok(path.exists())
    }

    /// Create a new plugin.
    fn new(project: &Project) -> Result<Self, Error> {
        Self::new_with_generator(project, try!(Vault::new()))
    }
}

#[test]
fn interpolates_policies() {
    use env_logger;
    let _ = env_logger::init();

    env::set_var("VAULT_ADDR", "http://example.com:8200/");
    env::set_var("VAULT_MASTER_TOKEN", "fake master token");

    let proj = Project::from_example("vault_integration").unwrap();
    let ovr = proj.ovr("production").unwrap();

    let vault = MockVault::new();
    let calls = vault.calls();
    let plugin = Plugin::new_with_generator(&proj, vault).unwrap();

    let frontend = proj.pod("frontend").unwrap();
    let ctx = plugins::Context::new(&proj, ovr, frontend);
    let mut file = frontend.merged_file(ovr).unwrap();
    plugin.transform(Operation::Output, &ctx, &mut file).unwrap();
    let web = file.services.get("web").unwrap();
    assert_eq!(web.environment.get("VAULT_ADDR").expect("has VAULT_ADDR"),
               "http://example.com:8200/");
    assert_eq!(web.environment.get("VAULT_TOKEN").expect("has VAULT_TOKEN"),
               "fake_token");
    assert_eq!(web.environment.get("VAULT_ENV").expect("has VAULT_ENV"),
               "production");

    let calls = calls.borrow();
    assert_eq!(calls.len(), 1);
    let (ref display_name, ref policies, ref ttl) = calls[0];
    assert_eq!(display_name, "vault_integration-production-frontend-web");
    assert_eq!(policies,
               &["vault_integration-production".to_owned(),
                 "vault_integration-production-frontend-web".to_owned(),
                 "vault_integration-production-ssl".to_owned()]);
    assert_eq!(ttl, &VaultDuration::seconds(2592000));
}
<commit_msg>vault: Try another convention for display_name<commit_after>//! Plugin which issues vault tokens to services.

use docker_compose::v2 as dc;
use serde_yaml;
#[cfg(test)]
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::env;
use std::fmt::Debug;
use std::fs;
use std::io::Read;
use std::path::PathBuf;
#[cfg(test)]
use std::rc::Rc;
use vault;
use vault::client::VaultDuration;

use plugins;
use plugins::transform::Operation;
use plugins::transform::{Plugin as PluginTransform, PluginNew};
use project::Project;
use util::{Error, err};

#[cfg(feature = "serde_macros")]
include!(concat!("vault_config.in.rs"));
#[cfg(feature = "serde_codegen")]
include!(concat!(env!("OUT_DIR"), "/plugins/transform/vault_config.rs"));

/// Load a vault token from `~/.vault-token`, where the command line client
/// puts it.
fn load_vault_token_from_file() -> Result<String, Error> {
    let path = try!(env::home_dir().ok_or_else(|| {
        err("You do not appear to have a home directory")
    })).join(".vault-token");
    let mut f = try!(fs::File::open(&path).map_err(|e| {
        err!("Error opening {}: {}", path.display(), e)
    }));
    let mut result = String::new();
    try!(f.read_to_string(&mut result).map_err(|e| {
        err!("Error reading {}: {}", path.display(), e)
    }));
    Ok(result.trim().to_owned())
}

/// Find the vault token we'll use to generate new tokens.
fn find_vault_token() -> Result<String, Error> {
    env::var("VAULT_MASTER_TOKEN")
        .or_else(|_| env::var("VAULT_TOKEN"))
        .or_else(|_| load_vault_token_from_file())
        .map_err(|e| err!("{}.  You probably want to log in using the vault \
                           client or set VAULT_MASTER_TOKEN", e))
}

/// The "environment" in which to interpret a configuration file.  We don't
/// want to use the OS environment variables, but rather a fake environment
/// with a few carefully selected values.
#[derive(Debug)]
struct ConfigEnvironment<'a> {
    /// The context for our transformation, including the project, pod,
    /// etc.
    ctx: &'a plugins::Context<'a>,
    /// The name of the current service.
    service: &'a str,
}

impl<'a> dc::Environment for ConfigEnvironment<'a> {
    fn var(&self, key: &str) -> Result<String, env::VarError> {
        let result = match key {
            "PROJECT" => Ok(self.ctx.project.name()),
            "OVERRIDE" => Ok(self.ctx.ovr.name()),
            "POD" => Ok(self.ctx.pod.name()),
            "SERVICE" => Ok(self.service),
            _ => Err(env::VarError::NotPresent),
        };
        result.map(|s| s.to_owned())
    }
}

/// An abstract interface to Vault's token-generation capabilities.  We use
/// this to mock vault during tests.
trait GenerateToken: Debug {
    /// Get a `VAULT_ADDR` value to use along with this token.
    fn addr(&self) -> &str;
    /// Generate a token with the specified parameters.
    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error>;
}

/// A list of calls made to a `MockVault` instance.
#[cfg(test)]
type MockVaultCalls = Rc<RefCell<Vec<(String, Vec<String>, VaultDuration)>>>;

/// A fake interface to vault for testing purposes.
#[derive(Debug)]
#[cfg(test)]
struct MockVault {
    /// The tokens we were asked to generate.  We store these in a RefCell
    /// so that we can have "interior" mutability, because we don't want
    /// `generate_token` to be `&mut self` in the general case.
    calls: MockVaultCalls,
}

#[cfg(test)]
impl MockVault {
    /// Create a new MockVault.
    fn new() -> MockVault {
        MockVault { calls: Rc::new(RefCell::new(vec![])) }
    }

    /// Return a reference to record of calls made to our vault.
    fn calls(&self) -> MockVaultCalls {
        self.calls.clone()
    }
}

#[cfg(test)]
impl GenerateToken for MockVault {
    fn addr(&self) -> &str {
        "http://example.com:8200/"
    }

    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error> {
        self.calls.borrow_mut().push((display_name.to_owned(), policies, ttl));
        Ok("fake_token".to_owned())
    }
}

/// An interface to an actual vault server.
#[derive(Debug)]
struct Vault {
    /// The address of our vault server.
    addr: String,
    /// The master token that we'll use to issue new tokens.
    token: String,
}

impl Vault {
    /// Create a new vault client.
    fn new() -> Result<Vault, Error> {
        let addr = try!(env::var("VAULT_ADDR").map_err(|_| {
            err("Please set the environment variable VAULT_ADDR to the URL of \
                 your vault server")
        }));
        let token = try!(find_vault_token());
        Ok(Vault {
            addr: addr,
            token: token,
        })
    }
}

impl GenerateToken for Vault {
    fn addr(&self) -> &str {
        &self.addr
    }

    fn generate_token(&self,
                      display_name: &str,
                      policies: Vec<String>,
                      ttl: VaultDuration)
                      -> Result<String, Error> {
        // We can't store `client` in `self`, because it has some obnoxious
        // lifetime parameters.  So we'll just recreate it.  This is
        // probably not the worst idea, because it uses `hyper` for HTTP,
        // and `hyper` HTTP connections used to have expiration issues that
        // were tricky for clients to deal with correctly.
        let client = try!(vault::Client::new(&self.addr, &self.token));
        let opts = vault::client::TokenOptions::default()
            .display_name(display_name)
            .renewable(false)
            .ttl(ttl)
            .policies(policies);
        let auth = try!(client.create_token(&opts));
        Ok(auth.client_token)
    }
}

/// Issues `VAULT_TOKEN` values to services.
#[derive(Debug)]
pub struct Plugin {
    /// Our `config/vault.yml` YAML file, parsed and read into memory.
    config: Config,
    /// Our source of tokens.
    generator: Box<GenerateToken>,
}

impl Plugin {
    /// Get the path to this plugin's config file.
    fn config_path(project: &Project) -> PathBuf {
        project.root_dir().join("config/vault.yml")
    }

    /// Create a new plugin, specifying an alternate source for tokens.
    fn new_with_generator<G>(project: &Project, generator: G) -> Result<Plugin, Error>
        where G: GenerateToken + 'static
    {
        let path = Self::config_path(project);
        let f = try!(fs::File::open(&path));
        let config = try!(serde_yaml::from_reader(f).map_err(|e| {
            err!("Error reading {}: {}", path.display(), e)
        }));
        Ok(Plugin {
            config: config,
            generator: Box::new(generator),
        })
    }
}

impl PluginTransform for Plugin {
    fn name(&self) -> &'static str {
        "vault"
    }

    fn transform(&self,
                 _op: Operation,
                 ctx: &plugins::Context,
                 file: &mut dc::File)
                 -> Result<(), Error> {

        for (name, mut service) in &mut file.services {
            // Set up a ConfigEnvironment that we can use to perform
            // interpolations of values like `$SERVICE` in our config file.
            let env = ConfigEnvironment {
                ctx: ctx,
                service: name,
            };

            // Define a local helper function to interpolate
            // `RawOr<String>` values using `env`.
            let interpolated = |raw_val: &dc::RawOr<String>| -> Result<String, Error> {
                let mut val = raw_val.to_owned();
                Ok(try!(val.interpolate_env(&env)).to_owned())
            };

            // Insert our VAULT_ADDR value into the generated files.
            service.environment
                .insert("VAULT_ADDR".to_owned(), self.generator.addr().to_owned());

            // Get a list of policy "patterns" that apply to this service.
            let mut raw_policies = self.config.default_policies.clone();
            raw_policies.extend(self.config
                .pods
                .get(ctx.pod.name())
                .and_then(|pod| pod.get(name))
                .map_or_else(|| vec![], |s| s.policies.clone()));

            // Interpolate the variables found in our policy patterns.
            let mut policies = vec![];
            for result in raw_policies.iter().map(|p| interpolated(p)) {
                // We'd like to use std::result::fold here but it's unstable.
                policies.push(try!(result));
            }

            // Generate a VAULT_TOKEN.
            let display_name = format!("{}_{}_{}_{}",
                                       ctx.project.name(),
                                       ctx.ovr.name(),
                                       ctx.pod.name(),
                                       name);
            let ttl = VaultDuration::seconds(self.config.default_ttl);
            let token = try!(self.generator
                .generate_token(&display_name, policies, ttl));
            service.environment.insert("VAULT_TOKEN".to_owned(), token);

            // Add in any extra environment variables.
            for (var, val) in &self.config.extra_environment {
                service.environment.insert(var.to_owned(), try!(interpolated(val)));
            }
        }
        Ok(())
    }
}

impl PluginNew for Plugin {
    /// Should we enable this plugin for this project?
    fn should_enable_for(project: &Project) -> Result<bool, Error> {
        let path = Self::config_path(project);
        Ok(path.exists())
    }

    /// Create a new plugin.
    fn new(project: &Project) -> Result<Self, Error> {
        Self::new_with_generator(project, try!(Vault::new()))
    }
}

#[test]
fn interpolates_policies() {
    use env_logger;
    let _ = env_logger::init();

    env::set_var("VAULT_ADDR", "http://example.com:8200/");
    env::set_var("VAULT_MASTER_TOKEN", "fake master token");

    let proj = Project::from_example("vault_integration").unwrap();
    let ovr = proj.ovr("production").unwrap();

    let vault = MockVault::new();
    let calls = vault.calls();
    let plugin = Plugin::new_with_generator(&proj, vault).unwrap();

    let frontend = proj.pod("frontend").unwrap();
    let ctx = plugins::Context::new(&proj, ovr, frontend);
    let mut file = frontend.merged_file(ovr).unwrap();
    plugin.transform(Operation::Output, &ctx, &mut file).unwrap();
    let web = file.services.get("web").unwrap();
    assert_eq!(web.environment.get("VAULT_ADDR").expect("has VAULT_ADDR"),
               "http://example.com:8200/");
    assert_eq!(web.environment.get("VAULT_TOKEN").expect("has VAULT_TOKEN"),
               "fake_token");
    assert_eq!(web.environment.get("VAULT_ENV").expect("has VAULT_ENV"),
               "production");

    let calls = calls.borrow();
    assert_eq!(calls.len(), 1);
    let (ref display_name, ref policies, ref ttl) = calls[0];
    assert_eq!(display_name, "vault_integration_production_frontend_web");
    assert_eq!(policies,
               &["vault_integration-production".to_owned(),
                 "vault_integration-production-frontend-web".to_owned(),
                 "vault_integration-production-ssl".to_owned()]);
    assert_eq!(ttl, &VaultDuration::seconds(2592000));
}
<|endoftext|>


<commit_before>use neb::dovahkiin::expr::symbols::Symbol;
use neb::dovahkiin::expr::SExpr;

// (insert-cell "<schema>" (hashmap "<key-1>" <value-1> "<key-2>" (hashmap "<key-3>" <value-2>)))
#[derive(Debug)]
pub struct Insert {}
impl Symbol for Insert {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Select {}
impl Symbol for Select {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Update {}
impl Symbol for Update {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

#[derive(Debug)]
pub struct Delete {}
impl Symbol for Delete {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}<commit_msg>modeling mql cell operations<commit_after>use neb::dovahkiin::expr::symbols::Symbol;
use neb::dovahkiin::expr::SExpr;

// (insert-cell "<schema>" (hashmap "<key-1>" <value-1> "<key-2>" (hashmap "<key-3>" <value-2>)))
#[derive(Debug)]
pub struct Insert {}
impl Symbol for Insert {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

// (select-cell "<schema>" <cell-id>)
// (select-cell "<schema>" (hashmap "<key>" <value>)) // until index is done
#[derive(Debug)]
pub struct Select {}
impl Symbol for Select {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

// (update-cell "<schema>" <cell-id> (hashmap ...))
// (update-cell "<schema>" (hashmap ...) (hashmap ...)) // until index is done
#[derive(Debug)]
pub struct Update {}
impl Symbol for Update {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}

// (delete-cell "<schema>" <cell-id>)
// (delete-cell "<schema>" (hashmap ...)) // until index is done
#[derive(Debug)]
pub struct Delete {}
impl Symbol for Delete {
    fn eval(&self, exprs: Vec<SExpr>) -> Result<SExpr, String> {
        unimplemented!();
    }
    fn is_macro(&self) -> bool { true }
}<|endoftext|>


<commit_before>use rusqlite::Connection;
use std::result::Result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String,
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY (fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        println!("table_create_variable_pair Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let me = VariablePair {
        id: 0,
        variable_value: name.to_string(),
        fk_variable: fk_variable.clone(),
    };
    let variable_pair_instance = conn.execute(
        "INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                 VALUES (?1, ?2)",
        &[&me.fk_variable, &me.variable_value],
    );
    if variable_pair_instance.is_err() {
        println!("Failed to insert:{:?}", me);
        return Err("INSERT INTO VARIABLE_PAIR failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection) -> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare(
        "SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value
        FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2",
    ).unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable, &bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Select failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<commit_msg>Bugfix of version numbers<commit_after>use rusqlite::Connection;
use std::result::Result;

#[derive(Debug)]
pub struct VariablePair {
    id: i32,
    fk_variable: i32,
    variable_value: String,
}

pub fn table_create_variable_pair(conn: &Connection) {
    let load_table = conn.execute(
        "CREATE TABLE  VARIABLE_PAIR (
                  id            INTEGER PRIMARY KEY ASC,
                  fk_variable   INTEGER NOT NULL,
                  variable_value  TEXT,
                  FOREIGN KEY (fk_variable) REFERENCES VARIABLE_NAME(id) ON UPDATE CASCADE
                  )",
        &[],
    );
    if load_table.is_err() {
        println!("table_create_variable_pair Failed {:?}", load_table);
        return;
    }
    load_table.unwrap();
}

pub fn insert_variable_pair(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let me = VariablePair {
        id: 0,
        variable_value: name.to_string(),
        fk_variable: *fk_variable,
    };
    println!("me.fk_variable:{:?}", me.fk_variable);
    let variable_pair_instance = conn.execute(
        "INSERT INTO VARIABLE_PAIR (fk_variable, variable_value)
                 VALUES (?1, ?2)",
        &[&me.fk_variable, &me.variable_value],
    );
    if variable_pair_instance.is_err() {
        println!("Failed to insert:{:?}", me);
        return Err("INSERT INTO VARIABLE_PAIR failed");
    }
    variable_pair_instance.unwrap();
    return Ok(0);
}

pub fn list_variable_pair(conn: &Connection) -> Vec<VariablePair> {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value  FROM VARIABLE_PAIR")
        .unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    let mut items = Vec::<VariablePair>::new();
    if wraped_fs_file_iter.is_err() {
        return items;

    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {

        items.push(person.unwrap());
    }
    return items;
}

pub fn variable_pair_list(conn: &Connection) {
    let mut stmt = conn.prepare("SELECT id, fk_variable, variable_value FROM VARIABLE_PAIR")
        .unwrap();
    let person_iter = stmt.query_map(&[], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    }).unwrap();

    for person in person_iter {
        println!("Found variable_pair {:?}", person.unwrap());
    }
}

pub fn pk_variable_pair_by_name(
    conn: &Connection,
    fk_variable: &i32,
    name: &str,
) -> Result<i32, &'static str> {
    let mut output = 0;
    let bill = String::from(name);
    let mut stmt = conn.prepare(
        "SELECT VARIABLE_PAIR.id, VARIABLE_PAIR.fk_variable, VARIABLE_PAIR.variable_value
        FROM VARIABLE_PAIR
		WHERE VARIABLE_PAIR.fk_variable = ?1 AND VARIABLE_PAIR.variable_value = ?2",
    ).unwrap();
    let variable_pair_iter = stmt.query_map(&[fk_variable, &bill], |row| {
        VariablePair {
            id: row.get(0),
            fk_variable: row.get(1),
            variable_value: row.get(2),
        }
    });
    if variable_pair_iter.is_err() {
        return Err("Select failed dfdf");
    }
    let result = variable_pair_iter.unwrap();
    let mut found = 0;
    for person in result {
        let bill = person.unwrap();
        output = bill.id;
        found = 1;
    }
    if found != 0 {
        return Ok(output);
    }
    return Err("None found");
}
<|endoftext|>


<commit_before>pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::HashMap,
    fmt::Debug,
    rc::Rc,
};

pub use dces::prelude::*;

pub use crate::{
    api::*,
    css_engine::{Selector, SelectorRelation, Theme as ThemeValue, ThemeBuilder},
    proc_macros::*,
    render,
    shell::Key,
    theme::{
	colors,
	default_theme,
	fonts,
	light_theme,
	vector_graphics::{
	    material_icons_font_ttf,
	    material_icons_font,
	    material_icons_round_font,
	    material_icons_sharp_font,
	    material_icons_twotone_font,
	}
    },
    tree::*,
    utils::*,
    widgets::*,
};
<commit_msg>prelude: update woff2 'material_icons_baseline_fonts'<commit_after>pub use std::{
    any::{Any, TypeId},
    cell::RefCell,
    collections::HashMap,
    fmt::Debug,
    rc::Rc,
};

pub use dces::prelude::*;

pub use crate::{
    api::*,
    css_engine::{Selector, SelectorRelation, Theme as ThemeValue, ThemeBuilder},
    proc_macros::*,
    render,
    shell::Key,
    theme::{
        colors,
        default_theme,
        fonts,
        light_theme,
        vector_graphics::{
            material_icons_font_ttf,
            material_icons_baseline_font,
            material_icons_round_font,
            material_icons_sharp_font,
            material_icons_twotone_font,
        }
    },
    tree::*,
    utils::*,
    widgets::*,
};
<|endoftext|>


<commit_before>use gl;
use std::{fmt, mem, ptr};
use std::collections::HashMap;
use std::sync::Arc;
use {Display, DisplayImpl, GlObject};
use context::CommandContext;

struct Shader {
    display: Arc<DisplayImpl>,
    id: gl::types::GLuint,
}

impl Drop for Shader {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(proc(ctxt) {
            unsafe {
                ctxt.gl.DeleteShader(id);
            }
        });
    }
}

/// A combinaison of shaders linked together.
pub struct Program {
    display: Arc<DisplayImpl>,
    #[allow(dead_code)]
    shaders: Vec<Shader>,
    id: gl::types::GLuint,
    uniforms: Arc<HashMap<String, Uniform>>,
    attributes: Arc<HashMap<String, Attribute>>,
}

/// Informations about a uniform (except its name).
///
/// Internal struct. Not public.
struct Uniform {
    pub location: gl::types::GLint,
    pub ty: gl::types::GLenum,
    pub size: gl::types::GLint,
}

/// Informations about an attribute of a program (except its name).
///
/// Internal struct. Not public.
#[deriving(Show)]
struct Attribute {
    pub location: gl::types::GLint,
    pub ty: gl::types::GLenum,
    pub size: gl::types::GLint,
}

/// Error that can be triggered when creating a `Program`.
#[deriving(Clone, Show)]
pub enum ProgramCreationError {
    /// Error while compiling one of the shaders.
    CompilationError(String),

    /// Error while linking the program.
    LinkingError(String),

    /// `glCreateProgram` failed.
    ProgramCreationFailure,

    /// One of the request shader type is not supported by the backend.
    ///
    /// Usually the case of geometry shaders.
    ShaderTypeNotSupported,
}

impl Program {
    /// Builds a new program.
    ///
    /// A program is a group of shaders linked together.
    ///
    /// # Parameters
    ///
    /// - `vertex_shader`: Source code of the vertex shader.
    /// - `fragment_shader`: Source code of the fragment shader.
    /// - `geometry_shader`: Source code of the geometry shader.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # let display: glium::Display = unsafe { std::mem::uninitialized() };
    /// # let vertex_source = ""; let fragment_source = ""; let geometry_source = "";
    /// let program = glium::Program::new(&display, vertex_source, fragment_source,
    ///     Some(geometry_source));
    /// ```
    ///
    #[experimental = "The list of shaders and the result error will probably change"]
    pub fn new(display: &Display, vertex_shader: &str, fragment_shader: &str,
               geometry_shader: Option<&str>) -> Result<Program, ProgramCreationError>
    {
        let mut shaders_store = Vec::new();
        shaders_store.push(try!(build_shader(display, gl::VERTEX_SHADER, vertex_shader)));
        match geometry_shader {
            Some(gs) => shaders_store.push(try!(build_shader(display, gl::GEOMETRY_SHADER, gs))),
            None => ()
        }
        shaders_store.push(try!(build_shader(display, gl::FRAGMENT_SHADER, fragment_shader)));

        let mut shaders_ids = Vec::new();
        for sh in shaders_store.iter() {
            shaders_ids.push(sh.id);
        }

        let (tx, rx) = channel();
        display.context.context.exec(proc(ctxt) {
            unsafe {
                let id = ctxt.gl.CreateProgram();
                if id == 0 {
                    tx.send(Err(ProgramCreationError::ProgramCreationFailure));
                    return;
                }

                // attaching shaders
                for sh in shaders_ids.iter() {
                    ctxt.gl.AttachShader(id, sh.clone());
                }

                // linking and checking for errors
                ctxt.gl.LinkProgram(id);
                {   let mut link_success: gl::types::GLint = mem::uninitialized();
                    ctxt.gl.GetProgramiv(id, gl::LINK_STATUS, &mut link_success);
                    if link_success == 0 {
                        use ProgramCreationError::LinkingError;

                        match ctxt.gl.GetError() {
                            gl::NO_ERROR => (),
                            gl::INVALID_VALUE => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered \
                                                                  GL_INVALID_VALUE"))));
                                return;
                            },
                            gl::INVALID_OPERATION => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered \
                                                                  GL_INVALID_OPERATION"))));
                                return;
                            },
                            _ => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered an \
                                                                  unknown error"))));
                                return;
                            }
                        };

                        let mut error_log_size: gl::types::GLint = mem::uninitialized();
                        ctxt.gl.GetProgramiv(id, gl::INFO_LOG_LENGTH, &mut error_log_size);

                        let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as uint);
                        ctxt.gl.GetProgramInfoLog(id, error_log_size, &mut error_log_size,
                            error_log.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
                        error_log.set_len(error_log_size as uint);

                        let msg = String::from_utf8(error_log).unwrap();
                        tx.send(Err(LinkingError(msg)));
                        return;
                    }
                }

                tx.send(Ok(id));
            }
        });

        let id = try!(rx.recv());

        let (tx, rx) = channel();
        display.context.context.exec(proc(mut ctxt) {
            unsafe {
                tx.send((
                    reflect_uniforms(&mut ctxt, id),
                    reflect_attributes(&mut ctxt, id)
                ))
            }
        });

        let (uniforms, attributes) = rx.recv();

        Ok(Program {
            display: display.context.clone(),
            shaders: shaders_store,
            id: id,
            uniforms: Arc::new(uniforms),
            attributes: Arc::new(attributes),
        })
    }
}

impl fmt::Show for Program {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Program #{}", self.id)).fmt(formatter)
    }
}

impl GlObject for Program {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

// TODO: remove this hack
pub fn get_uniforms_locations(program: &Program) -> Arc<HashMap<String, Uniform>>
{
    program.uniforms.clone()
}

// TODO: remove this hack
pub fn get_attributes(program: &Program) -> Arc<HashMap<String, Attribute>>
{
    program.attributes.clone()
}

impl Drop for Program {
    fn drop(&mut self) {
        // removing VAOs which contain this program
        {
            let mut vaos = self.display.vertex_array_objects.lock();
            let to_delete = vaos.keys().filter(|&&(_, _, p)| p == self.id)
                .map(|k| k.clone()).collect::<Vec<_>>();
            for k in to_delete.into_iter() {
                vaos.remove(&k);
            }
        }

        // sending the destroy command
        let id = self.id.clone();
        self.display.context.exec(proc(ctxt) {
            unsafe {
                if ctxt.state.program == id {
                    ctxt.gl.UseProgram(0);
                    ctxt.state.program = 0;
                }

                ctxt.gl.DeleteProgram(id);
            }
        });
    }
}

/// Builds an individual shader.
fn build_shader<S: ToCStr>(display: &Display, shader_type: gl::types::GLenum, source_code: S)
    -> Result<Shader, ProgramCreationError>
{
    let source_code = source_code.to_c_str();

    let (tx, rx) = channel();
    display.context.context.exec(proc(ctxt) {
        unsafe {
            if shader_type == gl::GEOMETRY_SHADER && ctxt.opengl_es {
                tx.send(Err(ProgramCreationError::ShaderTypeNotSupported));
                return;
            }

            let id = ctxt.gl.CreateShader(shader_type);

            if id == 0 {
                tx.send(Err(ProgramCreationError::ShaderTypeNotSupported));
                return;
            }

            ctxt.gl.ShaderSource(id, 1, [ source_code.as_ptr() ].as_ptr(), ptr::null());
            ctxt.gl.CompileShader(id);

            // checking compilation success
            let compilation_success = {
                let mut compilation_success: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetShaderiv(id, gl::COMPILE_STATUS, &mut compilation_success);
                compilation_success
            };

            if compilation_success == 0 {
                // compilation error
                let mut error_log_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetShaderiv(id, gl::INFO_LOG_LENGTH, &mut error_log_size);

                let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as uint);
                ctxt.gl.GetShaderInfoLog(id, error_log_size, &mut error_log_size,
                    error_log.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
                error_log.set_len(error_log_size as uint);

                let msg = String::from_utf8(error_log).unwrap();
                tx.send(Err(ProgramCreationError::CompilationError(msg)));
                return;
            }

            tx.send(Ok(id));
        }
    });

    rx.recv().map(|id| {
        Shader {
            display: display.context.clone(),
            id: id
        }
    })
}

unsafe fn reflect_uniforms(ctxt: &mut CommandContext, program: gl::types::GLuint)
    -> HashMap<String, Uniform>
{
    // reflecting program uniforms
    let mut uniforms = HashMap::new();

    let mut active_uniforms: gl::types::GLint = mem::uninitialized();
    ctxt.gl.GetProgramiv(program, gl::ACTIVE_UNIFORMS, &mut active_uniforms);

    for uniform_id in range(0, active_uniforms) {
        let mut uniform_name_tmp: Vec<u8> = Vec::with_capacity(64);
        let mut uniform_name_tmp_len = 63;

        let mut data_type: gl::types::GLenum = mem::uninitialized();
        let mut data_size: gl::types::GLint = mem::uninitialized();
        ctxt.gl.GetActiveUniform(program, uniform_id as gl::types::GLuint, uniform_name_tmp_len,
            &mut uniform_name_tmp_len, &mut data_size, &mut data_type,
            uniform_name_tmp.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
        uniform_name_tmp.set_len(uniform_name_tmp_len as uint);

        let uniform_name = String::from_utf8(uniform_name_tmp).unwrap();
        let location = ctxt.gl.GetUniformLocation(program, uniform_name.to_c_str().into_inner());

        uniforms.insert(uniform_name, Uniform {
            location: location,
            ty: data_type,
            size: data_size
        });
    }

    uniforms
}

unsafe fn reflect_attributes(ctxt: &mut CommandContext, program: gl::types::GLuint)
    -> HashMap<String, Attribute>
{
    let mut attributes = HashMap::new();

    let mut active_attributes: gl::types::GLint = mem::uninitialized();
    ctxt.gl.GetProgramiv(program, gl::ACTIVE_ATTRIBUTES, &mut active_attributes);

    for attribute_id in range(0, active_attributes) {
        let mut attr_name_tmp: Vec<u8> = Vec::with_capacity(64);
        let mut attr_name_tmp_len = 63;

        let mut data_type: gl::types::GLenum = mem::uninitialized();
        let mut data_size: gl::types::GLint = mem::uninitialized();
        ctxt.gl.GetActiveAttrib(program, attribute_id as gl::types::GLuint, attr_name_tmp_len,
            &mut attr_name_tmp_len, &mut data_size, &mut data_type,
            attr_name_tmp.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
        attr_name_tmp.set_len(attr_name_tmp_len as uint);

        let attr_name = String::from_utf8(attr_name_tmp).unwrap();
        let location = ctxt.gl.GetAttribLocation(program, attr_name.to_c_str().into_inner());

        attributes.insert(attr_name, Attribute {
            location: location,
            ty: data_type,
            size: data_size
        });
    }

    attributes
}
<commit_msg>Implement Error for ProgramCreationError<commit_after>use gl;
use std::{fmt, mem, ptr};
use std::collections::HashMap;
use std::sync::Arc;
use {Display, DisplayImpl, GlObject};
use context::CommandContext;

struct Shader {
    display: Arc<DisplayImpl>,
    id: gl::types::GLuint,
}

impl Drop for Shader {
    fn drop(&mut self) {
        let id = self.id.clone();
        self.display.context.exec(proc(ctxt) {
            unsafe {
                ctxt.gl.DeleteShader(id);
            }
        });
    }
}

/// A combinaison of shaders linked together.
pub struct Program {
    display: Arc<DisplayImpl>,
    #[allow(dead_code)]
    shaders: Vec<Shader>,
    id: gl::types::GLuint,
    uniforms: Arc<HashMap<String, Uniform>>,
    attributes: Arc<HashMap<String, Attribute>>,
}

/// Informations about a uniform (except its name).
///
/// Internal struct. Not public.
struct Uniform {
    pub location: gl::types::GLint,
    pub ty: gl::types::GLenum,
    pub size: gl::types::GLint,
}

/// Informations about an attribute of a program (except its name).
///
/// Internal struct. Not public.
#[deriving(Show)]
struct Attribute {
    pub location: gl::types::GLint,
    pub ty: gl::types::GLenum,
    pub size: gl::types::GLint,
}

/// Error that can be triggered when creating a `Program`.
#[deriving(Clone, Show)]
pub enum ProgramCreationError {
    /// Error while compiling one of the shaders.
    CompilationError(String),

    /// Error while linking the program.
    LinkingError(String),

    /// `glCreateProgram` failed.
    ProgramCreationFailure,

    /// One of the request shader type is not supported by the backend.
    ///
    /// Usually the case of geometry shaders.
    ShaderTypeNotSupported,
}

impl ::std::error::Error for ProgramCreationError {
    fn description(&self) -> &str {
        match self {
            &ProgramCreationError::CompilationError(_) => "Compilation error in one of the \
                                                           shaders",
            &ProgramCreationError::LinkingError(_) => "Error while linking shaders together",
            &ProgramCreationError::ProgramCreationFailure => "glCreateProgram failed",
            &ProgramCreationError::ShaderTypeNotSupported => "One of the request shader type is \
                                                              not supported by the backend",
        }
    }

    fn detail(&self) -> Option<String> {
        match self {
            &ProgramCreationError::CompilationError(ref s) => Some(s.clone()),
            &ProgramCreationError::LinkingError(ref s) => Some(s.clone()),
            &ProgramCreationError::ProgramCreationFailure => None,
            &ProgramCreationError::ShaderTypeNotSupported => None,
        }
    }

    fn cause(&self) -> Option<&::std::error::Error> {
        None
    }
}

impl Program {
    /// Builds a new program.
    ///
    /// A program is a group of shaders linked together.
    ///
    /// # Parameters
    ///
    /// - `vertex_shader`: Source code of the vertex shader.
    /// - `fragment_shader`: Source code of the fragment shader.
    /// - `geometry_shader`: Source code of the geometry shader.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # let display: glium::Display = unsafe { std::mem::uninitialized() };
    /// # let vertex_source = ""; let fragment_source = ""; let geometry_source = "";
    /// let program = glium::Program::new(&display, vertex_source, fragment_source,
    ///     Some(geometry_source));
    /// ```
    ///
    #[experimental = "The list of shaders and the result error will probably change"]
    pub fn new(display: &Display, vertex_shader: &str, fragment_shader: &str,
               geometry_shader: Option<&str>) -> Result<Program, ProgramCreationError>
    {
        let mut shaders_store = Vec::new();
        shaders_store.push(try!(build_shader(display, gl::VERTEX_SHADER, vertex_shader)));
        match geometry_shader {
            Some(gs) => shaders_store.push(try!(build_shader(display, gl::GEOMETRY_SHADER, gs))),
            None => ()
        }
        shaders_store.push(try!(build_shader(display, gl::FRAGMENT_SHADER, fragment_shader)));

        let mut shaders_ids = Vec::new();
        for sh in shaders_store.iter() {
            shaders_ids.push(sh.id);
        }

        let (tx, rx) = channel();
        display.context.context.exec(proc(ctxt) {
            unsafe {
                let id = ctxt.gl.CreateProgram();
                if id == 0 {
                    tx.send(Err(ProgramCreationError::ProgramCreationFailure));
                    return;
                }

                // attaching shaders
                for sh in shaders_ids.iter() {
                    ctxt.gl.AttachShader(id, sh.clone());
                }

                // linking and checking for errors
                ctxt.gl.LinkProgram(id);
                {   let mut link_success: gl::types::GLint = mem::uninitialized();
                    ctxt.gl.GetProgramiv(id, gl::LINK_STATUS, &mut link_success);
                    if link_success == 0 {
                        use ProgramCreationError::LinkingError;

                        match ctxt.gl.GetError() {
                            gl::NO_ERROR => (),
                            gl::INVALID_VALUE => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered \
                                                                  GL_INVALID_VALUE"))));
                                return;
                            },
                            gl::INVALID_OPERATION => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered \
                                                                  GL_INVALID_OPERATION"))));
                                return;
                            },
                            _ => {
                                tx.send(Err(LinkingError(format!("glLinkProgram triggered an \
                                                                  unknown error"))));
                                return;
                            }
                        };

                        let mut error_log_size: gl::types::GLint = mem::uninitialized();
                        ctxt.gl.GetProgramiv(id, gl::INFO_LOG_LENGTH, &mut error_log_size);

                        let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as uint);
                        ctxt.gl.GetProgramInfoLog(id, error_log_size, &mut error_log_size,
                            error_log.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
                        error_log.set_len(error_log_size as uint);

                        let msg = String::from_utf8(error_log).unwrap();
                        tx.send(Err(LinkingError(msg)));
                        return;
                    }
                }

                tx.send(Ok(id));
            }
        });

        let id = try!(rx.recv());

        let (tx, rx) = channel();
        display.context.context.exec(proc(mut ctxt) {
            unsafe {
                tx.send((
                    reflect_uniforms(&mut ctxt, id),
                    reflect_attributes(&mut ctxt, id)
                ))
            }
        });

        let (uniforms, attributes) = rx.recv();

        Ok(Program {
            display: display.context.clone(),
            shaders: shaders_store,
            id: id,
            uniforms: Arc::new(uniforms),
            attributes: Arc::new(attributes),
        })
    }
}

impl fmt::Show for Program {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        (format!("Program #{}", self.id)).fmt(formatter)
    }
}

impl GlObject for Program {
    fn get_id(&self) -> gl::types::GLuint {
        self.id
    }
}

// TODO: remove this hack
pub fn get_uniforms_locations(program: &Program) -> Arc<HashMap<String, Uniform>>
{
    program.uniforms.clone()
}

// TODO: remove this hack
pub fn get_attributes(program: &Program) -> Arc<HashMap<String, Attribute>>
{
    program.attributes.clone()
}

impl Drop for Program {
    fn drop(&mut self) {
        // removing VAOs which contain this program
        {
            let mut vaos = self.display.vertex_array_objects.lock();
            let to_delete = vaos.keys().filter(|&&(_, _, p)| p == self.id)
                .map(|k| k.clone()).collect::<Vec<_>>();
            for k in to_delete.into_iter() {
                vaos.remove(&k);
            }
        }

        // sending the destroy command
        let id = self.id.clone();
        self.display.context.exec(proc(ctxt) {
            unsafe {
                if ctxt.state.program == id {
                    ctxt.gl.UseProgram(0);
                    ctxt.state.program = 0;
                }

                ctxt.gl.DeleteProgram(id);
            }
        });
    }
}

/// Builds an individual shader.
fn build_shader<S: ToCStr>(display: &Display, shader_type: gl::types::GLenum, source_code: S)
    -> Result<Shader, ProgramCreationError>
{
    let source_code = source_code.to_c_str();

    let (tx, rx) = channel();
    display.context.context.exec(proc(ctxt) {
        unsafe {
            if shader_type == gl::GEOMETRY_SHADER && ctxt.opengl_es {
                tx.send(Err(ProgramCreationError::ShaderTypeNotSupported));
                return;
            }

            let id = ctxt.gl.CreateShader(shader_type);

            if id == 0 {
                tx.send(Err(ProgramCreationError::ShaderTypeNotSupported));
                return;
            }

            ctxt.gl.ShaderSource(id, 1, [ source_code.as_ptr() ].as_ptr(), ptr::null());
            ctxt.gl.CompileShader(id);

            // checking compilation success
            let compilation_success = {
                let mut compilation_success: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetShaderiv(id, gl::COMPILE_STATUS, &mut compilation_success);
                compilation_success
            };

            if compilation_success == 0 {
                // compilation error
                let mut error_log_size: gl::types::GLint = mem::uninitialized();
                ctxt.gl.GetShaderiv(id, gl::INFO_LOG_LENGTH, &mut error_log_size);

                let mut error_log: Vec<u8> = Vec::with_capacity(error_log_size as uint);
                ctxt.gl.GetShaderInfoLog(id, error_log_size, &mut error_log_size,
                    error_log.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
                error_log.set_len(error_log_size as uint);

                let msg = String::from_utf8(error_log).unwrap();
                tx.send(Err(ProgramCreationError::CompilationError(msg)));
                return;
            }

            tx.send(Ok(id));
        }
    });

    rx.recv().map(|id| {
        Shader {
            display: display.context.clone(),
            id: id
        }
    })
}

unsafe fn reflect_uniforms(ctxt: &mut CommandContext, program: gl::types::GLuint)
    -> HashMap<String, Uniform>
{
    // reflecting program uniforms
    let mut uniforms = HashMap::new();

    let mut active_uniforms: gl::types::GLint = mem::uninitialized();
    ctxt.gl.GetProgramiv(program, gl::ACTIVE_UNIFORMS, &mut active_uniforms);

    for uniform_id in range(0, active_uniforms) {
        let mut uniform_name_tmp: Vec<u8> = Vec::with_capacity(64);
        let mut uniform_name_tmp_len = 63;

        let mut data_type: gl::types::GLenum = mem::uninitialized();
        let mut data_size: gl::types::GLint = mem::uninitialized();
        ctxt.gl.GetActiveUniform(program, uniform_id as gl::types::GLuint, uniform_name_tmp_len,
            &mut uniform_name_tmp_len, &mut data_size, &mut data_type,
            uniform_name_tmp.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
        uniform_name_tmp.set_len(uniform_name_tmp_len as uint);

        let uniform_name = String::from_utf8(uniform_name_tmp).unwrap();
        let location = ctxt.gl.GetUniformLocation(program, uniform_name.to_c_str().into_inner());

        uniforms.insert(uniform_name, Uniform {
            location: location,
            ty: data_type,
            size: data_size
        });
    }

    uniforms
}

unsafe fn reflect_attributes(ctxt: &mut CommandContext, program: gl::types::GLuint)
    -> HashMap<String, Attribute>
{
    let mut attributes = HashMap::new();

    let mut active_attributes: gl::types::GLint = mem::uninitialized();
    ctxt.gl.GetProgramiv(program, gl::ACTIVE_ATTRIBUTES, &mut active_attributes);

    for attribute_id in range(0, active_attributes) {
        let mut attr_name_tmp: Vec<u8> = Vec::with_capacity(64);
        let mut attr_name_tmp_len = 63;

        let mut data_type: gl::types::GLenum = mem::uninitialized();
        let mut data_size: gl::types::GLint = mem::uninitialized();
        ctxt.gl.GetActiveAttrib(program, attribute_id as gl::types::GLuint, attr_name_tmp_len,
            &mut attr_name_tmp_len, &mut data_size, &mut data_type,
            attr_name_tmp.as_mut_slice().as_mut_ptr() as *mut gl::types::GLchar);
        attr_name_tmp.set_len(attr_name_tmp_len as uint);

        let attr_name = String::from_utf8(attr_name_tmp).unwrap();
        let location = ctxt.gl.GetAttribLocation(program, attr_name.to_c_str().into_inner());

        attributes.insert(attr_name, Attribute {
            location: location,
            ty: data_type,
            size: data_size
        });
    }

    attributes
}
<|endoftext|>


<commit_before>//! Endpoints for push notifications.

use std::convert::TryFrom;

use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};

pub mod delete_pushrule;
pub mod get_notifications;
pub mod get_pushers;
pub mod get_pushrule;
pub mod get_pushrule_actions;
pub mod get_pushrule_enabled;
pub mod get_pushrules_all;
pub mod get_pushrules_global_scope;
pub mod set_pusher;
pub mod set_pushrule;
pub mod set_pushrule_actions;
pub mod set_pushrule_enabled;

pub use ruma_common::push::Action;

/// The kinds of push rules that are available
#[derive(
    Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display, EnumString,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RuleKind {
    /// User-configured rules that override all other kinds
    Override,

    /// Lowest priority user-defined rules
    Underride,

    /// Sender-specific rules
    Sender,

    /// Room-specific rules
    Room,

    /// Content-specific rules
    Content,
}

impl TryFrom<&'_ str> for RuleKind {
    type Error = strum::ParseError;

    fn try_from(s: &str) -> Result<Self, Self::Error> {
        s.parse()
    }
}

/// A push rule
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PushRule {
    /// The actions to perform when this rule is matched.
    pub actions: Vec<Action>,

    /// Whether this is a default rule, or has been set explicitly.
    pub default: bool,

    /// Whether the push rule is enabled or not.
    pub enabled: bool,

    /// The ID of this rule.
    pub rule_id: String,

    /// The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches.
    /// Only applicable to underride and override rules.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conditions: Option<Vec<PushCondition>>,

    /// The glob-style pattern to match against. Only applicable to content rules.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pattern: Option<String>,
}

/// A condition for a push rule
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")] // Using internally tagged enum representation to match the spec
pub enum PushCondition {
    /// This is a glob pattern match on a field of the event.
    EventMatch {
        /// The dot-separated field of the event to match, e.g. `content.body`
        key: String,

        /// The glob-style pattern to match against.
        pattern: String,
    },

    /// This matches unencrypted messages where `content.body` contains
    /// the owner's display name in that room.
    ContainsDisplayName,

    /// This matches the current number of members in the room.
    RoomMemberCount {
        /// A decimal integer optionally prefixed by one of, ==, <, >, >= or <=.
        /// Default prefix is ==.
        is: String,
    },

    /// This takes into account the current power levels in the room, ensuring the
    /// sender of the event has high enough power to trigger the notification.
    SenderNotificationPermission {
        /// A string that determines the power level the sender must have to
        /// trigger notifications of a given type, such as `room`.
        key: String,
    },
}

/// Defines a pusher
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Pusher {
    /// This is a unique identifier for this pusher. Max length, 512 bytes.
    pub pushkey: String,

    /// The kind of the pusher. If set to None in a call to set_pusher, this
    /// will delete the pusher
    pub kind: Option<PusherKind>,

    /// This is a reverse-DNS style identifier for the application. Max length, 64 chars.
    pub app_id: String,

    /// A string that will allow the user to identify what application owns this pusher.
    pub app_display_name: String,

    /// A string that will allow the user to identify what device owns this pusher.
    pub device_display_name: String,

    /// This string determines which set of device specific rules this pusher executes.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_tag: Option<String>,

    /// The preferred language for receiving notifications (e.g. 'en' or 'en-US')
    pub lang: String,

    /// Information for the pusher implementation itself.
    pub data: PusherData,
}

/// Which kind a pusher is
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PusherKind {
    /// A pusher that sends HTTP pokes.
    Http,

    /// A pusher that emails the user with unread notifications.
    Email,
}

/// Information for the pusher implementation itself.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PusherData {
    /// Required if the pusher's kind is http. The URL to use to send notifications to.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,

    /// The format to use when sending notifications to the Push Gateway.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<PushFormat>,
}

/// A special format that the homeserver should use when sending notifications to a Push Gateway.
/// Currently, only "event_id_only" is supported as of [Push Gateway API r0.1.1](https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour)
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PushFormat {
    /// Require the homeserver to only send a reduced set of fields in the push.
    EventIdOnly,
}
<commit_msg>Use PushCondition from ruma_events instead of declaring a separate one<commit_after>//! Endpoints for push notifications.

use std::convert::TryFrom;

use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};

pub mod delete_pushrule;
pub mod get_notifications;
pub mod get_pushers;
pub mod get_pushrule;
pub mod get_pushrule_actions;
pub mod get_pushrule_enabled;
pub mod get_pushrules_all;
pub mod get_pushrules_global_scope;
pub mod set_pusher;
pub mod set_pushrule;
pub mod set_pushrule_actions;
pub mod set_pushrule_enabled;

pub use ruma_common::push::Action;
pub use ruma_events::push_rules::PushCondition;

/// The kinds of push rules that are available
#[derive(
    Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Display, EnumString,
)]
#[serde(rename_all = "snake_case")]
#[strum(serialize_all = "snake_case")]
pub enum RuleKind {
    /// User-configured rules that override all other kinds
    Override,

    /// Lowest priority user-defined rules
    Underride,

    /// Sender-specific rules
    Sender,

    /// Room-specific rules
    Room,

    /// Content-specific rules
    Content,
}

impl TryFrom<&'_ str> for RuleKind {
    type Error = strum::ParseError;

    fn try_from(s: &str) -> Result<Self, Self::Error> {
        s.parse()
    }
}

/// A push rule
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PushRule {
    /// The actions to perform when this rule is matched.
    pub actions: Vec<Action>,

    /// Whether this is a default rule, or has been set explicitly.
    pub default: bool,

    /// Whether the push rule is enabled or not.
    pub enabled: bool,

    /// The ID of this rule.
    pub rule_id: String,

    /// The conditions that must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches.
    /// Only applicable to underride and override rules.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub conditions: Option<Vec<PushCondition>>,

    /// The glob-style pattern to match against. Only applicable to content rules.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pattern: Option<String>,
}

/// Defines a pusher
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Pusher {
    /// This is a unique identifier for this pusher. Max length, 512 bytes.
    pub pushkey: String,

    /// The kind of the pusher. If set to None in a call to set_pusher, this
    /// will delete the pusher
    pub kind: Option<PusherKind>,

    /// This is a reverse-DNS style identifier for the application. Max length, 64 chars.
    pub app_id: String,

    /// A string that will allow the user to identify what application owns this pusher.
    pub app_display_name: String,

    /// A string that will allow the user to identify what device owns this pusher.
    pub device_display_name: String,

    /// This string determines which set of device specific rules this pusher executes.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub profile_tag: Option<String>,

    /// The preferred language for receiving notifications (e.g. 'en' or 'en-US')
    pub lang: String,

    /// Information for the pusher implementation itself.
    pub data: PusherData,
}

/// Which kind a pusher is
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PusherKind {
    /// A pusher that sends HTTP pokes.
    Http,

    /// A pusher that emails the user with unread notifications.
    Email,
}

/// Information for the pusher implementation itself.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PusherData {
    /// Required if the pusher's kind is http. The URL to use to send notifications to.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub url: Option<String>,

    /// The format to use when sending notifications to the Push Gateway.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub format: Option<PushFormat>,
}

/// A special format that the homeserver should use when sending notifications to a Push Gateway.
/// Currently, only "event_id_only" is supported as of [Push Gateway API r0.1.1](https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour)
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum PushFormat {
    /// Require the homeserver to only send a reduced set of fields in the push.
    EventIdOnly,
}
<|endoftext|>


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

// LLDB can't handle zero-sized values
// ignore-lldb

// compile-flags:-g
// gdb-command:run

// gdb-command:print first
// gdbg-check:$1 = {<No data fields>}
// gdbr-check:$1 = <error reading variable>

// gdb-command:print second
// gdbg-check:$2 = {<No data fields>}
// gdbr-check:$2 = <error reading variable>

#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]

enum ANilEnum {}
enum AnotherNilEnum {}

// This test relies on gdbg printing the string "{<No data fields>}" for empty
// structs (which may change some time)
// The error from gdbr is expected since nil enums are not supposed to exist.
fn main() {
    unsafe {
        let first: ANilEnum = ::std::mem::zeroed();
        let second: AnotherNilEnum = ::std::mem::zeroed();

        zzz(); // #break
    }
}

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

// NOTE Instantiating an empty enum is UB. This test may break in the future.

// LLDB can't handle zero-sized values
// ignore-lldb

// compile-flags:-g
// gdb-command:run

// gdb-command:print first
// gdbg-check:$1 = {<No data fields>}
// gdbr-check:$1 = <error reading variable>

// gdb-command:print second
// gdbg-check:$2 = {<No data fields>}
// gdbr-check:$2 = <error reading variable>

#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
#![feature(maybe_uninit)]
#![omit_gdb_pretty_printer_section]

use std::mem::MaybeUninit;

enum ANilEnum {}
enum AnotherNilEnum {}

// This test relies on gdbg printing the string "{<No data fields>}" for empty
// structs (which may change some time)
// The error from gdbr is expected since nil enums are not supposed to exist.
fn main() {
    unsafe {
        let first: ANilEnum = MaybeUninit::uninitialized().into_inner();
        let second: AnotherNilEnum = MaybeUninit::uninitialized().into_inner();

        zzz(); // #break
    }
}

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