<commit_before>use kvm::CpuId;
use std::result;

// constants for setting the fields of kvm_cpuid2 structures
// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.
const EBX_CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
const EBX_CPU_COUNT_SHIFT: u32 = 16; // The logical processor count .
const EBX_APICID_SHIFT: u32 = 24; // The (fixed) default APIC ID.
const ECX_EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
const ECX_TSC_DEADLINE_TIMER_SHIFT: u32 = 24;
const ECX_HYPERVISOR_SHIFT: u32 = 31; // Flag to be set when the cpu is running on a hypervisor.
const ECX_LEVEL_TYPE_SHIFT: u32 = 8; // Shift for setting level type for leaf 11
const EDX_HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.

// Deterministic Cache Parameters Leaf
const EAX_CACHE_LEVEL: u32 = 5;
const EAX_MAX_ADDR_IDS_SHARING_CACHE: u32 = 14;
const EAX_MAX_ADDR_IDS_IN_PACKAGE: u32 = 26;

const LEAFBH_LEVEL_TYPE_INVALID: u32 = 0;
const LEAFBH_LEVEL_TYPE_THREAD: u32 = 1;
const LEAFBH_LEVEL_TYPE_CORE: u32 = 2;

// The APIC ID shift in leaf 0xBh specifies the number of bits to shit the x2APIC ID to get a
// unique topology of the next level. This allows 64 logical processors/package.
const LEAFBH_INDEX1_APICID_SHIFT: u32 = 6;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    VcpuCountOverflow,
}

/// This function is used for setting leaf 01H EBX[23-16]
/// The maximum number of addressable logical CPUs is computed as the closest power of 2
/// higher or equal to the CPU count configured by the user
fn get_max_addressable_lprocessors(cpu_count: u8) -> result::Result<u8, Error> {
    let mut max_addressable_lcpu = (cpu_count as f64).log2().ceil();
    max_addressable_lcpu = (2 as f64).powf(max_addressable_lcpu);
    // check that this number is still an u8
    if max_addressable_lcpu > u8::max_value().into() {
        return Err(Error::VcpuCountOverflow);
    }
    Ok(max_addressable_lcpu as u8)
}

/// Sets up the cpuid entries for the given vcpu
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn filter_cpuid(cpu_id: u8, cpu_count: u8, kvm_cpuid: &mut CpuId) -> Result<()> {
    let entries = kvm_cpuid.mut_entries_slice();
    let max_addr_cpu = get_max_addressable_lprocessors(cpu_count).unwrap() as u32;
    for entry in entries.iter_mut() {
        match entry.function {
            0x1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << ECX_TSC_DEADLINE_TIMER_SHIFT;
                    entry.ecx |= 1 << ECX_HYPERVISOR_SHIFT;
                }
                entry.ebx = ((cpu_id as u32) << EBX_APICID_SHIFT) as u32
                    | (EBX_CLFLUSH_CACHELINE << EBX_CLFLUSH_SIZE_SHIFT);
                entry.ebx |= max_addr_cpu << EBX_CPU_COUNT_SHIFT;
                // Make sure that Hyperthreading is disabled
                entry.edx &= !(1 << EDX_HTT_SHIFT);
                // Enable Hyperthreading for even vCPU count so you don't end up with
                // an even and > 1 number of sibilings
                if cpu_count > 1 && cpu_count % 2 == 0 {
                    entry.edx |= 1 << EDX_HTT_SHIFT;
                }
            }
            0x4 => {
                // Deterministic Cache Parameters Leaf
                // Only use the last 3 bits of EAX[5:32] because the level is encoded in EAX[5:7]
                let cache_level = (entry.eax >> EAX_CACHE_LEVEL) & (0b111 as u32);
                match cache_level {
                    // L1 & L2 Cache
                    1 | 2 => {
                        // Set the maximum addressable IDS sharing the data cache to zero
                        // when you only have 1 vcpu because there are no other threads on
                        // the machine to share the data/instruction cache
                        // This sets EAX[25:14]
                        entry.eax &= !(0b111111111111 << EAX_MAX_ADDR_IDS_SHARING_CACHE);
                        if cpu_count > 1 {
                            // Hyperthreading is enabled by default for vcpu_count > 2
                            entry.eax |= 1 << EAX_MAX_ADDR_IDS_SHARING_CACHE;
                        }
                    }
                    // L3 Cache
                    3 => {
                        // Set the maximum addressable IDS sharing the data cache to zero
                        // when you only have 1 vcpu because there are no other threads on
                        // the machine to share the data/instruction cache
                        // This sets EAX[25:14]
                        entry.eax &= !(0b111111111111 << EAX_MAX_ADDR_IDS_SHARING_CACHE);
                        if cpu_count > 1 {
                            entry.eax |= ((cpu_count - 1) as u32) << EAX_MAX_ADDR_IDS_SHARING_CACHE;
                        }
                    }
                    _ => (),
                }

                // Maximum number of addressable IDs for processor cores in the physical package
                // should be the same on all cache levels
                // set this to 0 because there is only 1 core available for vcpu_count <= 2
                // This sets EAX[31:26]
                entry.eax &= !(0b111111 << EAX_MAX_ADDR_IDS_IN_PACKAGE);
                if cpu_count > 2 {
                    // we have HT enabled by default, so we will have cpu_count/2 cores in package
                    entry.eax |= (((cpu_count >> 1) - 1) as u32) << EAX_MAX_ADDR_IDS_IN_PACKAGE;
                }
            }
            0x6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << ECX_EPB_SHIFT);
            }
            0xB => {
                // Hide the actual topology of the underlying host
                match entry.index {
                    0 => {
                        // Thread Level Topology; index = 0
                        if cpu_count == 1 {
                            // No APIC ID at the next level, set EAX to 0
                            entry.eax = 0;
                            // Set the numbers of logical processors to 1
                            entry.ebx = 1;
                            // There are no hyperthreads for 1 VCPU, set the level type = 2 (Core)
                            entry.ecx = LEAFBH_LEVEL_TYPE_CORE << ECX_LEVEL_TYPE_SHIFT;
                        } else {
                            // To get the next level APIC ID, shift right with 1 because we have
                            // maximum 2 hyperthreads per core that can be represented with 1 bit
                            entry.eax = 1;
                            // 2 logical cores at this level
                            entry.ebx = 2;
                            // enforce this level to be of type thread
                            entry.ecx = LEAFBH_LEVEL_TYPE_THREAD << ECX_LEVEL_TYPE_SHIFT;
                        }
                    }
                    1 => {
                        // Core Level Processor Topology; index = 1
                        entry.eax = LEAFBH_INDEX1_APICID_SHIFT;
                        if cpu_count == 1 {
                            // For 1 vCPU, this level is invalid
                            entry.ebx = 0;
                            // ECX[7:0] = entry.index; ECX[15:8] = 0 (Invalid Level)
                            entry.ecx = (entry.index as u32)
                                | (LEAFBH_LEVEL_TYPE_INVALID << ECX_LEVEL_TYPE_SHIFT);
                        } else {
                            entry.ebx = cpu_count as u32;
                            entry.ecx = (entry.index as u32)
                                | (LEAFBH_LEVEL_TYPE_CORE << ECX_LEVEL_TYPE_SHIFT);
                        }
                    }
                    level => {
                        // Core Level Processor Topology; index >=2
                        // No other levels available; This should already be set to correctly,
                        // and it is added here as a "re-enforcement" in case we run on
                        // different hardware
                        entry.eax = 0;
                        entry.ebx = 0;
                        entry.ecx = level;
                    }
                }
                // EDX bits 31..0 contain x2APIC ID of current logical processor
                // x2APIC increases the size of the APIC ID from 8 bits to 32 bits
                entry.edx = cpu_id as u32;
            }
            _ => (),
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use kvm::{Kvm, MAX_KVM_CPUID_ENTRIES};
    use kvm_sys::kvm_cpuid_entry2;

    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[test]
    fn test_get_max_addressable_lprocessors() {
        assert_eq!(get_max_addressable_lprocessors(1).unwrap(), 1);
        assert_eq!(get_max_addressable_lprocessors(2).unwrap(), 2);
        assert_eq!(get_max_addressable_lprocessors(4).unwrap(), 4);
        assert_eq!(get_max_addressable_lprocessors(6).unwrap(), 8);
        assert!(get_max_addressable_lprocessors(u8::max_value()).is_err());
    }

    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[test]
    fn test_filter_cpuid() {
        let kvm = Kvm::new().unwrap();
        let mut kvm_cpuid: CpuId = kvm.get_supported_cpuid(MAX_KVM_CPUID_ENTRIES).unwrap();
        match filter_cpuid(0, 1, &mut kvm_cpuid) {
            Ok(_) => (),
            _ => assert!(false),
        };

        let entries = kvm_cpuid.mut_entries_slice();
        // TODO: add tests for the other cpuid leaves
        // Test the extended topology
        // See https://www.scss.tcd.ie/~jones/CS4021/processor-identification-cpuid-instruction-note.pdf
        let leaf11_index0 = kvm_cpuid_entry2 {
            function: 11,
            index: 0,
            flags: 1,
            eax: 0,
            ebx: 1,                                              // nr of hyperthreads/core
            ecx: LEAFBH_LEVEL_TYPE_CORE << ECX_LEVEL_TYPE_SHIFT, // ECX[15:8] = 2 (Core Level)
            edx: 0,                                              // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index0));
        let leaf11_index1 = kvm_cpuid_entry2 {
            function: 11,
            index: 1,
            flags: 1,
            eax: LEAFBH_INDEX1_APICID_SHIFT,
            ebx: 0,
            ecx: 1, // ECX[15:8] = 0 (Invalid Level) & ECX[7:0] = 1 (Level Number)
            edx: 0, // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index1));
        let leaf11_index2 = kvm_cpuid_entry2 {
            function: 11,
            index: 2,
            flags: 1,
            eax: 0,
            ebx: 0, // nr of hyperthreads/core
            ecx: 2, // ECX[15:8] = 0 (Invalid Level) & ECX[7:0] = 2 (Level Number)
            edx: 0, // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index2));
    }
}
<commit_msg>cpuid: group defines by leaf & register<commit_after>use kvm::CpuId;
use std::result;

// Basic CPUID Information
mod leaf_0x1 {
    pub mod ebx {
        pub const APICID_SHIFT: u32 = 24; // The (fixed) default APIC ID.
        pub const CLFLUSH_SIZE_SHIFT: u32 = 8; // Bytes flushed when executing CLFLUSH.
        pub const CPU_COUNT_SHIFT: u32 = 16; // The logical processor count.
    }

    pub mod ecx {
        pub const TSC_DEADLINE_TIMER_SHIFT: u32 = 24;
        // Flag to be set when the cpu is running on a hypervisor.
        pub const HYPERVISOR_SHIFT: u32 = 31;
    }

    pub mod edx {
        pub const HTT_SHIFT: u32 = 28; // Hyper Threading Enabled.
    }
}

// Deterministic Cache Parameters Leaf
mod leaf_0x4 {
    pub mod eax {
        pub const CACHE_LEVEL: u32 = 5;
        pub const MAX_ADDR_IDS_SHARING_CACHE: u32 = 14;
        pub const MAX_ADDR_IDS_IN_PACKAGE: u32 = 26;
    }
}

// Thermal and Power Management Leaf
mod leaf_0x6 {
    pub mod ecx {
        pub const EPB_SHIFT: u32 = 3; // "Energy Performance Bias" bit.
    }
}

// Extended Topology Leaf
#[allow(non_snake_case)]
mod leaf_0xb {
    pub const LEVEL_TYPE_INVALID: u32 = 0;
    pub const LEVEL_TYPE_THREAD: u32 = 1;
    pub const LEVEL_TYPE_CORE: u32 = 2;
    pub mod ecx {
        pub const LEVEL_TYPE_SHIFT: u32 = 8; // Shift for setting level type for leaf 11
    }
}

// constants for setting the fields of kvm_cpuid2 structures
// CPUID bits in ebx, ecx, and edx.
const EBX_CLFLUSH_CACHELINE: u32 = 8; // Flush a cache line size.

// The APIC ID shift in leaf 0xBh specifies the number of bits to shit the x2APIC ID to get a
// unique topology of the next level. This allows 64 logical processors/package.
const LEAFBH_INDEX1_APICID_SHIFT: u32 = 6;

pub type Result<T> = result::Result<T, Error>;

#[derive(Debug)]
pub enum Error {
    VcpuCountOverflow,
}

/// This function is used for setting leaf 01H EBX[23-16]
/// The maximum number of addressable logical CPUs is computed as the closest power of 2
/// higher or equal to the CPU count configured by the user
fn get_max_addressable_lprocessors(cpu_count: u8) -> result::Result<u8, Error> {
    let mut max_addressable_lcpu = (cpu_count as f64).log2().ceil();
    max_addressable_lcpu = (2 as f64).powf(max_addressable_lcpu);
    // check that this number is still an u8
    if max_addressable_lcpu > u8::max_value().into() {
        return Err(Error::VcpuCountOverflow);
    }
    Ok(max_addressable_lcpu as u8)
}

/// Sets up the cpuid entries for the given vcpu
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
pub fn filter_cpuid(cpu_id: u8, cpu_count: u8, kvm_cpuid: &mut CpuId) -> Result<()> {
    let entries = kvm_cpuid.mut_entries_slice();
    let max_addr_cpu = get_max_addressable_lprocessors(cpu_count).unwrap() as u32;
    for entry in entries.iter_mut() {
        match entry.function {
            0x1 => {
                // X86 hypervisor feature
                if entry.index == 0 {
                    entry.ecx |= 1 << leaf_0x1::ecx::TSC_DEADLINE_TIMER_SHIFT;
                    entry.ecx |= 1 << leaf_0x1::ecx::HYPERVISOR_SHIFT;
                }
                entry.ebx = ((cpu_id as u32) << leaf_0x1::ebx::APICID_SHIFT) as u32
                    | (EBX_CLFLUSH_CACHELINE << leaf_0x1::ebx::CLFLUSH_SIZE_SHIFT);
                entry.ebx |= max_addr_cpu << leaf_0x1::ebx::CPU_COUNT_SHIFT;
                // Make sure that Hyperthreading is disabled
                entry.edx &= !(1 << leaf_0x1::edx::HTT_SHIFT);
                // Enable Hyperthreading for even vCPU count so you don't end up with
                // an even and > 1 number of sibilings
                if cpu_count > 1 && cpu_count % 2 == 0 {
                    entry.edx |= 1 << leaf_0x1::edx::HTT_SHIFT;
                }
            }
            0x4 => {
                // Deterministic Cache Parameters Leaf
                // Only use the last 3 bits of EAX[5:32] because the level is encoded in EAX[5:7]
                let cache_level = (entry.eax >> leaf_0x4::eax::CACHE_LEVEL) & (0b111 as u32);
                match cache_level {
                    // L1 & L2 Cache
                    1 | 2 => {
                        // Set the maximum addressable IDS sharing the data cache to zero
                        // when you only have 1 vcpu because there are no other threads on
                        // the machine to share the data/instruction cache
                        // This sets EAX[25:14]
                        entry.eax &= !(0b111111111111 << leaf_0x4::eax::MAX_ADDR_IDS_SHARING_CACHE);
                        if cpu_count > 1 {
                            // Hyperthreading is enabled by default for vcpu_count > 2
                            entry.eax |= 1 << leaf_0x4::eax::MAX_ADDR_IDS_SHARING_CACHE;
                        }
                    }
                    // L3 Cache
                    3 => {
                        // Set the maximum addressable IDS sharing the data cache to zero
                        // when you only have 1 vcpu because there are no other threads on
                        // the machine to share the data/instruction cache
                        // This sets EAX[25:14]
                        entry.eax &= !(0b111111111111 << leaf_0x4::eax::MAX_ADDR_IDS_SHARING_CACHE);
                        if cpu_count > 1 {
                            entry.eax |= ((cpu_count - 1) as u32)
                                << leaf_0x4::eax::MAX_ADDR_IDS_SHARING_CACHE;
                        }
                    }
                    _ => (),
                }

                // Maximum number of addressable IDs for processor cores in the physical package
                // should be the same on all cache levels
                // set this to 0 because there is only 1 core available for vcpu_count <= 2
                // This sets EAX[31:26]
                entry.eax &= !(0b111111 << leaf_0x4::eax::MAX_ADDR_IDS_IN_PACKAGE);
                if cpu_count > 2 {
                    // we have HT enabled by default, so we will have cpu_count/2 cores in package
                    entry.eax |=
                        (((cpu_count >> 1) - 1) as u32) << leaf_0x4::eax::MAX_ADDR_IDS_IN_PACKAGE;
                }
            }
            0x6 => {
                // Clear X86 EPB feature.  No frequency selection in the hypervisor.
                entry.ecx &= !(1 << leaf_0x6::ecx::EPB_SHIFT);
            }
            0xB => {
                // Hide the actual topology of the underlying host
                match entry.index {
                    0 => {
                        // Thread Level Topology; index = 0
                        if cpu_count == 1 {
                            // No APIC ID at the next level, set EAX to 0
                            entry.eax = 0;
                            // Set the numbers of logical processors to 1
                            entry.ebx = 1;
                            // There are no hyperthreads for 1 VCPU, set the level type = 2 (Core)
                            entry.ecx =
                                leaf_0xb::LEVEL_TYPE_CORE << leaf_0xb::ecx::LEVEL_TYPE_SHIFT;
                        } else {
                            // To get the next level APIC ID, shift right with 1 because we have
                            // maximum 2 hyperthreads per core that can be represented with 1 bit
                            entry.eax = 1;
                            // 2 logical cores at this level
                            entry.ebx = 2;
                            // enforce this level to be of type thread
                            entry.ecx =
                                leaf_0xb::LEVEL_TYPE_THREAD << leaf_0xb::ecx::LEVEL_TYPE_SHIFT;
                        }
                    }
                    1 => {
                        // Core Level Processor Topology; index = 1
                        entry.eax = LEAFBH_INDEX1_APICID_SHIFT;
                        if cpu_count == 1 {
                            // For 1 vCPU, this level is invalid
                            entry.ebx = 0;
                            // ECX[7:0] = entry.index; ECX[15:8] = 0 (Invalid Level)
                            entry.ecx = (entry.index as u32)
                                | (leaf_0xb::LEVEL_TYPE_INVALID << leaf_0xb::ecx::LEVEL_TYPE_SHIFT);
                        } else {
                            entry.ebx = cpu_count as u32;
                            entry.ecx = (entry.index as u32)
                                | (leaf_0xb::LEVEL_TYPE_CORE << leaf_0xb::ecx::LEVEL_TYPE_SHIFT);
                        }
                    }
                    level => {
                        // Core Level Processor Topology; index >=2
                        // No other levels available; This should already be set to correctly,
                        // and it is added here as a "re-enforcement" in case we run on
                        // different hardware
                        entry.eax = 0;
                        entry.ebx = 0;
                        entry.ecx = level;
                    }
                }
                // EDX bits 31..0 contain x2APIC ID of current logical processor
                // x2APIC increases the size of the APIC ID from 8 bits to 32 bits
                entry.edx = cpu_id as u32;
            }
            _ => (),
        }
    }

    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use kvm::{Kvm, MAX_KVM_CPUID_ENTRIES};
    use kvm_sys::kvm_cpuid_entry2;

    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[test]
    fn test_get_max_addressable_lprocessors() {
        assert_eq!(get_max_addressable_lprocessors(1).unwrap(), 1);
        assert_eq!(get_max_addressable_lprocessors(2).unwrap(), 2);
        assert_eq!(get_max_addressable_lprocessors(4).unwrap(), 4);
        assert_eq!(get_max_addressable_lprocessors(6).unwrap(), 8);
        assert!(get_max_addressable_lprocessors(u8::max_value()).is_err());
    }

    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    #[test]
    fn test_filter_cpuid() {
        let kvm = Kvm::new().unwrap();
        let mut kvm_cpuid: CpuId = kvm.get_supported_cpuid(MAX_KVM_CPUID_ENTRIES).unwrap();
        match filter_cpuid(0, 1, &mut kvm_cpuid) {
            Ok(_) => (),
            _ => assert!(false),
        };

        let entries = kvm_cpuid.mut_entries_slice();
        // TODO: add tests for the other cpuid leaves
        // Test the extended topology
        // See https://www.scss.tcd.ie/~jones/CS4021/processor-identification-cpuid-instruction-note.pdf
        let leaf11_index0 = kvm_cpuid_entry2 {
            function: 11,
            index: 0,
            flags: 1,
            eax: 0,
            ebx: 1, // nr of hyperthreads/core
            ecx: leaf_0xb::LEVEL_TYPE_CORE << leaf_0xb::ecx::LEVEL_TYPE_SHIFT, // ECX[15:8] = 2 (Core Level)
            edx: 0,                                                            // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index0));
        let leaf11_index1 = kvm_cpuid_entry2 {
            function: 11,
            index: 1,
            flags: 1,
            eax: LEAFBH_INDEX1_APICID_SHIFT,
            ebx: 0,
            ecx: 1, // ECX[15:8] = 0 (Invalid Level) & ECX[7:0] = 1 (Level Number)
            edx: 0, // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index1));
        let leaf11_index2 = kvm_cpuid_entry2 {
            function: 11,
            index: 2,
            flags: 1,
            eax: 0,
            ebx: 0, // nr of hyperthreads/core
            ecx: 2, // ECX[15:8] = 0 (Invalid Level) & ECX[7:0] = 2 (Level Number)
            edx: 0, // EDX = APIC ID = 0
            padding: [0, 0, 0],
        };
        assert!(entries.contains(&leaf11_index2));
    }
}
<|endoftext|>


<commit_before>//! parsing data from the configuration file
use std::collections::HashMap;
use std::io::{self,Error,ErrorKind,Read};
use std::fs::File;
use std::str::FromStr;
use command::data::ListenerType;
use toml;

use yxorp::messages::{HttpProxyConfiguration,TlsProxyConfiguration};

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct ListenerConfig {
  pub listener_type:   ListenerType,
  pub address:         String,
  pub public_address:  Option<String>,
  pub port:            u16,
  pub max_connections: usize,
  pub buffer_size:     usize,
  pub answer_404:      Option<String>,
  pub answer_503:      Option<String>,
  pub cipher_list:     Option<String>,
  pub worker_count:    Option<u16>,
}

impl ListenerConfig {
  pub fn to_http(&self) -> Option<HttpProxyConfiguration> {
    let mut address = self.address.clone();
    address.push(':');
    address.push_str(&self.port.to_string());

    let public_address = self.public_address.as_ref().and_then(|addr| FromStr::from_str(&addr).ok());
    //FIXME: error message when we cannot parse the address
    address.parse().ok().map(|addr| {
    HttpProxyConfiguration {
      front: addr,
      public_address: public_address,
      max_connections: self.max_connections,
      buffer_size: self.buffer_size,
      //FIXME: handle the default case,
      answer_404: String::from(""),
      answer_503: String::from(""),
      ..Default::default()
    }
    })
  }

  pub fn to_tls(&self) -> Option<TlsProxyConfiguration> {
    let mut address = self.address.clone();
    address.push(':');
    address.push_str(&self.port.to_string());

    let public_address     = self.public_address.as_ref().and_then(|addr| FromStr::from_str(&addr).ok());
    let cipher_list:String = self.cipher_list.clone().unwrap_or(String::from(""));
    //FIXME: error message when we cannot parse the address
    address.parse().ok().map(|addr| {
    TlsProxyConfiguration {
      front: addr,
      public_address: public_address,
      max_connections: self.max_connections,
      buffer_size: self.buffer_size,
      //FIXME: handle the default case,
      answer_404: String::from(""),
      answer_503: String::from(""),
      cipher_list: cipher_list,
      ..Default::default()
    }
    })
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct MetricsConfig {
  pub address: String,
  pub port:    u16,
}

#[derive(Debug,Clone,PartialEq,Eq, RustcDecodable, RustcEncodable)]
pub struct Config {
  pub command_socket: String,
  pub command_buffer_size: Option<usize>,
  pub max_command_buffer_size: Option<usize>,
  pub saved_state:    Option<String>,
  pub metrics:        MetricsConfig,
  pub listeners:      HashMap<String, ListenerConfig>,
  pub log_level:      Option<String>,
}

impl Config {
  pub fn load_from_path(path: &str) -> io::Result<Config> {
    let mut f = try!(File::open(path));
    let mut data = String::new();
    try!(f.read_to_string(&mut data));

    let mut parser = toml::Parser::new(&data[..]);
    if let Some(config) = parser.parse().and_then(|t| toml::decode(toml::Value::Table(t))) {
      Ok(config)
    } else {
      Err(Error::new(ErrorKind::InvalidData, format!("could not parse the configuration file: {:?}", parser.errors)))
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::collections::HashMap;
  use toml::encode_str;
  use command::data::ListenerType;

  #[test]
  fn serialize() {
    let mut map = HashMap::new();
    map.insert(String::from("HTTP"), ListenerConfig {
      listener_type: ListenerType::HTTP,
      address: String::from("127.0.0.1"),
      port: 8080,
      max_connections: 500,
      buffer_size: 12000,
      answer_404: Some(String::from("404.html")),
      answer_503: None,
      public_address: None,
      cipher_list: None,
      worker_count: None,
    });
    map.insert(String::from("TLS"), ListenerConfig {
      listener_type: ListenerType::HTTPS,
      address: String::from("127.0.0.1"),
      port: 8080,
      max_connections: 500,
      buffer_size: 12000,
      answer_404: Some(String::from("404.html")),
      answer_503: None,
      public_address: None,
      cipher_list: None,
      worker_count: None,
    });
    let config = Config {
      command_socket: String::from("./command_folder/sock"),
      saved_state: None,
      command_buffer_size: None,
      max_command_buffer_size: None,
      log_level: None,
      metrics: MetricsConfig {
        address: String::from("192.168.59.103"),
        port:    8125,
      },
      listeners: map
    };

    let encoded = encode_str(&config);
    println!("conf:\n{}", encoded);
  }
}
<commit_msg>Pass the default answers from the configuration<commit_after>//! parsing data from the configuration file
use std::collections::HashMap;
use std::io::{self,Error,ErrorKind,Read};
use std::fs::File;
use std::str::FromStr;
use command::data::ListenerType;
use toml;

use yxorp::messages::{HttpProxyConfiguration,TlsProxyConfiguration};

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct ListenerConfig {
  pub listener_type:   ListenerType,
  pub address:         String,
  pub public_address:  Option<String>,
  pub port:            u16,
  pub max_connections: usize,
  pub buffer_size:     usize,
  pub answer_404:      Option<String>,
  pub answer_503:      Option<String>,
  pub cipher_list:     Option<String>,
  pub worker_count:    Option<u16>,
}

impl ListenerConfig {
  pub fn to_http(&self) -> Option<HttpProxyConfiguration> {
    let mut address = self.address.clone();
    address.push(':');
    address.push_str(&self.port.to_string());

    let public_address = self.public_address.as_ref().and_then(|addr| FromStr::from_str(&addr).ok());
    //FIXME: error message when we cannot parse the address
    address.parse().ok().map(|addr| {
      let mut configuration = HttpProxyConfiguration {
        front: addr,
        public_address: public_address,
        max_connections: self.max_connections,
        buffer_size: self.buffer_size,
        ..Default::default()
      };

      //FIXME: error messages if file not found?
      let mut answer_404 = String::new();
      if self.answer_404.as_ref().and_then(|path| File::open(path).ok())
        .and_then(|mut file| file.read_to_string(&mut answer_404).ok()).is_some() {
        configuration.answer_404 = answer_404;
      }
      let mut answer_503 = String::new();
      if self.answer_503.as_ref().and_then(|path| File::open(path).ok())
        .and_then(|mut file| file.read_to_string(&mut answer_503).ok()).is_some() {
        configuration.answer_503 = answer_503;
      }
      configuration
    })
  }

  pub fn to_tls(&self) -> Option<TlsProxyConfiguration> {
    let mut address = self.address.clone();
    address.push(':');
    address.push_str(&self.port.to_string());

    let public_address     = self.public_address.as_ref().and_then(|addr| FromStr::from_str(&addr).ok());
    let cipher_list:String = self.cipher_list.clone().unwrap_or(String::from(""));
    //FIXME: error message when we cannot parse the address
    address.parse().ok().map(|addr| {
      let mut configuration = TlsProxyConfiguration {
        front: addr,
        public_address: public_address,
        max_connections: self.max_connections,
        buffer_size: self.buffer_size,
        ..Default::default()
      };
      //FIXME: error messages if file not found?
      let mut answer_404 = String::new();
      if self.answer_404.as_ref().and_then(|path| File::open(path).ok())
        .and_then(|mut file| file.read_to_string(&mut answer_404).ok()).is_some() {
        configuration.answer_404 = answer_404;
      }
      let mut answer_503 = String::new();
      if self.answer_503.as_ref().and_then(|path| File::open(path).ok())
        .and_then(|mut file| file.read_to_string(&mut answer_503).ok()).is_some() {
        configuration.answer_503 = answer_503;
      }
      if let Some(cipher_list) = self.cipher_list.as_ref() {
        configuration.cipher_list = cipher_list.clone();
      }
      configuration

    })
  }
}

#[derive(Debug,Clone,PartialEq,Eq,Hash, RustcDecodable, RustcEncodable)]
pub struct MetricsConfig {
  pub address: String,
  pub port:    u16,
}

#[derive(Debug,Clone,PartialEq,Eq, RustcDecodable, RustcEncodable)]
pub struct Config {
  pub command_socket: String,
  pub command_buffer_size: Option<usize>,
  pub max_command_buffer_size: Option<usize>,
  pub saved_state:    Option<String>,
  pub metrics:        MetricsConfig,
  pub listeners:      HashMap<String, ListenerConfig>,
  pub log_level:      Option<String>,
}

impl Config {
  pub fn load_from_path(path: &str) -> io::Result<Config> {
    let mut f = try!(File::open(path));
    let mut data = String::new();
    try!(f.read_to_string(&mut data));

    let mut parser = toml::Parser::new(&data[..]);
    if let Some(config) = parser.parse().and_then(|t| toml::decode(toml::Value::Table(t))) {
      Ok(config)
    } else {
      Err(Error::new(ErrorKind::InvalidData, format!("could not parse the configuration file: {:?}", parser.errors)))
    }
  }
}

#[cfg(test)]
mod tests {
  use super::*;
  use std::collections::HashMap;
  use toml::encode_str;
  use command::data::ListenerType;

  #[test]
  fn serialize() {
    let mut map = HashMap::new();
    map.insert(String::from("HTTP"), ListenerConfig {
      listener_type: ListenerType::HTTP,
      address: String::from("127.0.0.1"),
      port: 8080,
      max_connections: 500,
      buffer_size: 12000,
      answer_404: Some(String::from("404.html")),
      answer_503: None,
      public_address: None,
      cipher_list: None,
      worker_count: None,
    });
    map.insert(String::from("TLS"), ListenerConfig {
      listener_type: ListenerType::HTTPS,
      address: String::from("127.0.0.1"),
      port: 8080,
      max_connections: 500,
      buffer_size: 12000,
      answer_404: Some(String::from("404.html")),
      answer_503: None,
      public_address: None,
      cipher_list: None,
      worker_count: None,
    });
    let config = Config {
      command_socket: String::from("./command_folder/sock"),
      saved_state: None,
      command_buffer_size: None,
      max_command_buffer_size: None,
      log_level: None,
      metrics: MetricsConfig {
        address: String::from("192.168.59.103"),
        port:    8125,
      },
      listeners: map
    };

    let encoded = encode_str(&config);
    println!("conf:\n{}", encoded);
  }
}
<|endoftext|>


<commit_before>//! JSON and serialization
//!
//! # What is JSON?
//!
//! JSON (JavaScript Object Notation) is a way to write data in JavaScript.  Like XML, it allows to
//! encode structured data in a text format that can be easily read by humans.  Its simple syntax
//! and native compatibility with JavaScript have made it a widely used format.
//!
//! Data types that can be encoded are JavaScript types (see the `serde_json:Value` enum for more
//! details):
//!
//! * `Boolean`: equivalent to rust's `bool`
//! * `I64`: equivalent to rust's `i64`
//! * `U64`: equivalent to rust's `u64`
//! * `F64`: equivalent to rust's `i64`
//! * `String`: equivalent to rust's `String`
//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
//!    same array
//! * `Object`: equivalent to rust's `BTreeMap<String, serde_json::Value>`
//! * `Null`
//!
//! An object is a series of string keys mapping to values, in `"key": value` format.  Arrays are
//! enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).  A simple JSON
//! document encoding a person, his/her age, address and phone numbers could look like
//!
//! ```ignore
//! {
//!     "FirstName": "John",
//!     "LastName": "Doe",
//!     "Age": 43,
//!     "Address": {
//!         "Street": "Downing Street 10",
//!         "City": "London",
//!         "Country": "Great Britain"
//!     },
//!     "PhoneNumbers": [
//!         "+44 1234567",
//!         "+44 2345678"
//!     ]
//! }
//! ```
//!
//! If we assume that FirstName is optional and all other fields are mandatory, the above JSON could
//! correspond to the following Rust structs:
//!
//! ```rust
//! #[derive(Serialize, Deserialize)]
//! struct Data {
//!     #[serde(rename="FirstName")] // to comply with Rust coding standards
//!     first_name: Option<String>,
//!     LastName: String,
//!     Age: u32,
//!     Address: Address,
//!     PhoneNumbers: Vec<String>
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     Street: String,
//!     City: String,
//!     Country: String
//! }
//! ```
//!
//! # Type-based Serialization and Deserialization
//!
//! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and
//! from JSON via the serialization API.  To be able to serialize a piece of data, it must implement
//! the `serde::Serialize` trait.  To be able to deserialize a piece of data, it must implement the
//! `serde::Deserialize` trait.  Serde provides provides an annotation to automatically generate
//! the code for these traits: `#[derive(Serialize, Deserialize)]`.
//!
//! The JSON API also provides an enum `serde_json::Value` and a method `to_value` to serialize
//! objects.  A `serde_json::Value` value can be serialized as a string or buffer using the
//! functions described above.  You can also use the `json::Serializer` object, which implements the
//! `Serializer` trait.
//!
//! # Examples of use
//!
//! ## Parsing a `str` to `Value` and reading the result
//!
//! ```rust
//! //#![feature(custom_derive, plugin)]
//! //#![plugin(serde_macros)]
//!
//! extern crate serde_json;
//!
//! use serde_json::Value;
//!
//! fn main() {
//!     let data: Value = serde_json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap();
//!     println!("data: {:?}", data);
//!     // data: {"bar":"baz","foo":13}
//!     println!("object? {}", data.is_object());
//!     // object? true
//!
//!     let obj = data.as_object().unwrap();
//!     let foo = obj.get("foo").unwrap();
//!
//!     println!("array? {:?}", foo.as_array());
//!     // array? None
//!     println!("u64? {:?}", foo.as_u64());
//!     // u64? Some(13u64)
//!
//!     for (key, value) in obj.iter() {
//!         println!("{}: {}", key, match *value {
//!             Value::U64(v) => format!("{} (u64)", v),
//!             Value::String(ref v) => format!("{} (string)", v),
//!             _ => format!("other")
//!         });
//!     }
//!     // bar: baz (string)
//!     // foo: 13 (u64)
//! }
//! ```

#![deny(missing_docs)]

extern crate num;
extern crate serde;

pub use self::de::{
    Deserializer,
    from_iter,
    from_reader,
    from_slice,
    from_str,
};
pub use self::error::{Error, ErrorCode, Result};
pub use self::ser::{
    Serializer,
    to_writer,
    to_writer_pretty,
    to_vec,
    to_vec_pretty,
    to_string,
    to_string_pretty,
    escape_str,
};
pub use self::value::{Value, to_value, from_value};

pub mod builder;
pub mod de;
pub mod error;
pub mod ser;
pub mod value;
<commit_msg>Add custom_derive<commit_after>//! JSON and serialization
//!
//! # What is JSON?
//!
//! JSON (JavaScript Object Notation) is a way to write data in JavaScript.  Like XML, it allows to
//! encode structured data in a text format that can be easily read by humans.  Its simple syntax
//! and native compatibility with JavaScript have made it a widely used format.
//!
//! Data types that can be encoded are JavaScript types (see the `serde_json:Value` enum for more
//! details):
//!
//! * `Boolean`: equivalent to rust's `bool`
//! * `I64`: equivalent to rust's `i64`
//! * `U64`: equivalent to rust's `u64`
//! * `F64`: equivalent to rust's `i64`
//! * `String`: equivalent to rust's `String`
//! * `Array`: equivalent to rust's `Vec<T>`, but also allowing objects of different types in the
//!    same array
//! * `Object`: equivalent to rust's `BTreeMap<String, serde_json::Value>`
//! * `Null`
//!
//! An object is a series of string keys mapping to values, in `"key": value` format.  Arrays are
//! enclosed in square brackets ([ ... ]) and objects in curly brackets ({ ... }).  A simple JSON
//! document encoding a person, his/her age, address and phone numbers could look like
//!
//! ```ignore
//! {
//!     "FirstName": "John",
//!     "LastName": "Doe",
//!     "Age": 43,
//!     "Address": {
//!         "Street": "Downing Street 10",
//!         "City": "London",
//!         "Country": "Great Britain"
//!     },
//!     "PhoneNumbers": [
//!         "+44 1234567",
//!         "+44 2345678"
//!     ]
//! }
//! ```
//!
//! If we assume that FirstName is optional and all other fields are mandatory, the above JSON could
//! correspond to the following Rust structs:
//!
//! ```rust
//! //#![feature(custom_derive, plugin)]
//! #[derive(Serialize, Deserialize)]
//! struct Data {
//!     #[serde(rename="FirstName")] // to comply with Rust coding standards
//!     first_name: Option<String>,
//!     LastName: String,
//!     Age: u32,
//!     Address: Address,
//!     PhoneNumbers: Vec<String>
//! }
//!
//! #[derive(Serialize, Deserialize)]
//! struct Address {
//!     Street: String,
//!     City: String,
//!     Country: String
//! }
//! ```
//!
//! # Type-based Serialization and Deserialization
//!
//! Serde provides a mechanism for low boilerplate serialization & deserialization of values to and
//! from JSON via the serialization API.  To be able to serialize a piece of data, it must implement
//! the `serde::Serialize` trait.  To be able to deserialize a piece of data, it must implement the
//! `serde::Deserialize` trait.  Serde provides provides an annotation to automatically generate
//! the code for these traits: `#[derive(Serialize, Deserialize)]`.
//!
//! The JSON API also provides an enum `serde_json::Value` and a method `to_value` to serialize
//! objects.  A `serde_json::Value` value can be serialized as a string or buffer using the
//! functions described above.  You can also use the `json::Serializer` object, which implements the
//! `Serializer` trait.
//!
//! # Examples of use
//!
//! ## Parsing a `str` to `Value` and reading the result
//!
//! ```rust
//! //#![feature(custom_derive, plugin)]
//! //#![plugin(serde_macros)]
//!
//! extern crate serde_json;
//!
//! use serde_json::Value;
//!
//! fn main() {
//!     let data: Value = serde_json::from_str("{\"foo\": 13, \"bar\": \"baz\"}").unwrap();
//!     println!("data: {:?}", data);
//!     // data: {"bar":"baz","foo":13}
//!     println!("object? {}", data.is_object());
//!     // object? true
//!
//!     let obj = data.as_object().unwrap();
//!     let foo = obj.get("foo").unwrap();
//!
//!     println!("array? {:?}", foo.as_array());
//!     // array? None
//!     println!("u64? {:?}", foo.as_u64());
//!     // u64? Some(13u64)
//!
//!     for (key, value) in obj.iter() {
//!         println!("{}: {}", key, match *value {
//!             Value::U64(v) => format!("{} (u64)", v),
//!             Value::String(ref v) => format!("{} (string)", v),
//!             _ => format!("other")
//!         });
//!     }
//!     // bar: baz (string)
//!     // foo: 13 (u64)
//! }
//! ```

#![deny(missing_docs)]

extern crate num;
extern crate serde;

pub use self::de::{
    Deserializer,
    from_iter,
    from_reader,
    from_slice,
    from_str,
};
pub use self::error::{Error, ErrorCode, Result};
pub use self::ser::{
    Serializer,
    to_writer,
    to_writer_pretty,
    to_vec,
    to_vec_pretty,
    to_string,
    to_string_pretty,
    escape_str,
};
pub use self::value::{Value, to_value, from_value};

pub mod builder;
pub mod de;
pub mod error;
pub mod ser;
pub mod value;
<|endoftext|>


<commit_before>import middle::typeck::infer::{ty_and_region_var_methods};

fn check_alt(fcx: @fn_ctxt,
             expr: @ast::expr,
             discrim: @ast::expr,
             arms: [ast::arm]) -> bool {
    let tcx = fcx.ccx.tcx;
    let mut bot;

    let pattern_ty = fcx.infcx.next_ty_var();
    bot = check_expr_with(fcx, discrim, pattern_ty);

    // Typecheck the patterns first, so that we get types for all the
    // bindings.
    for arms.each {|arm|
        let pcx = {
            fcx: fcx,
            map: pat_id_map(tcx.def_map, arm.pats[0]),
            alt_region: ty::re_scope(expr.id),
            block_region: ty::re_scope(arm.body.node.id),
            pat_region: ty::re_scope(expr.id)
        };

        for arm.pats.each {|p| check_pat(pcx, p, pattern_ty);}
    }
    // Now typecheck the blocks.
    let mut result_ty = fcx.infcx.next_ty_var();
    let mut arm_non_bot = false;
    for arms.each {|arm|
        alt arm.guard {
          some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); }
          none { }
        }
        if !check_block(fcx, arm.body) { arm_non_bot = true; }
        let bty = fcx.node_ty(arm.body.node.id);
        demand::suptype(fcx, arm.body.span, result_ty, bty);
    }
    bot |= !arm_non_bot;
    if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
    fcx.write_ty(expr.id, result_ty);
    ret bot;
}

type pat_ctxt = {
    fcx: @fn_ctxt,
    map: pat_id_map,
    alt_region: ty::region,
    block_region: ty::region,
    /* Equal to either alt_region or block_region. */
    pat_region: ty::region
};

fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
                     subpats: option<[@ast::pat]>, expected: ty::t) {

    // Typecheck the path.
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    // Lookup the enum and variant def ids:
    let v_def = lookup_def(pcx.fcx, path.span, pat.id);
    let v_def_ids = ast_util::variant_def_ids(v_def);

    // Assign the pattern the type of the *enum*, not the variant.
    let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
    instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);

    // Take the enum type params out of `expected`.
    alt structure_of(pcx.fcx, pat.span, expected) {
      ty::ty_enum(_, expected_substs) {
        // check that the type of the value being matched is a subtype
        // of the type of the pattern:
        let pat_ty = fcx.node_ty(pat.id);
        demand::suptype(fcx, pat.span, pat_ty, expected);

        // Get the expected types of the arguments.
        let arg_types = {
            let vinfo =
                ty::enum_variant_with_id(
                    tcx, v_def_ids.enm, v_def_ids.var);
            vinfo.args.map { |t| ty::subst(tcx, expected_substs, t) }
        };
        let arg_len = arg_types.len(), subpats_len = alt subpats {
            none { arg_len }
            some(ps) { ps.len() }};
        if arg_len > 0u {
            // N-ary variant.
            if arg_len != subpats_len {
                let s = #fmt["this pattern has %u field%s, but the \
                              corresponding variant has %u field%s",
                             subpats_len,
                             if subpats_len == 1u { "" } else { "s" },
                             arg_len,
                             if arg_len == 1u { "" } else { "s" }];
                tcx.sess.span_fatal(pat.span, s);
            }

            option::iter(subpats) {|pats|
                vec::iter2(pats, arg_types) {|subpat, arg_ty|
                  check_pat(pcx, subpat, arg_ty);
                }
            };
        } else if subpats_len > 0u {
            tcx.sess.span_fatal
                (pat.span, #fmt["this pattern has %u field%s, \
                                 but the corresponding variant has no fields",
                                subpats_len,
                                if subpats_len == 1u { "" }
                                else { "s" }]);
        }
      }
      _ {
        tcx.sess.span_fatal
            (pat.span,
             #fmt["mismatched types: expected enum but found `%s`",
                  fcx.ty_to_str(expected)]);
      }
    }
}

// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;
    alt pat.node {
      ast::pat_wild {
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_lit(lt) {
        check_expr_with(pcx.fcx, lt, expected);
        fcx.write_ty(pat.id, fcx.expr_ty(lt));
      }
      ast::pat_range(begin, end) {
        check_expr_with(pcx.fcx, begin, expected);
        check_expr_with(pcx.fcx, end, expected);
        let b_ty = resolve_type_vars_if_possible(pcx.fcx,
                                                 fcx.expr_ty(begin));
        if !require_same_types(
            tcx, pat.span, b_ty,
            resolve_type_vars_if_possible(
                pcx.fcx, fcx.expr_ty(end)),
            {|| "mismatched types in range" }) {
            // no-op
        } else if !ty::type_is_numeric(b_ty) {
            tcx.sess.span_err(pat.span, "non-numeric type used in range");
        } else if !valid_range_bounds(pcx.fcx.ccx, begin, end) {
            tcx.sess.span_err(begin.span, "lower range bound must be less \
                                           than upper");
        }
        fcx.write_ty(pat.id, b_ty);
      }
      ast::pat_ident(name, sub) if !pat_is_variant(tcx.def_map, pat) {
        let vid = lookup_local(pcx.fcx, pat.span, pat.id);
        let mut typ = ty::mk_var(tcx, vid);
        demand::suptype(pcx.fcx, pat.span, expected, typ);
        let canon_id = pcx.map.get(ast_util::path_to_ident(name));
        if canon_id != pat.id {
            let tv_id = lookup_local(pcx.fcx, pat.span, canon_id);
            let ct = ty::mk_var(tcx, tv_id);
            demand::suptype(pcx.fcx, pat.span, ct, typ);
        }
        fcx.write_ty(pat.id, typ);
        alt sub {
          some(p) { check_pat(pcx, p, expected); }
          _ {}
        }
      }
      ast::pat_ident(path, c) {
        check_pat_variant(pcx, pat, path, some([]), expected);
      }
      ast::pat_enum(path, subpats) {
        check_pat_variant(pcx, pat, path, subpats, expected);
      }
      ast::pat_rec(fields, etc) {
        let ex_fields = alt structure_of(pcx.fcx, pat.span, expected) {
          ty::ty_rec(fields) { fields }
          _ {
            tcx.sess.span_fatal
                (pat.span,
                #fmt["mismatched types: expected `%s` but found record",
                     fcx.ty_to_str(expected)]);
          }
        };
        let f_count = vec::len(fields);
        let ex_f_count = vec::len(ex_fields);
        if ex_f_count < f_count || !etc && ex_f_count > f_count {
            tcx.sess.span_fatal
                (pat.span, #fmt["mismatched types: expected a record \
                      with %u fields, found one with %u \
                      fields",
                                ex_f_count, f_count]);
        }
        fn matches(name: str, f: ty::field) -> bool {
            ret str::eq(name, f.ident);
        }
        for fields.each {|f|
            alt vec::find(ex_fields, bind matches(f.ident, _)) {
              some(field) {
                check_pat(pcx, f.pat, field.mt.ty);
              }
              none {
                tcx.sess.span_fatal(pat.span,
                                    #fmt["mismatched types: did not \
                                          expect a record with a field `%s`",
                                         f.ident]);
              }
            }
        }
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_tup(elts) {
        let ex_elts = alt structure_of(pcx.fcx, pat.span, expected) {
          ty::ty_tup(elts) { elts }
          _ {
            tcx.sess.span_fatal
                (pat.span,
                 #fmt["mismatched types: expected `%s`, found tuple",
                      fcx.ty_to_str(expected)]);
          }
        };
        let e_count = vec::len(elts);
        if e_count != vec::len(ex_elts) {
            tcx.sess.span_fatal
                (pat.span, #fmt["mismatched types: expected a tuple \
                      with %u fields, found one with %u \
                      fields", vec::len(ex_elts), e_count]);
        }
        let mut i = 0u;
        for elts.each {|elt|
            check_pat(pcx, elt, ex_elts[i]);
            i += 1u;
        }

        fcx.write_ty(pat.id, expected);
      }
      ast::pat_box(inner) {
        alt structure_of(pcx.fcx, pat.span, expected) {
          ty::ty_box(e_inner) {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ {
            tcx.sess.span_fatal(
                pat.span,
                "mismatched types: expected `" +
                pcx.fcx.ty_to_str(expected) +
                "` found box");
          }
        }
      }
      ast::pat_uniq(inner) {
        alt structure_of(pcx.fcx, pat.span, expected) {
          ty::ty_uniq(e_inner) {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ {
            tcx.sess.span_fatal(
                pat.span,
                "mismatched types: expected `" +
                pcx.fcx.ty_to_str(expected) +
                "` found uniq");
          }
        }
      }
    }
}

<commit_msg>typeck: Minor cleanup<commit_after>import middle::typeck::infer::{ty_and_region_var_methods};

fn check_alt(fcx: @fn_ctxt,
             expr: @ast::expr,
             discrim: @ast::expr,
             arms: [ast::arm]) -> bool {
    let tcx = fcx.ccx.tcx;
    let mut bot;

    let pattern_ty = fcx.infcx.next_ty_var();
    bot = check_expr_with(fcx, discrim, pattern_ty);

    // Typecheck the patterns first, so that we get types for all the
    // bindings.
    for arms.each {|arm|
        let pcx = {
            fcx: fcx,
            map: pat_id_map(tcx.def_map, arm.pats[0]),
            alt_region: ty::re_scope(expr.id),
            block_region: ty::re_scope(arm.body.node.id),
            pat_region: ty::re_scope(expr.id)
        };

        for arm.pats.each {|p| check_pat(pcx, p, pattern_ty);}
    }
    // Now typecheck the blocks.
    let mut result_ty = fcx.infcx.next_ty_var();
    let mut arm_non_bot = false;
    for arms.each {|arm|
        alt arm.guard {
          some(e) { check_expr_with(fcx, e, ty::mk_bool(tcx)); }
          none { }
        }
        if !check_block(fcx, arm.body) { arm_non_bot = true; }
        let bty = fcx.node_ty(arm.body.node.id);
        demand::suptype(fcx, arm.body.span, result_ty, bty);
    }
    bot |= !arm_non_bot;
    if !arm_non_bot { result_ty = ty::mk_bot(tcx); }
    fcx.write_ty(expr.id, result_ty);
    ret bot;
}

type pat_ctxt = {
    fcx: @fn_ctxt,
    map: pat_id_map,
    alt_region: ty::region,
    block_region: ty::region,
    /* Equal to either alt_region or block_region. */
    pat_region: ty::region
};

fn check_pat_variant(pcx: pat_ctxt, pat: @ast::pat, path: @ast::path,
                     subpats: option<[@ast::pat]>, expected: ty::t) {

    // Typecheck the path.
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;

    // Lookup the enum and variant def ids:
    let v_def = lookup_def(pcx.fcx, path.span, pat.id);
    let v_def_ids = ast_util::variant_def_ids(v_def);

    // Assign the pattern the type of the *enum*, not the variant.
    let enum_tpt = ty::lookup_item_type(tcx, v_def_ids.enm);
    instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);

    // Take the enum type params out of `expected`.
    alt structure_of(pcx.fcx, pat.span, expected) {
      ty::ty_enum(_, expected_substs) {
        // check that the type of the value being matched is a subtype
        // of the type of the pattern:
        let pat_ty = fcx.node_ty(pat.id);
        demand::suptype(fcx, pat.span, pat_ty, expected);

        // Get the expected types of the arguments.
        let arg_types = {
            let vinfo =
                ty::enum_variant_with_id(
                    tcx, v_def_ids.enm, v_def_ids.var);
            vinfo.args.map { |t| ty::subst(tcx, expected_substs, t) }
        };
        let arg_len = arg_types.len(), subpats_len = alt subpats {
            none { arg_len }
            some(ps) { ps.len() }};
        if arg_len > 0u {
            // N-ary variant.
            if arg_len != subpats_len {
                let s = #fmt["this pattern has %u field%s, but the \
                              corresponding variant has %u field%s",
                             subpats_len,
                             if subpats_len == 1u { "" } else { "s" },
                             arg_len,
                             if arg_len == 1u { "" } else { "s" }];
                tcx.sess.span_fatal(pat.span, s);
            }

            option::iter(subpats) {|pats|
                vec::iter2(pats, arg_types) {|subpat, arg_ty|
                  check_pat(pcx, subpat, arg_ty);
                }
            };
        } else if subpats_len > 0u {
            tcx.sess.span_fatal
                (pat.span, #fmt["this pattern has %u field%s, \
                                 but the corresponding variant has no fields",
                                subpats_len,
                                if subpats_len == 1u { "" }
                                else { "s" }]);
        }
      }
      _ {
        tcx.sess.span_fatal
            (pat.span,
             #fmt["mismatched types: expected enum but found `%s`",
                  fcx.ty_to_str(expected)]);
      }
    }
}

// Pattern checking is top-down rather than bottom-up so that bindings get
// their types immediately.
fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
    let fcx = pcx.fcx;
    let tcx = pcx.fcx.ccx.tcx;
    alt pat.node {
      ast::pat_wild {
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_lit(lt) {
        check_expr_with(fcx, lt, expected);
        fcx.write_ty(pat.id, fcx.expr_ty(lt));
      }
      ast::pat_range(begin, end) {
        check_expr_with(fcx, begin, expected);
        check_expr_with(fcx, end, expected);
        let b_ty = resolve_type_vars_if_possible(fcx,
                                                 fcx.expr_ty(begin));
        if !require_same_types(
            tcx, pat.span, b_ty,
            resolve_type_vars_if_possible(
                fcx, fcx.expr_ty(end)),
            {|| "mismatched types in range" }) {
            // no-op
        } else if !ty::type_is_numeric(b_ty) {
            tcx.sess.span_err(pat.span, "non-numeric type used in range");
        } else if !valid_range_bounds(fcx.ccx, begin, end) {
            tcx.sess.span_err(begin.span, "lower range bound must be less \
                                           than upper");
        }
        fcx.write_ty(pat.id, b_ty);
      }
      ast::pat_ident(name, sub) if !pat_is_variant(tcx.def_map, pat) {
        let vid = lookup_local(fcx, pat.span, pat.id);
        let mut typ = ty::mk_var(tcx, vid);
        demand::suptype(fcx, pat.span, expected, typ);
        let canon_id = pcx.map.get(ast_util::path_to_ident(name));
        if canon_id != pat.id {
            let tv_id = lookup_local(fcx, pat.span, canon_id);
            let ct = ty::mk_var(tcx, tv_id);
            demand::suptype(fcx, pat.span, ct, typ);
        }
        fcx.write_ty(pat.id, typ);
        alt sub {
          some(p) { check_pat(pcx, p, expected); }
          _ {}
        }
      }
      ast::pat_ident(path, c) {
        check_pat_variant(pcx, pat, path, some([]), expected);
      }
      ast::pat_enum(path, subpats) {
        check_pat_variant(pcx, pat, path, subpats, expected);
      }
      ast::pat_rec(fields, etc) {
        let ex_fields = alt structure_of(fcx, pat.span, expected) {
          ty::ty_rec(fields) { fields }
          _ {
            tcx.sess.span_fatal
                (pat.span,
                #fmt["mismatched types: expected `%s` but found record",
                     fcx.ty_to_str(expected)]);
          }
        };
        let f_count = vec::len(fields);
        let ex_f_count = vec::len(ex_fields);
        if ex_f_count < f_count || !etc && ex_f_count > f_count {
            tcx.sess.span_fatal
                (pat.span, #fmt["mismatched types: expected a record \
                      with %u fields, found one with %u \
                      fields",
                                ex_f_count, f_count]);
        }
        fn matches(name: str, f: ty::field) -> bool {
            ret str::eq(name, f.ident);
        }
        for fields.each {|f|
            alt vec::find(ex_fields, bind matches(f.ident, _)) {
              some(field) {
                check_pat(pcx, f.pat, field.mt.ty);
              }
              none {
                tcx.sess.span_fatal(pat.span,
                                    #fmt["mismatched types: did not \
                                          expect a record with a field `%s`",
                                         f.ident]);
              }
            }
        }
        fcx.write_ty(pat.id, expected);
      }
      ast::pat_tup(elts) {
        let ex_elts = alt structure_of(fcx, pat.span, expected) {
          ty::ty_tup(elts) { elts }
          _ {
            tcx.sess.span_fatal
                (pat.span,
                 #fmt["mismatched types: expected `%s`, found tuple",
                      fcx.ty_to_str(expected)]);
          }
        };
        let e_count = vec::len(elts);
        if e_count != vec::len(ex_elts) {
            tcx.sess.span_fatal
                (pat.span, #fmt["mismatched types: expected a tuple \
                      with %u fields, found one with %u \
                      fields", vec::len(ex_elts), e_count]);
        }
        let mut i = 0u;
        for elts.each {|elt|
            check_pat(pcx, elt, ex_elts[i]);
            i += 1u;
        }

        fcx.write_ty(pat.id, expected);
      }
      ast::pat_box(inner) {
        alt structure_of(fcx, pat.span, expected) {
          ty::ty_box(e_inner) {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ {
            tcx.sess.span_fatal(
                pat.span,
                "mismatched types: expected `" +
                fcx.ty_to_str(expected) +
                "` found box");
          }
        }
      }
      ast::pat_uniq(inner) {
        alt structure_of(fcx, pat.span, expected) {
          ty::ty_uniq(e_inner) {
            check_pat(pcx, inner, e_inner.ty);
            fcx.write_ty(pat.id, expected);
          }
          _ {
            tcx.sess.span_fatal(
                pat.span,
                "mismatched types: expected `" +
                fcx.ty_to_str(expected) +
                "` found uniq");
          }
        }
      }
    }
}

<|endoftext|>


<commit_before>use std::error::Error;

pub trait AsDynError {
    fn as_dyn_error(&self) -> &(dyn Error + 'static);
}

impl<T: Error + 'static> AsDynError for T {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + 'static {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + Send + 'static {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}

impl AsDynError for dyn Error + Send + Sync + 'static {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'static) {
        self
    }
}
<commit_msg>Support non-static AsDynError lifetimes<commit_after>use std::error::Error;

pub trait AsDynError<'a> {
    fn as_dyn_error(&self) -> &(dyn Error + 'a);
}

impl<'a, T: Error + 'a> AsDynError<'a> for T {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
        self
    }
}

impl<'a> AsDynError<'a> for dyn Error + 'a {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
        self
    }
}

impl<'a> AsDynError<'a> for dyn Error + Send + 'a {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
        self
    }
}

impl<'a> AsDynError<'a> for dyn Error + Send + Sync + 'a {
    #[inline]
    fn as_dyn_error(&self) -> &(dyn Error + 'a) {
        self
    }
}
<|endoftext|>


<commit_before>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;
extern crate rpassword;

use pwx::{Pwx,PwxIterator};
use std::io::{Write,stdout,stderr};
use std::process::exit;
use std::path::Path;
use docopt::Docopt;
use uuid::Uuid;

const USAGE: &'static str = "
Usage: pwx [options] <file> list
       pwx [options] <file> info
       pwx [options] <file> get <uuid> <name>
       pwx [options] <file> set <uuid <name> <val>
       pwx (--help | --version)

Options:
    -h, --help          Show this help message
    -v, --version       Show pwx version
    --pass-interactive  Read password from console
";

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

macro_rules! usage {
    ($code:expr, $err:expr) => {{
        let _ = writeln!(std::io::stderr(), "{}\n{}", $err, USAGE);
        return $code;
    }};
}

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_name: String,
    arg_val: String,
    arg_uuid: String,
    cmd_list: bool,
    cmd_set: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
    flag_pass_interactive: bool,
}

fn get_password_from_console() -> String {
    // Get password from terminal
    print!("Password: ");
    stdout().flush().unwrap();
    rpassword::read_password().unwrap()
}

/**
 * Get password
 * 1. If --pass-interactive read from console
 * 2. If PWX_PASSWORD is set use it
 * 3. Otherwise read from console
 *
 * This function may panic on encoding issues
 */
fn get_password(args: &Args) -> String {
    if args.flag_pass_interactive {
        return get_password_from_console();
    }

    let var = std::env::var("PWX_PASSWORD");
    if var.is_ok() {
        return var.unwrap()
    }

    get_password_from_console()
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    let mut p = match Pwx::open(Path::new(&args.arg_file), get_password(&args).as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {}", f);
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list {
        let mut fields = PwxIterator::from_start(&mut p).unwrap();
        fields.skip_record();

        let mut uuid = String::new();
        let mut title = String::new();
        let mut username = String::new();

        for (typ,val) in fields {
            match typ {
                0x01 => uuid = Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string(),
                0x03 => title = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0x04 => username = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0xff => {
                    println!("{} {}[{}]", uuid, title, username);
                    uuid = String::new();
                    title = String::new();
                    username = String::new();
                }
                _ => (),
            }
        }
    } else if args.cmd_info {

        let fields = PwxIterator::from_start(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string()),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    }

    return 0
}

// Rust set_exit_status cannot be used yet, the only way to
// set an exit code to exit using exit(code) so we wrap the
// main function like this
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<commit_msg>Better panic message for read_password()<commit_after>extern crate pwx;
extern crate docopt;
extern crate rustc_serialize;
extern crate uuid;
extern crate rpassword;

use pwx::{Pwx,PwxIterator};
use std::io::{Write,stdout,stderr};
use std::process::exit;
use std::path::Path;
use docopt::Docopt;
use uuid::Uuid;

const USAGE: &'static str = "
Usage: pwx [options] <file> list
       pwx [options] <file> info
       pwx [options] <file> get <uuid> <name>
       pwx [options] <file> set <uuid <name> <val>
       pwx (--help | --version)

Options:
    -h, --help          Show this help message
    -v, --version       Show pwx version
    --pass-interactive  Read password from console
";

// Get pkg version at compile time
const VERSION: &'static str = env!("CARGO_PKG_VERSION");

macro_rules! usage {
    ($code:expr, $err:expr) => {{
        let _ = writeln!(std::io::stderr(), "{}\n{}", $err, USAGE);
        return $code;
    }};
}

#[derive(RustcDecodable, Debug)]
struct Args {
    arg_file: String,
    arg_name: String,
    arg_val: String,
    arg_uuid: String,
    cmd_list: bool,
    cmd_set: bool,
    cmd_get: bool,
    cmd_info: bool,
    flag_version: bool,
    flag_pass_interactive: bool,
}

fn get_password_from_console() -> String {
    // Get password from terminal
    print!("Password: ");
    stdout().flush().unwrap();
    rpassword::read_password().ok().expect("Unable to read password from console")
}

/**
 * Get password
 * 1. If --pass-interactive read from console
 * 2. If PWX_PASSWORD is set use it
 * 3. Otherwise read from console
 *
 * This function may panic on encoding issues
 */
fn get_password(args: &Args) -> String {
    if args.flag_pass_interactive {
        return get_password_from_console();
    }

    let var = std::env::var("PWX_PASSWORD");
    if var.is_ok() {
        return var.unwrap()
    }

    get_password_from_console()
}

fn real_main() -> i32 {

    let args: Args = Docopt::new(USAGE)
                            .and_then(|d| d.decode())
                            .unwrap_or_else(|e| e.exit());

    if args.flag_version {
        println!("pwx {}", VERSION);
        return 0;
    }

    let mut p = match Pwx::open(Path::new(&args.arg_file), get_password(&args).as_bytes()) {
        Err(f) => {
            let _ = writeln!(stderr(), "Error: {}", f);
            exit(-1);
        },
        Ok(p) => p,
    };

    if !p.is_authentic() {
        return -1;
    }

    if args.cmd_list {
        let mut fields = PwxIterator::from_start(&mut p).unwrap();
        fields.skip_record();

        let mut uuid = String::new();
        let mut title = String::new();
        let mut username = String::new();

        for (typ,val) in fields {
            match typ {
                0x01 => uuid = Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string(),
                0x03 => title = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0x04 => username = String::from_utf8_lossy(val.as_ref()).into_owned(),
                0xff => {
                    println!("{} {}[{}]", uuid, title, username);
                    uuid = String::new();
                    title = String::new();
                    username = String::new();
                }
                _ => (),
            }
        }
    } else if args.cmd_info {

        let fields = PwxIterator::from_start(&mut p).unwrap();
        for (typ,val) in fields {
            match typ {
                0x01 => print!("{} ", Uuid::from_bytes(val.as_ref()).unwrap_or(Uuid::nil()).to_hyphenated_string()),
                0x07 => print!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x08 => println!("@{} ", String::from_utf8_lossy(val.as_ref())),
                0x09 => println!("{} ", String::from_utf8_lossy(val.as_ref())),
                0x0a => println!("\"{}\" ", String::from_utf8_lossy(val.as_ref())),
                0xff => break,
                _ => (),
            }
        }
    }

    return 0
}

// Rust set_exit_status cannot be used yet, the only way to
// set an exit code to exit using exit(code) so we wrap the
// main function like this
fn main() {
    let exit_code = real_main();
    exit(exit_code);
}

<|endoftext|>


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

use std::env;
use std::fs::create_dir_all;
use std::fs::{File, canonicalize, OpenOptions};
use std::io::{Write, BufRead, BufReader};
use std::path::Path;
use std::collections::HashMap;

use handlebars::Handlebars;
use hcore::package::PackageIdent;

use common::ui::{UI, Status};
use error::Result;

const DEFAULT_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/default_template_plan.sh"
));
const FULL_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/full_template_plan.sh"
));
const DEFAULT_TOML_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_default.toml"
));
const GITIGNORE_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_gitignore"
));

pub fn start(
    ui: &mut UI,
    origin: String,
    with_docs: bool,
    with_callbacks: bool,
    with_all: bool,
    scaffolding_ident: Option<PackageIdent>,
    maybe_name: Option<String>,
) -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            (
                "habitat".into(),
                canonicalize(".")
                    .ok()
                    .and_then(|path| {
                        path.components().last().and_then(|val| {
                            // Type gymnastics!
                            val.as_os_str().to_os_string().into_string().ok()
                        })
                    })
                    .unwrap_or("unnamed".into()),
            )
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);

    let scaffold = match scaffolding_ident {
        Some(ident) => Some(data.insert(
            "scaffolding_ident".to_string(),
            ident.to_string(),
        )),
        None => None,
    };

    if with_callbacks {
        data.insert("with_callbacks".to_string(), "true".to_string());
    }
    if with_docs {
        data.insert("with_docs".to_string(), "true".to_string());
    }
    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if with_all || scaffold.is_none() {
        let rendered_plan = handlebars.template_render(FULL_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    } else {
        let rendered_plan = handlebars.template_render(DEFAULT_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para(
        "The `plan.sh` is the foundation of your new habitat. You can \
        define core metadata, dependencies, and tasks.",
    )?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(
        ui,
        &format!("{}/default.toml", root),
        &rendered_default_toml,
    )?;
    ui.para(
        "The `default.toml` allows you to declare default values for `cfg` prefixed
        variables.",
    )?;

    let config_path = format!("{}/config/", root);
    match Path::new(&config_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", config_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", config_path),
            )?;
            create_dir_all(&config_path)?;
        }
    };
    ui.para(
        "The `config` directory is where you can set up configuration files for your app. \
        They are influenced by `default.toml`.",
    )?;

    let hooks_path = format!("{}/hooks/", root);
    match Path::new(&hooks_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", hooks_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", hooks_path),
            )?;
            create_dir_all(&hooks_path)?;
        }
    };
    ui.para(
        "The `hooks` directory is where you can create a number of automation hooks into \
        your habitat.",
    )?;

    ui.para(
        "For more information on any of the generated files: \
        https://www.habitat.sh/docs/reference/plan-syntax/#basic-settings \
        https://www.habitat.sh/docs/reference/plan-syntax/#runtime-configuration-settings \
        https://www.habitat.sh/docs/reference/plan-syntax/#hooks \
        https://www.habitat.sh/docs/reference/plan-syntax/#callbacks",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code has been initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true).append(true).open(target_path)?;

            let entries: Vec<String> = BufReader::new(&file)
                .lines()
                .map(|l| l.expect("Failed to parse line"))
                .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(
                Status::Using,
                format!(
                    "existing file: {} ({} lines appended)",
                    &target,
                    appended
                ),
            )?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {

    if path.join(".git").is_dir() {
        return true;
    }

    if let Some(parent) = path.parent() {
        return is_git_managed(&parent);
    }

    return false;
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    match path.exists() {
        false => {
            ui.status(Status::Creating, format!("file: {}", location))?;
            // If the directory doesn't exist we need to make it.
            if let Some(directory) = path.parent() {
                create_dir_all(directory)?;
            }
            // Create and then render the template with Handlebars
            File::create(path).and_then(
                |mut file| file.write(template.as_bytes()),
            )?;
        }
        true => {
            // If the user has already configured a file overwriting would be impolite.
            ui.status(
                Status::Using,
                format!("existing file: {}", location),
            )?;
        }
    };
    Ok(())
}
<commit_msg>Give just enough info at init time, delagate lengthy explanations to docs.<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::env;
use std::fs::create_dir_all;
use std::fs::{File, canonicalize, OpenOptions};
use std::io::{Write, BufRead, BufReader};
use std::path::Path;
use std::collections::HashMap;

use handlebars::Handlebars;
use hcore::package::PackageIdent;

use common::ui::{UI, Status};
use error::Result;

const DEFAULT_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/default_template_plan.sh"
));
const FULL_PLAN_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/full_template_plan.sh"
));
const DEFAULT_TOML_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_default.toml"
));
const GITIGNORE_TEMPLATE: &'static str = include_str!(concat!(
    env!("CARGO_MANIFEST_DIR"),
    "/static/template_gitignore"
));

pub fn start(
    ui: &mut UI,
    origin: String,
    with_docs: bool,
    with_callbacks: bool,
    with_all: bool,
    scaffolding_ident: Option<PackageIdent>,
    maybe_name: Option<String>,
) -> Result<()> {
    ui.begin("Constructing a cozy habitat for your app...")?;
    ui.br()?;

    let (root, name) = match maybe_name {
        Some(name) => (name.clone(), name.clone()),
        // The name of the current working directory.
        None => {
            (
                "habitat".into(),
                canonicalize(".")
                    .ok()
                    .and_then(|path| {
                        path.components().last().and_then(|val| {
                            // Type gymnastics!
                            val.as_os_str().to_os_string().into_string().ok()
                        })
                    })
                    .unwrap_or("unnamed".into()),
            )
        }
    };

    // Build out the variables passed.
    let handlebars = Handlebars::new();
    let mut data = HashMap::new();
    data.insert("pkg_name".to_string(), name);
    data.insert("pkg_origin".to_string(), origin);

    let scaffold = match scaffolding_ident {
        Some(ident) => Some(data.insert(
            "scaffolding_ident".to_string(),
            ident.to_string(),
        )),
        None => None,
    };

    if with_callbacks {
        data.insert("with_callbacks".to_string(), "true".to_string());
    }
    if with_docs {
        data.insert("with_docs".to_string(), "true".to_string());
    }
    // Add all environment variables that start with "pkg_" as variables in
    // the template.
    for (key, value) in env::vars() {
        if key.starts_with("pkg_") {
            data.insert(key, value);
        }
    }

    // We want to render the configured variables.
    if with_all || scaffold.is_none() {
        let rendered_plan = handlebars.template_render(FULL_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    } else {
        let rendered_plan = handlebars.template_render(DEFAULT_PLAN_TEMPLATE, &data)?;
        create_with_template(ui, &format!("{}/plan.sh", root), &rendered_plan)?;
    }
    ui.para(
        "`plan.sh` is the foundation of your new habitat. It contains \
        metadata, dependencies, and tasks.",
    )?;
    let rendered_default_toml = handlebars.template_render(DEFAULT_TOML_TEMPLATE, &data)?;
    create_with_template(
        ui,
        &format!("{}/default.toml", root),
        &rendered_default_toml,
    )?;
    ui.para(
        "`default.toml` contains default values for `cfg` prefixed variables.",
    )?;

    let config_path = format!("{}/config/", root);
    match Path::new(&config_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", config_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", config_path),
            )?;
            create_dir_all(&config_path)?;
        }
    };
    ui.para(
        "`/config/` contains configuration files for your app.",
    )?;

    let hooks_path = format!("{}/hooks/", root);
    match Path::new(&hooks_path).exists() {
        true => {
            ui.status(
                Status::Using,
                format!("existing directory: {}", hooks_path),
            )?
        }
        false => {
            ui.status(
                Status::Creating,
                format!("directory: {}", hooks_path),
            )?;
            create_dir_all(&hooks_path)?;
        }
    };
    ui.para(
        "`/hooks/` contains automation hooks into your habitat.",
    )?;

    ui.para(
        "For more information on any of the files: \
        https://www.habitat.sh/docs/reference/plan-syntax/",
    )?;

    render_ignorefile(ui, &root)?;

    ui.end("An abode for your code is initialized!")?;
    Ok(())
}

fn render_ignorefile(ui: &mut UI, root: &str) -> Result<()> {
    let parent = format!("{}/..", root);
    let expanded = canonicalize(&parent)?;
    let current_path = Path::new(&expanded);

    if is_git_managed(&current_path) {
        let target = format!("{}/.gitignore", parent);
        let target_path = Path::new(&target);

        if !target_path.exists() {
            create_with_template(ui, &target, GITIGNORE_TEMPLATE)?
        } else {
            let file = OpenOptions::new().read(true).append(true).open(target_path)?;

            let entries: Vec<String> = BufReader::new(&file)
                .lines()
                .map(|l| l.expect("Failed to parse line"))
                .collect();

            let mut appended = 0;

            for line in GITIGNORE_TEMPLATE.lines() {
                let s = line.to_string();

                if !entries.contains(&s) {
                    writeln!(&file, "{}", s)?;
                    appended += 1;
                }
            }

            ui.status(
                Status::Using,
                format!(
                    "existing file: {} ({} lines appended)",
                    &target,
                    appended
                ),
            )?;
        }
    }
    Ok(())
}

fn is_git_managed(path: &Path) -> bool {

    if path.join(".git").is_dir() {
        return true;
    }

    if let Some(parent) = path.parent() {
        return is_git_managed(&parent);
    }

    return false;
}

fn create_with_template(ui: &mut UI, location: &str, template: &str) -> Result<()> {
    let path = Path::new(&location);
    match path.exists() {
        false => {
            ui.status(Status::Creating, format!("file: {}", location))?;
            // If the directory doesn't exist we need to make it.
            if let Some(directory) = path.parent() {
                create_dir_all(directory)?;
            }
            // Create and then render the template with Handlebars
            File::create(path).and_then(
                |mut file| file.write(template.as_bytes()),
            )?;
        }
        true => {
            // If the user has already configured a file overwriting would be impolite.
            ui.status(
                Status::Using,
                format!("existing file: {}", location),
            )?;
        }
    };
    Ok(())
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt;
use std::cmp::Ordering;
use super::{ST, OrderedST};

pub struct Node<K, V> {
    key: K,
    val: V,
    left:  Option<Box<Node<K, V>>>,
    right: Option<Box<Node<K, V>>>
}

impl<K, V> Node<K, V> {
    pub fn new(key: K, val: V) -> Node<K, V> {
        Node {
            key: key,
            val: val,
            left: None,
            right: None
        }
    }
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter) {
        if depth == 0 {
            writeln!(f, "{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}+--{:?}[{:?}]", iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f);
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f);
        }
    }
}

fn put<K: Ord, V>(x: Option<Box<Node<K,V>>>, key: K, val: V) -> Option<Box<Node<K,V>>> {
    let mut x = x;
    if x.is_none() {
        return Some(Box::new(Node::new(key, val)));
    }
    let cmp = key.cmp(&x.as_ref().unwrap().key);
    match cmp {
        Ordering::Less => {
            let left = x.as_mut().unwrap().left.take();
            x.as_mut().unwrap().left = put(left, key, val)
        },
        Ordering::Greater => {
            let right = x.as_mut().unwrap().right.take();
            x.as_mut().unwrap().right = put(right, key, val)
        },
        Ordering::Equal => {
            x.as_mut().unwrap().val = val
        }
    }
    x
}

pub struct BST<K, V> {
    root: Option<Box<Node<K, V>>>
}

impl<K: Ord, V> ST<K, V> for BST<K, V> {
    fn new() -> BST<K, V> {
        BST { root: None }
    }

    fn get(&self, key: &K) -> Option<&V> {
        let mut x = self.root.as_ref();
        while x.is_some() {
            match key.cmp(&x.unwrap().key) {
                Ordering::Less => {
                    x = x.unwrap().left.as_ref();
                },
                Ordering::Greater => {
                    x = x.unwrap().right.as_ref();
                },
                Ordering::Equal  => {
                    return Some(&x.unwrap().val)
                }
            }
        }
        None
    }

    fn put(&mut self, key: K, val: V) {
        let root = self.root.take();
        self.root = put(root, key, val);
    }

    fn delete(&mut self, key: &K) {
        unimplemented!()
    }

    fn is_empty(&self) -> bool {
        self.root.is_none()
    }
    /// number of key-value pairs in the table
    fn size(&self) -> usize {
        unimplemented!()
    }
}

fn floor<'a, K: Ord, V>(x: Option<&'a Box<Node<K,V>>>, key: &K) -> Option<&'a Node<K,V>> {
    if x.is_none() {
        return None;
    }

    match key.cmp(&x.unwrap().key) {
        Ordering::Equal => {
            return Some(&(**x.unwrap()));
        },
        Ordering::Less => {
            return floor(x.unwrap().left.as_ref(), key);
        },
        _ => (),
    }

    let t = floor(x.unwrap().right.as_ref(), key);
    if t.is_some() {
        return t
    } else {
        return Some(x.unwrap())
    }
}

impl<K: Ord, V> OrderedST<K, V> for BST<K, V> {
    /// smallest key
    fn min(&self) -> Option<&K> {
        unimplemented!()
    }

    /// largest key
    fn max(&self) -> Option<&K> {
        unimplemented!()
    }

    /// largest key less than or equal to key
    fn floor(&self, key: &K) -> Option<&K> {
        let x = floor(self.root.as_ref(), key);
        if x.is_none() {
            None
        } else {
            Some(&x.unwrap().key)
        }
    }

    /// smallest key greater than or equal to key
    fn ceiling(&self, key: &K) -> Option<&K> {
        unimplemented!()
    }

    /// number of keys less than key
    fn rank(&self, key: &K) -> usize {
        unimplemented!()
    }

    /// key of rank k
    fn select(&self, k: usize) -> Option<&K> {
        unimplemented!()
    }

    /// delete smallest key
    fn delete_min(&mut self) {
        unimplemented!()
    }

    /// delete largest key
    fn delete_max(&mut self) {
        unimplemented!()
    }
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for BST<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f);
            Ok(())
        }
    }
}

#[test]
fn test_binary_search_tree() {
    let mut t = BST::<char, usize>::new();
    for (i, c) in "SEARCHEXAMP".chars().enumerate() {
        t.put(c, i);
    }

    //println!("{:?}", t);
    assert_eq!(t.get(&'E'),  Some(&6));
    assert_eq!(t.floor(&'O'), Some(&'M'));
}
<commit_msg>symbol_tables/binary_search_tree: implement BST::rank()<commit_after>use std::iter;
use std::fmt;
use std::cmp::Ordering;
use super::{ST, OrderedST};

pub struct Node<K, V> {
    key: K,
    val: V,
    left:  Option<Box<Node<K, V>>>,
    right: Option<Box<Node<K, V>>>
}

impl<K, V> Node<K, V> {
    pub fn new(key: K, val: V) -> Node<K, V> {
        Node {
            key: key,
            val: val,
            left: None,
            right: None
        }
    }

    fn size(&self) -> usize {
        let mut ret = 1;
        if self.left.is_some() {
            ret += self.left.as_ref().unwrap().size()
        }
        if self.right.is_some() {
            ret += self.right.as_ref().unwrap().size()
        }
        ret
    }
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter) {
        if depth == 0 {
            writeln!(f, "{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}+--{:?}[{:?}]", iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f);
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f);
        }
    }
}

fn put<K: Ord, V>(x: Option<Box<Node<K,V>>>, key: K, val: V) -> Option<Box<Node<K,V>>> {
    let mut x = x;
    if x.is_none() {
        return Some(Box::new(Node::new(key, val)));
    }
    let cmp = key.cmp(&x.as_ref().unwrap().key);
    match cmp {
        Ordering::Less => {
            let left = x.as_mut().unwrap().left.take();
            x.as_mut().unwrap().left = put(left, key, val)
        },
        Ordering::Greater => {
            let right = x.as_mut().unwrap().right.take();
            x.as_mut().unwrap().right = put(right, key, val)
        },
        Ordering::Equal => {
            x.as_mut().unwrap().val = val
        }
    }
    x
}

pub struct BST<K, V> {
    root: Option<Box<Node<K, V>>>
}

impl<K: Ord, V> ST<K, V> for BST<K, V> {
    fn new() -> BST<K, V> {
        BST { root: None }
    }

    fn get(&self, key: &K) -> Option<&V> {
        let mut x = self.root.as_ref();
        while x.is_some() {
            match key.cmp(&x.unwrap().key) {
                Ordering::Less => {
                    x = x.unwrap().left.as_ref();
                },
                Ordering::Greater => {
                    x = x.unwrap().right.as_ref();
                },
                Ordering::Equal  => {
                    return Some(&x.unwrap().val)
                }
            }
        }
        None
    }

    fn put(&mut self, key: K, val: V) {
        let root = self.root.take();
        self.root = put(root, key, val);
    }

    fn delete(&mut self, key: &K) {
        unimplemented!()
    }

    fn is_empty(&self) -> bool {
        self.root.is_none()
    }

    /// number of key-value pairs in the table
    fn size(&self) -> usize {
        if self.is_empty() {
            0
        } else {
            self.root.as_ref().unwrap().size()
        }
    }
}

fn floor<'a, K: Ord, V>(x: Option<&'a Box<Node<K,V>>>, key: &K) -> Option<&'a Node<K,V>> {
    if x.is_none() {
        return None;
    }

    match key.cmp(&x.unwrap().key) {
        Ordering::Equal => {
            return Some(&(**x.unwrap()));
        },
        Ordering::Less => {
            return floor(x.unwrap().left.as_ref(), key);
        },
        _ => (),
    }

    let t = floor(x.unwrap().right.as_ref(), key);
    if t.is_some() {
        return t
    } else {
        return Some(x.unwrap())
    }
}

impl<K: Ord, V> OrderedST<K, V> for BST<K, V> {
    /// smallest key
    fn min(&self) -> Option<&K> {
        unimplemented!()
    }

    /// largest key
    fn max(&self) -> Option<&K> {
        unimplemented!()
    }

    /// largest key less than or equal to key
    fn floor(&self, key: &K) -> Option<&K> {
        let x = floor(self.root.as_ref(), key);
        if x.is_none() {
            None
        } else {
            Some(&x.unwrap().key)
        }
    }

    /// smallest key greater than or equal to key
    fn ceiling(&self, key: &K) -> Option<&K> {
        unimplemented!()
    }

    /// number of keys less than key
    fn rank(&self, key: &K) -> usize {
        fn rank_helper<'a, K: Ord, V>(x: Option<&'a Box<Node<K,V>>>, key: &K) -> usize {
            if x.is_none() {
                return 0;
            }

            match key.cmp(&x.unwrap().key) {
                Ordering::Less => {
                    rank_helper(x.unwrap().left.as_ref(), key)
                },
                Ordering::Greater => {
                    1 + x.as_ref().unwrap().left.as_ref().map(|ref n| n.size()).unwrap_or(0) +
                        rank_helper(x.unwrap().right.as_ref(), key)
                }
                Ordering::Equal => {
                    x.as_ref().unwrap().left.as_ref().map(|ref n| n.size()).unwrap_or(0)
                }
            }
        }

        rank_helper(self.root.as_ref(), key)
    }

    /// key of rank k
    fn select(&self, k: usize) -> Option<&K> {
        unimplemented!()
    }

    /// delete smallest key
    fn delete_min(&mut self) {
        unimplemented!()
    }

    /// delete largest key
    fn delete_max(&mut self) {
        unimplemented!()
    }
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for BST<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f);
            Ok(())
        }
    }
}

#[test]
fn test_binary_search_tree() {
    let mut t = BST::<char, usize>::new();
    for (i, c) in "SEARCHEXAMP".chars().enumerate() {
        t.put(c, i);
    }

    println!("{:?}", t);
    assert_eq!(t.get(&'E'),  Some(&6));
    assert_eq!(t.floor(&'O'), Some(&'M'));
    assert_eq!(t.size(), 9);
    assert_eq!(t.rank(&'E'), 2);
    assert_eq!(t.rank(&'M'), 4);
}
<|endoftext|>