<commit_before>use core::cell::Cell;
use core::mem;
use core::intrinsics;
use common::take_cell::TakeCell;
use pm;
use nvic;

use helpers::*;
use process::AppSlice;

/// Memory registers for a DMA channel. Section 16.6.1 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct DMARegisters {
    memory_address:           usize,
    peripheral_select:        usize,
    transfer_counter:         usize,
    memory_address_reload:    usize,
    transfer_counter_reload:  usize,
    control:                  usize,
    mode:                     usize,
    status:                   usize,
    interrupt_enable:         usize,
    interrupt_disable:        usize,
    interrupt_mask:           usize,
    interrupt_status:         usize,
    version:                  usize,
    _unused:                  [usize; 3]
}

/// The PDCA's base addresses in memory (Section 7.1 of manual)
pub const DMA_BASE_ADDR : usize = 0x400A2000;

/// The number of bytes between each memory mapped DMA Channel (Section 16.6.1)
pub const DMA_CHANNEL_SIZE : usize = 0x40;

/// Shared counter that Keeps track of how many DMA channels are currently
/// active.
static mut NUM_ENABLED: usize = 0;

/// The DMA channel number. Each channel transfers data between memory and a
/// particular peripheral function (e.g., SPI read or SPI write, but not both
/// simultaneously). There are 16 available channels (Section 16.7)
#[derive(Copy,Clone)]
pub enum DMAChannelNum {
    // Relies on the fact that assigns values 0-15 to each constructor in order
    DMAChannel00 = 0,
    DMAChannel01 = 1,
    DMAChannel02 = 2,
    DMAChannel03 = 3,
    DMAChannel04 = 4,
    DMAChannel05 = 5,
    DMAChannel06 = 6,
    DMAChannel07 = 7,
    DMAChannel08 = 8,
    DMAChannel09 = 9,
    DMAChannel10 = 10,
    DMAChannel11 = 11,
    DMAChannel12 = 12,
    DMAChannel13 = 13,
    DMAChannel14 = 14,
    DMAChannel15 = 15
}

/// The peripheral function a channel is assigned to (Section 16.7)
/// *_RX means transfer data from peripheral to memory, *_TX means transfer data
/// from memory to peripheral.
#[allow(non_camel_case_types)]
pub enum DMAPeripheral {
    USART0_RX      = 0,
    USART1_RX      = 1,
    USART2_RX      = 2,
    USART3_RX      = 3,
    SPI_RX         = 4,
    TWIM0_RX       = 5,
    TWIM1_RX       = 6,
    TWIM2_RX       = 7,
    TWIM3_RX       = 8,
    TWIS0_RX       = 9,
    TWIS1_RX       = 10,
    ADCIFE_RX      = 11,
    CATB_RX        = 12,
    IISC_CH0_RX    = 14,
    IISC_CH1_RX    = 15,
    PARC_RX        = 16,
    AESA_RX        = 17,
    USART0_TX      = 18,
    USART1_TX      = 19,
    USART2_TX      = 20,
    USART3_TX      = 21,
    SPI_TX         = 22,
    TWIM0_TX       = 23,
    TWIM1_TX       = 24,
    TWIM2_TX       = 25,
    TWIM3_TX       = 26,
    TWIS0_TX       = 27,
    TWIS1_TX       = 28,
    ADCIFE_TX      = 29,
    CATB_TX        = 30,
    ABDACB_SDR0_TX = 31,
    ABDACB_SDR1_TX = 32,
    IISC_CH0_TX    = 33,
    IISC_CH1_TX    = 34,
    DACC_TX        = 35,
    AESA_TX        = 36,
    LCDCA_ACMDR_TX = 37,
    LCDCA_ABMDR_TX = 38
}

pub static mut DMAChannels : [DMAChannel; 16] = [
    DMAChannel::new(DMAChannelNum::DMAChannel00, nvic::NvicIdx::PDCA0),
    DMAChannel::new(DMAChannelNum::DMAChannel01, nvic::NvicIdx::PDCA1),
    DMAChannel::new(DMAChannelNum::DMAChannel02, nvic::NvicIdx::PDCA2),
    DMAChannel::new(DMAChannelNum::DMAChannel03, nvic::NvicIdx::PDCA3),
    DMAChannel::new(DMAChannelNum::DMAChannel04, nvic::NvicIdx::PDCA4),
    DMAChannel::new(DMAChannelNum::DMAChannel05, nvic::NvicIdx::PDCA5),
    DMAChannel::new(DMAChannelNum::DMAChannel06, nvic::NvicIdx::PDCA6),
    DMAChannel::new(DMAChannelNum::DMAChannel07, nvic::NvicIdx::PDCA7),
    DMAChannel::new(DMAChannelNum::DMAChannel08, nvic::NvicIdx::PDCA8),
    DMAChannel::new(DMAChannelNum::DMAChannel09, nvic::NvicIdx::PDCA9),
    DMAChannel::new(DMAChannelNum::DMAChannel10, nvic::NvicIdx::PDCA10),
    DMAChannel::new(DMAChannelNum::DMAChannel11, nvic::NvicIdx::PDCA11),
    DMAChannel::new(DMAChannelNum::DMAChannel12, nvic::NvicIdx::PDCA12),
    DMAChannel::new(DMAChannelNum::DMAChannel13, nvic::NvicIdx::PDCA13),
    DMAChannel::new(DMAChannelNum::DMAChannel14, nvic::NvicIdx::PDCA14),
    DMAChannel::new(DMAChannelNum::DMAChannel15, nvic::NvicIdx::PDCA15),
];

pub struct DMAChannel {
    registers: *mut DMARegisters,
    nvic: nvic::NvicIdx,
    pub client: Option<&'static mut DMAClient>,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>
}

pub trait DMAClient {
    fn xfer_done(&mut self, pid: usize, buffer: &'static mut [u8]);
}

impl DMAChannel {
    const fn new(channel: DMAChannelNum, nvic: nvic::NvicIdx) -> DMAChannel {
        DMAChannel {
            registers: (DMA_BASE_ADDR + (channel as usize) * DMA_CHANNEL_SIZE)
                    as *mut DMARegisters,
            nvic: nvic,
            client: None,
            enabled: Cell::new(false),
            buffer: TakeCell::empty()
        }
    }

    pub fn enable(&self) {
        unsafe {
            pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
            pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
        }
        if !self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xadd(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.interrupt_disable, 0xffffffff);
            volatile_store(&mut registers.control, 0x1);

            unsafe { nvic::enable(self.nvic) };

            self.enabled.set(true);
        }
    }

    pub fn disable(&self) {
        if self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xsub(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::disable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::disable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.control, 0x2);
            self.enabled.set(false);
            unsafe {
                nvic::disable(self.nvic);
            }
        }
    }

    pub fn handle_interrupt(&mut self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        let channel : usize = volatile_load(&registers.peripheral_select);

        // Here we take the buffer reference out of the option and
        // return it to the caller
        let buffer = self.buffer.take();
        self.client.as_mut().map(|client| {
            // If buffer is `None` we neglected to `replace` it in `do_xfer`
            // which should never happen...
            buffer.map(|buf| {
                client.xfer_done(channel, buf);
            });
        });
    }

    pub fn do_xfer_old<S>(&self, pid: usize, mut slice: AppSlice<S, u8>) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };

        volatile_store(&mut registers.peripheral_select, pid);
        volatile_store(&mut registers.memory_address_reload,
                       &slice.as_ref()[0] as *const u8 as usize);
        volatile_store(&mut registers.transfer_counter_reload, slice.len());

        volatile_store(&mut registers.interrupt_enable, 1 << 1);

        // TODO(alevy): This is, like, pretty stupid, but we're gonna get rid of
        // this whole method anyway
        self.buffer.replace(unsafe { mem::transmute(slice.as_mut()) });
    }

    pub fn do_xfer(&self, pid: usize,
                       buf: &'static mut [u8],
                       len: usize) {
        if len > buf.len() {
            return;
        }

        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };

        volatile_store(&mut registers.peripheral_select, pid);
        volatile_store(&mut registers.memory_address_reload,
                       &buf[0] as *const u8 as usize);
        volatile_store(&mut registers.transfer_counter_reload, len);

        volatile_store(&mut registers.interrupt_enable, 1 << 1);

        // Store the buffer reference in the TakeCell so it can be returned to
        // the caller in `handle_interrupt`
        self.buffer.replace(buf);
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_0_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[0].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA0);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA0);
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_1_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[1].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA1);
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_2_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[2].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA2);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA2);
}

<commit_msg>sam4l: Remove old method from dma<commit_after>use core::cell::Cell;
use core::mem;
use core::intrinsics;
use common::take_cell::TakeCell;
use pm;
use nvic;

use helpers::*;

/// Memory registers for a DMA channel. Section 16.6.1 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct DMARegisters {
    memory_address:           usize,
    peripheral_select:        usize,
    transfer_counter:         usize,
    memory_address_reload:    usize,
    transfer_counter_reload:  usize,
    control:                  usize,
    mode:                     usize,
    status:                   usize,
    interrupt_enable:         usize,
    interrupt_disable:        usize,
    interrupt_mask:           usize,
    interrupt_status:         usize,
    version:                  usize,
    _unused:                  [usize; 3]
}

/// The PDCA's base addresses in memory (Section 7.1 of manual)
pub const DMA_BASE_ADDR : usize = 0x400A2000;

/// The number of bytes between each memory mapped DMA Channel (Section 16.6.1)
pub const DMA_CHANNEL_SIZE : usize = 0x40;

/// Shared counter that Keeps track of how many DMA channels are currently
/// active.
static mut NUM_ENABLED: usize = 0;

/// The DMA channel number. Each channel transfers data between memory and a
/// particular peripheral function (e.g., SPI read or SPI write, but not both
/// simultaneously). There are 16 available channels (Section 16.7)
#[derive(Copy,Clone)]
pub enum DMAChannelNum {
    // Relies on the fact that assigns values 0-15 to each constructor in order
    DMAChannel00 = 0,
    DMAChannel01 = 1,
    DMAChannel02 = 2,
    DMAChannel03 = 3,
    DMAChannel04 = 4,
    DMAChannel05 = 5,
    DMAChannel06 = 6,
    DMAChannel07 = 7,
    DMAChannel08 = 8,
    DMAChannel09 = 9,
    DMAChannel10 = 10,
    DMAChannel11 = 11,
    DMAChannel12 = 12,
    DMAChannel13 = 13,
    DMAChannel14 = 14,
    DMAChannel15 = 15
}

/// The peripheral function a channel is assigned to (Section 16.7)
/// *_RX means transfer data from peripheral to memory, *_TX means transfer data
/// from memory to peripheral.
#[allow(non_camel_case_types)]
pub enum DMAPeripheral {
    USART0_RX      = 0,
    USART1_RX      = 1,
    USART2_RX      = 2,
    USART3_RX      = 3,
    SPI_RX         = 4,
    TWIM0_RX       = 5,
    TWIM1_RX       = 6,
    TWIM2_RX       = 7,
    TWIM3_RX       = 8,
    TWIS0_RX       = 9,
    TWIS1_RX       = 10,
    ADCIFE_RX      = 11,
    CATB_RX        = 12,
    IISC_CH0_RX    = 14,
    IISC_CH1_RX    = 15,
    PARC_RX        = 16,
    AESA_RX        = 17,
    USART0_TX      = 18,
    USART1_TX      = 19,
    USART2_TX      = 20,
    USART3_TX      = 21,
    SPI_TX         = 22,
    TWIM0_TX       = 23,
    TWIM1_TX       = 24,
    TWIM2_TX       = 25,
    TWIM3_TX       = 26,
    TWIS0_TX       = 27,
    TWIS1_TX       = 28,
    ADCIFE_TX      = 29,
    CATB_TX        = 30,
    ABDACB_SDR0_TX = 31,
    ABDACB_SDR1_TX = 32,
    IISC_CH0_TX    = 33,
    IISC_CH1_TX    = 34,
    DACC_TX        = 35,
    AESA_TX        = 36,
    LCDCA_ACMDR_TX = 37,
    LCDCA_ABMDR_TX = 38
}

pub static mut DMAChannels : [DMAChannel; 16] = [
    DMAChannel::new(DMAChannelNum::DMAChannel00, nvic::NvicIdx::PDCA0),
    DMAChannel::new(DMAChannelNum::DMAChannel01, nvic::NvicIdx::PDCA1),
    DMAChannel::new(DMAChannelNum::DMAChannel02, nvic::NvicIdx::PDCA2),
    DMAChannel::new(DMAChannelNum::DMAChannel03, nvic::NvicIdx::PDCA3),
    DMAChannel::new(DMAChannelNum::DMAChannel04, nvic::NvicIdx::PDCA4),
    DMAChannel::new(DMAChannelNum::DMAChannel05, nvic::NvicIdx::PDCA5),
    DMAChannel::new(DMAChannelNum::DMAChannel06, nvic::NvicIdx::PDCA6),
    DMAChannel::new(DMAChannelNum::DMAChannel07, nvic::NvicIdx::PDCA7),
    DMAChannel::new(DMAChannelNum::DMAChannel08, nvic::NvicIdx::PDCA8),
    DMAChannel::new(DMAChannelNum::DMAChannel09, nvic::NvicIdx::PDCA9),
    DMAChannel::new(DMAChannelNum::DMAChannel10, nvic::NvicIdx::PDCA10),
    DMAChannel::new(DMAChannelNum::DMAChannel11, nvic::NvicIdx::PDCA11),
    DMAChannel::new(DMAChannelNum::DMAChannel12, nvic::NvicIdx::PDCA12),
    DMAChannel::new(DMAChannelNum::DMAChannel13, nvic::NvicIdx::PDCA13),
    DMAChannel::new(DMAChannelNum::DMAChannel14, nvic::NvicIdx::PDCA14),
    DMAChannel::new(DMAChannelNum::DMAChannel15, nvic::NvicIdx::PDCA15),
];

pub struct DMAChannel {
    registers: *mut DMARegisters,
    nvic: nvic::NvicIdx,
    pub client: Option<&'static mut DMAClient>,
    enabled: Cell<bool>,
    buffer: TakeCell<&'static mut [u8]>
}

pub trait DMAClient {
    fn xfer_done(&mut self, pid: usize, buffer: &'static mut [u8]);
}

impl DMAChannel {
    const fn new(channel: DMAChannelNum, nvic: nvic::NvicIdx) -> DMAChannel {
        DMAChannel {
            registers: (DMA_BASE_ADDR + (channel as usize) * DMA_CHANNEL_SIZE)
                    as *mut DMARegisters,
            nvic: nvic,
            client: None,
            enabled: Cell::new(false),
            buffer: TakeCell::empty()
        }
    }

    pub fn enable(&self) {
        unsafe {
            pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
            pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
        }
        if !self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xadd(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::enable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::enable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.interrupt_disable, 0xffffffff);
            volatile_store(&mut registers.control, 0x1);

            unsafe { nvic::enable(self.nvic) };

            self.enabled.set(true);
        }
    }

    pub fn disable(&self) {
        if self.enabled.get() {
            unsafe {
                let num_enabled = intrinsics::atomic_xsub(&mut NUM_ENABLED, 1);
                if num_enabled == 1 {
                    pm::disable_clock(pm::Clock::HSB(pm::HSBClock::PDCA));
                    pm::disable_clock(pm::Clock::PBB(pm::PBBClock::PDCA));
                }
            }
            let registers : &mut DMARegisters = unsafe {
                mem::transmute(self.registers)
            };
            volatile_store(&mut registers.control, 0x2);
            self.enabled.set(false);
            unsafe {
                nvic::disable(self.nvic);
            }
        }
    }

    pub fn handle_interrupt(&mut self) {
        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };
        let channel : usize = volatile_load(&registers.peripheral_select);

        // Here we take the buffer reference out of the option and
        // return it to the caller
        let buffer = self.buffer.take();
        self.client.as_mut().map(|client| {
            // If buffer is `None` we neglected to `replace` it in `do_xfer`
            // which should never happen...
            buffer.map(|buf| {
                client.xfer_done(channel, buf);
            });
        });
    }

    pub fn do_xfer(&self, pid: usize,
                       buf: &'static mut [u8],
                       len: usize) {
        if len > buf.len() {
            return;
        }

        let registers : &mut DMARegisters = unsafe {
            mem::transmute(self.registers)
        };

        volatile_store(&mut registers.peripheral_select, pid);
        volatile_store(&mut registers.memory_address_reload,
                       &buf[0] as *const u8 as usize);
        volatile_store(&mut registers.transfer_counter_reload, len);

        volatile_store(&mut registers.interrupt_enable, 1 << 1);

        // Store the buffer reference in the TakeCell so it can be returned to
        // the caller in `handle_interrupt`
        self.buffer.replace(buf);
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_0_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[0].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA0);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA0);
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_1_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[1].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA1);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA1);
}

#[no_mangle]
#[allow(non_snake_case)]
pub unsafe extern fn PDCA_2_Handler() {
    use common::Queue;
    use nvic;
    use chip;

    let registers : &mut DMARegisters =
        mem::transmute(DMAChannels[2].registers);
    volatile_store(&mut registers.interrupt_disable, 0xffffffff);
    nvic::disable(nvic::NvicIdx::PDCA2);
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(nvic::NvicIdx::PDCA2);
}

<|endoftext|>


<commit_before>extern crate cbindgen;

fn main() {
    let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
    let config = {
        let mut c: cbindgen::Config = Default::default();
        c.header = Some(concat!(
  "// THIS FILE IS AUTOGENERATED BY mp4parse-rust/build.rs - DO NOT EDIT\n\n",
  "// This Source Code Form is subject to the terms of the Mozilla Public\n",
  "// License, v. 2.0. If a copy of the MPL was not distributed with this\n",
  "// file, You can obtain one at https://mozilla.org/MPL/2.0/.",
        ).to_owned());
        c
    };

    println!("cargo:rerun-if-changed=src/lib.rs");
    // Generate mp4parse.h.
    cbindgen::generate_with_config(&crate_dir, config)
        .expect("Could not generate header")
        .write_to_file("include/mp4parse.h");
}
<commit_msg>Generate C bindings, not C++.<commit_after>extern crate cbindgen;

fn main() {
    let crate_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();

    println!("cargo:rerun-if-changed=src/lib.rs");

    let config = {
        let mut c: cbindgen::Config = Default::default();
        c.header = Some(concat!(
  "// THIS FILE IS AUTOGENERATED BY mp4parse_capi/build.rs - DO NOT EDIT\n\n",
  "// This Source Code Form is subject to the terms of the Mozilla Public\n",
  "// License, v. 2.0. If a copy of the MPL was not distributed with this\n",
  "// file, You can obtain one at https://mozilla.org/MPL/2.0/.",
        ).into());
        c.language = cbindgen::Language::C;
        c
    };

    // Generate mp4parse.h.
    cbindgen::generate_with_config(&crate_dir, config)
        .expect("Could not generate header")
        .write_to_file("include/mp4parse.h");
}
<|endoftext|>


<commit_before>// Copyright 2018 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! Common protocol bits.

#![allow(dead_code)] // various things are unused with --no-default-features
#![allow(missing_docs)]

use std::collections::HashMap;
use std::str::FromStr;

use eui48::MacAddress;
use reqwest::{Method, Url};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{DeserializeOwned, Error as DeserError};
use serde_json;

use super::super::{Error, ErrorKind, Result};
use super::super::auth::AuthMethod;
use super::super::session::{RequestBuilderExt, ServiceType};
use super::super::utils;
use super::ApiVersion;

#[derive(Clone, Debug, Deserialize)]
pub struct Link {
    #[serde(deserialize_with = "deser_url")]
    pub href: Url,
    pub rel: String
}

#[derive(Clone, Debug, Deserialize)]
pub struct Ref {
    pub id: String,
    pub links: Vec<Link>
}

#[derive(Clone, Debug, Deserialize)]
pub struct IdAndName {
    pub id: String,
    pub name: String
}

#[derive(Clone, Debug, Deserialize)]
pub struct KeyValue {
    pub key: String,
    pub value: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Version {
    #[serde(deserialize_with = "deser_version")]
    pub id: ApiVersion,
    pub links: Vec<Link>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub status: Option<String>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub version: Option<ApiVersion>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub min_version: Option<ApiVersion>
}

#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Root {
    MultipleVersions { versions: Vec<Version> },
    OneVersion { version: Version },
}

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Major API version.
    pub major_version: ApiVersion,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

impl Version {
    pub fn is_stable(&self) -> bool {
        if let Some(ref status) = self.status {
            let upper = status.to_uppercase();
            upper == "STABLE" || upper == "CURRENT"
        } else {
            true
        }
    }

    pub fn into_service_info(self) -> Result<ServiceInfo> {
        let endpoint = match self.links.into_iter().find(|x| &x.rel == "self") {
            Some(link) => link.href,
            None => {
                return Err(Error::new(
                    ErrorKind::InvalidResponse,
                    "Invalid version - missing self link"));
            }
        };

        Ok(ServiceInfo {
            root_url: endpoint,
            major_version: self.id,
            current_version: self.version,
            minimum_version: self.min_version
        })
    }
}

impl Root {
    /// Extract `ServiceInfo` from a version discovery root.
    pub fn into_service_info<Srv: ServiceType>(self) -> Result<ServiceInfo> {
        match self {
            Root::OneVersion { version: ver } => {
                if Srv::major_version_supported(ver.id) {
                    if ! ver.is_stable() {
                        warn!("Using version {:?} of {} API that is not marked as stable",
                              ver, Srv::catalog_type());
                    }

                    ver.into_service_info()
                } else {
                    Err(Error::new(ErrorKind::EndpointNotFound,
                                   "Major version not supported"))
                }
            },
            Root::MultipleVersions { versions: mut vers } => {
                vers.sort_unstable_by_key(|x| x.id);
                match vers.into_iter().rfind(|x| {
                    x.is_stable() && Srv::major_version_supported(x.id)
                }) {
                    Some(ver) => ver.into_service_info(),
                    None => Err(Error::new_endpoint_not_found(Srv::catalog_type()))
                }
            }
        }
    }
}

impl ServiceInfo {
    /// Generic code to extract a `ServiceInfo` from a URL.
    pub fn fetch<Srv: ServiceType>(endpoint: Url, auth: &AuthMethod) -> Result<ServiceInfo> {
        let service_type = Srv::catalog_type();
        debug!("Fetching {} service info from {}", service_type, endpoint);

        // Workaround for old version of Nova returning HTTP endpoints even if
        // accessed via HTTP
        let secure = endpoint.scheme() == "https";

        let result = auth.request(Method::GET, endpoint.clone())?.send_checked();
        match result {
            Ok(mut resp) => {
                let root = resp.json::<Root>()?;
                trace!("Available major versions for {} service from {}: {:?}",
                       service_type, endpoint, root);

                let mut info = root.into_service_info::<Srv>()?;

                // Older Nova returns insecure URLs even for secure protocol.
                if secure {
                    info.root_url.set_scheme("https").unwrap();
                }

                debug!("Received {:?} for {} service from {}",
                       info, service_type, endpoint);
                Ok(info)
            },
            Err(ref e) if e.kind() == ErrorKind::ResourceNotFound => {
                if utils::url::is_root(&endpoint) {
                    Err(Error::new_endpoint_not_found(service_type))
                } else {
                    debug!("Got HTTP 404 from {}, trying parent endpoint",
                           endpoint);
                    ServiceInfo::fetch::<Srv>(utils::url::pop(endpoint, true),
                                              auth)
                }
            },
            Err(other) => Err(other)
        }
    }
}

/// Deserialize value where empty string equals None.
pub fn empty_as_none<'de, D, T>(des: D) -> ::std::result::Result<Option<T>, D::Error>
        where D: Deserializer<'de>, T: DeserializeOwned {
    let value = serde_json::Value::deserialize(des)?;
    match value {
        serde_json::Value::String(ref s) if s == "" => return Ok(None),
        _ => ()
    };

    serde_json::from_value(value).map_err(DeserError::custom)
}

/// Deserialize value where empty string equals None.
pub fn empty_as_default<'de, D, T>(des: D) -> ::std::result::Result<T, D::Error>
        where D: Deserializer<'de>, T: DeserializeOwned + Default {
    let value = serde_json::Value::deserialize(des)?;
    match value {
        serde_json::Value::String(ref s) if s == "" =>
            return Ok(Default::default()),
        _ => ()
    };

    serde_json::from_value(value).map_err(DeserError::custom)
}

pub fn deser_version<'de, D>(des: D)
        -> ::std::result::Result<ApiVersion, D::Error>
        where D: Deserializer<'de> {
    let value = String::deserialize(des)?;
    if value.is_empty() {
        return Err(D::Error::custom("Empty version ID"));
    }

    let version_part = if value.starts_with("v") {
        &value[1..]
    } else {
        &value
    };

    ApiVersion::from_str(version_part).map_err(D::Error::custom)
}

/// Deserialize a URL.
pub fn deser_url<'de, D>(des: D) -> ::std::result::Result<Url, D::Error>
        where D: Deserializer<'de> {
    Url::parse(&String::deserialize(des)?).map_err(DeserError::custom)
}

/// Deserialize a URL.
pub fn deser_optional_url<'de, D>(des: D)
        -> ::std::result::Result<Option<Url>, D::Error>
        where D: Deserializer<'de> {
    let value: Option<String> = Deserialize::deserialize(des)?;
    match value {
        Some(s) => Url::parse(&s).map_err(DeserError::custom).map(Some),
        None => Ok(None)
    }
}

/// Deserialize a key-value mapping.
pub fn deser_key_value<'de, D>(des: D)
        -> ::std::result::Result<HashMap<String, String>, D::Error>
        where D: Deserializer<'de> {
    let value: Vec<KeyValue> = Deserialize::deserialize(des)?;
    Ok(value.into_iter().map(|kv| (kv.key, kv.value)).collect())
}

/// Serialize a MAC address in its HEX format.
pub fn ser_mac<S>(value: &MacAddress, serializer: S)
        -> ::std::result::Result<S::Ok, S::Error>
        where S: Serializer {
    value.to_hex_string().serialize(serializer)
}

/// Serialize a MAC address in its HEX format.
pub fn ser_opt_mac<S>(value: &Option<MacAddress>, serializer: S)
        -> ::std::result::Result<S::Ok, S::Error>
        where S: Serializer {
    value.map(|m| m.to_hex_string()).serialize(serializer)
}
<commit_msg>fix(common): SUPPORTED is also a stable version (used e.g. in Nova)<commit_after>// Copyright 2018 Dmitry Tantsur <divius.inside@gmail.com>
//
// 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.

//! Common protocol bits.

#![allow(dead_code)] // various things are unused with --no-default-features
#![allow(missing_docs)]

use std::collections::HashMap;
use std::str::FromStr;

use eui48::MacAddress;
use reqwest::{Method, Url};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::{DeserializeOwned, Error as DeserError};
use serde_json;

use super::super::{Error, ErrorKind, Result};
use super::super::auth::AuthMethod;
use super::super::session::{RequestBuilderExt, ServiceType};
use super::super::utils;
use super::ApiVersion;

#[derive(Clone, Debug, Deserialize)]
pub struct Link {
    #[serde(deserialize_with = "deser_url")]
    pub href: Url,
    pub rel: String
}

#[derive(Clone, Debug, Deserialize)]
pub struct Ref {
    pub id: String,
    pub links: Vec<Link>
}

#[derive(Clone, Debug, Deserialize)]
pub struct IdAndName {
    pub id: String,
    pub name: String
}

#[derive(Clone, Debug, Deserialize)]
pub struct KeyValue {
    pub key: String,
    pub value: String,
}

#[derive(Clone, Debug, Deserialize)]
pub struct Version {
    #[serde(deserialize_with = "deser_version")]
    pub id: ApiVersion,
    pub links: Vec<Link>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub status: Option<String>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub version: Option<ApiVersion>,
    #[serde(deserialize_with = "empty_as_none", default)]
    pub min_version: Option<ApiVersion>
}

#[derive(Clone, Debug, Deserialize)]
#[serde(untagged)]
pub enum Root {
    MultipleVersions { versions: Vec<Version> },
    OneVersion { version: Version },
}

/// Information about API endpoint.
#[derive(Clone, Debug)]
pub struct ServiceInfo {
    /// Root endpoint.
    pub root_url: Url,
    /// Major API version.
    pub major_version: ApiVersion,
    /// Current API version (if supported).
    pub current_version: Option<ApiVersion>,
    /// Minimum API version (if supported).
    pub minimum_version: Option<ApiVersion>
}

impl Version {
    pub fn is_stable(&self) -> bool {
        if let Some(ref status) = self.status {
            let upper = status.to_uppercase();
            upper == "STABLE" || upper == "CURRENT" || upper == "SUPPORTED"
        } else {
            true
        }
    }

    pub fn into_service_info(self) -> Result<ServiceInfo> {
        let endpoint = match self.links.into_iter().find(|x| &x.rel == "self") {
            Some(link) => link.href,
            None => {
                return Err(Error::new(
                    ErrorKind::InvalidResponse,
                    "Invalid version - missing self link"));
            }
        };

        Ok(ServiceInfo {
            root_url: endpoint,
            major_version: self.id,
            current_version: self.version,
            minimum_version: self.min_version
        })
    }
}

impl Root {
    /// Extract `ServiceInfo` from a version discovery root.
    pub fn into_service_info<Srv: ServiceType>(self) -> Result<ServiceInfo> {
        match self {
            Root::OneVersion { version: ver } => {
                if Srv::major_version_supported(ver.id) {
                    if ! ver.is_stable() {
                        warn!("Using version {:?} of {} API that is not marked as stable",
                              ver, Srv::catalog_type());
                    }

                    ver.into_service_info()
                } else {
                    Err(Error::new(ErrorKind::EndpointNotFound,
                                   "Major version not supported"))
                }
            },
            Root::MultipleVersions { versions: mut vers } => {
                vers.sort_unstable_by_key(|x| x.id);
                match vers.into_iter().rfind(|x| {
                    x.is_stable() && Srv::major_version_supported(x.id)
                }) {
                    Some(ver) => ver.into_service_info(),
                    None => Err(Error::new_endpoint_not_found(Srv::catalog_type()))
                }
            }
        }
    }
}

impl ServiceInfo {
    /// Generic code to extract a `ServiceInfo` from a URL.
    pub fn fetch<Srv: ServiceType>(endpoint: Url, auth: &AuthMethod) -> Result<ServiceInfo> {
        let service_type = Srv::catalog_type();
        debug!("Fetching {} service info from {}", service_type, endpoint);

        // Workaround for old version of Nova returning HTTP endpoints even if
        // accessed via HTTP
        let secure = endpoint.scheme() == "https";

        let result = auth.request(Method::GET, endpoint.clone())?.send_checked();
        match result {
            Ok(mut resp) => {
                let root = resp.json::<Root>()?;
                trace!("Available major versions for {} service from {}: {:?}",
                       service_type, endpoint, root);

                let mut info = root.into_service_info::<Srv>()?;

                // Older Nova returns insecure URLs even for secure protocol.
                if secure {
                    info.root_url.set_scheme("https").unwrap();
                }

                debug!("Received {:?} for {} service from {}",
                       info, service_type, endpoint);
                Ok(info)
            },
            Err(ref e) if e.kind() == ErrorKind::ResourceNotFound => {
                if utils::url::is_root(&endpoint) {
                    Err(Error::new_endpoint_not_found(service_type))
                } else {
                    debug!("Got HTTP 404 from {}, trying parent endpoint",
                           endpoint);
                    ServiceInfo::fetch::<Srv>(utils::url::pop(endpoint, true),
                                              auth)
                }
            },
            Err(other) => Err(other)
        }
    }
}

/// Deserialize value where empty string equals None.
pub fn empty_as_none<'de, D, T>(des: D) -> ::std::result::Result<Option<T>, D::Error>
        where D: Deserializer<'de>, T: DeserializeOwned {
    let value = serde_json::Value::deserialize(des)?;
    match value {
        serde_json::Value::String(ref s) if s == "" => return Ok(None),
        _ => ()
    };

    serde_json::from_value(value).map_err(DeserError::custom)
}

/// Deserialize value where empty string equals None.
pub fn empty_as_default<'de, D, T>(des: D) -> ::std::result::Result<T, D::Error>
        where D: Deserializer<'de>, T: DeserializeOwned + Default {
    let value = serde_json::Value::deserialize(des)?;
    match value {
        serde_json::Value::String(ref s) if s == "" =>
            return Ok(Default::default()),
        _ => ()
    };

    serde_json::from_value(value).map_err(DeserError::custom)
}

pub fn deser_version<'de, D>(des: D)
        -> ::std::result::Result<ApiVersion, D::Error>
        where D: Deserializer<'de> {
    let value = String::deserialize(des)?;
    if value.is_empty() {
        return Err(D::Error::custom("Empty version ID"));
    }

    let version_part = if value.starts_with("v") {
        &value[1..]
    } else {
        &value
    };

    ApiVersion::from_str(version_part).map_err(D::Error::custom)
}

/// Deserialize a URL.
pub fn deser_url<'de, D>(des: D) -> ::std::result::Result<Url, D::Error>
        where D: Deserializer<'de> {
    Url::parse(&String::deserialize(des)?).map_err(DeserError::custom)
}

/// Deserialize a URL.
pub fn deser_optional_url<'de, D>(des: D)
        -> ::std::result::Result<Option<Url>, D::Error>
        where D: Deserializer<'de> {
    let value: Option<String> = Deserialize::deserialize(des)?;
    match value {
        Some(s) => Url::parse(&s).map_err(DeserError::custom).map(Some),
        None => Ok(None)
    }
}

/// Deserialize a key-value mapping.
pub fn deser_key_value<'de, D>(des: D)
        -> ::std::result::Result<HashMap<String, String>, D::Error>
        where D: Deserializer<'de> {
    let value: Vec<KeyValue> = Deserialize::deserialize(des)?;
    Ok(value.into_iter().map(|kv| (kv.key, kv.value)).collect())
}

/// Serialize a MAC address in its HEX format.
pub fn ser_mac<S>(value: &MacAddress, serializer: S)
        -> ::std::result::Result<S::Ok, S::Error>
        where S: Serializer {
    value.to_hex_string().serialize(serializer)
}

/// Serialize a MAC address in its HEX format.
pub fn ser_opt_mac<S>(value: &Option<MacAddress>, serializer: S)
        -> ::std::result::Result<S::Ok, S::Error>
        where S: Serializer {
    value.map(|m| m.to_hex_string()).serialize(serializer)
}

#[cfg(test)]
mod test {
    use reqwest::Url;

    use super::super::super::ErrorKind;
    use super::super::ApiVersion;
    use super::{Link, Version};

    #[test]
    fn test_version_current_is_stable() {
        let stable = Version {
            id: ApiVersion(2, 0),
            links: Vec::new(),
            status: Some("CURRENT".to_string()),
            version: None,
            min_version: None,
        };
        assert!(stable.is_stable());
    }

    #[test]
    fn test_version_stable_is_stable() {
        let stable = Version {
            id: ApiVersion(2, 0),
            links: Vec::new(),
            status: Some("Stable".to_string()),
            version: None,
            min_version: None,
        };
        assert!(stable.is_stable());
    }

    #[test]
    fn test_version_supported_is_stable() {
        let stable = Version {
            id: ApiVersion(2, 0),
            links: Vec::new(),
            status: Some("supported".to_string()),
            version: None,
            min_version: None,
        };
        assert!(stable.is_stable());
    }

    #[test]
    fn test_version_no_status_is_stable() {
        let stable = Version {
            id: ApiVersion(2, 0),
            links: Vec::new(),
            status: None,
            version: None,
            min_version: None,
        };
        assert!(stable.is_stable());
    }

    #[test]
    fn test_version_deprecated_is_not_stable() {
        let unstable = Version {
            id: ApiVersion(2, 0),
            links: Vec::new(),
            status: Some("DEPRECATED".to_string()),
            version: None,
            min_version: None,
        };
        assert!(!unstable.is_stable());
    }

    #[test]
    fn test_version_into_service_info() {
        let url = Url::parse("https://example.com/v2").unwrap();
        let ver = Version {
            id: ApiVersion(2, 0),
            links: vec![Link{
                href: Url::parse("https://example.com/docs").unwrap(),
                rel: "other".to_string(),
            }, Link {
                href: url.clone(),
                rel: "self".to_string(),
            }],
            status: None,
            version: Some(ApiVersion(2, 2)),
            min_version: None,
        };
        let info = ver.into_service_info().unwrap();
        assert_eq!(info.root_url, url);
        assert_eq!(info.major_version, ApiVersion(2, 0));
        assert_eq!(info.current_version, Some(ApiVersion(2, 2)));
        assert_eq!(info.minimum_version, None);
    }

    #[test]
    fn test_version_into_service_info_no_self_link() {
        let ver = Version {
            id: ApiVersion(2, 0),
            links: vec![Link{
                href: Url::parse("https://example.com/docs").unwrap(),
                rel: "other".to_string(),
            }],
            status: None,
            version: Some(ApiVersion(2, 2)),
            min_version: None,
        };
        let err = ver.into_service_info().err().unwrap();
        assert_eq!(err.kind(), ErrorKind::InvalidResponse);
    }
}
<|endoftext|>


<commit_before>extern crate ink;

use ink::BlockParser;
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("demo.txt").unwrap();
    let mut input = String::new();

    file.read_to_string(&mut input).unwrap();

    let mut parser = BlockParser::new(input);

    for block in parser {
        println!("{:?}", block);
    }
}<commit_msg>Remove unused mut<commit_after>extern crate ink;

use ink::BlockParser;
use std::fs::File;
use std::io::Read;

fn main() {
    let mut file = File::open("demo.txt").unwrap();
    let mut input = String::new();

    file.read_to_string(&mut input).unwrap();

    let parser = BlockParser::new(input);

    for block in parser {
        println!("{:?}", block);
    }
}<|endoftext|>


<commit_before>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(os, cwd, output, _), libs)
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "@executable_path" + fs::path_sep() }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::starts_with(res, "/");
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "@executable_path/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<commit_msg>Hopefully make test_prefix_rpath_abs work on win32<commit_after>import std::os;
import std::fs;
import std::os_fs;
import std::vec;
import std::map;
import std::str;
import std::uint;
import metadata::cstore;
import driver::session;
import util::filesearch;

// FIXME #721: Despite the compiler warning, test does exist and needs
// to be exported
export get_rpath_flags, test;

fn get_rpath_flags(sess: session::session, out_filename: str) -> [str] {
    let os = sess.get_targ_cfg().os;

    // No rpath on windows
    if os == session::os_win32 {
        ret [];
    }

    log "preparing the RPATH!";

    let cwd = os::getcwd();
    let sysroot = sess.filesearch().sysroot();
    let output = out_filename;
    let libs = cstore::get_used_crate_files(sess.get_cstore());
    // We don't currently rpath native libraries, but we know
    // where rustrt is and we know every rust program needs it
    let libs = libs + [get_sysroot_absolute_rt_lib(sess)];

    let target_triple = sess.get_opts().target_triple;
    let rpaths = get_rpaths(os, cwd, sysroot, output, libs, target_triple);
    rpaths_to_flags(rpaths)
}

fn get_sysroot_absolute_rt_lib(sess: session::session) -> fs::path {
    let path = [sess.filesearch().sysroot()]
        + filesearch::relative_target_lib_path(
            sess.get_opts().target_triple)
        + [os::dylib_filename("rustrt")];
    check vec::is_not_empty(path);
    fs::connect_many(path)
}

fn rpaths_to_flags(rpaths: [str]) -> [str] {
    vec::map({ |rpath| #fmt("-Wl,-rpath,%s",rpath)}, rpaths)
}

fn get_rpaths(os: session::os, cwd: fs::path, sysroot: fs::path,
              output: fs::path, libs: [fs::path],
              target_triple: str) -> [str] {
    log #fmt("cwd: %s", cwd);
    log #fmt("sysroot: %s", sysroot);
    log #fmt("output: %s", output);
    log #fmt("libs:");
    for libpath in libs {
        log #fmt("    %s", libpath);
    }
    log #fmt("target_triple: %s", target_triple);

    // Use relative paths to the libraries. Binaries can be moved
    // as long as they maintain the relative relationship to the
    // crates they depend on.
    let rel_rpaths = get_rpaths_relative_to_output(os, cwd, output, libs);

    // Make backup absolute paths to the libraries. Binaries can
    // be moved as long as the crates they link against don't move.
    let abs_rpaths = get_absolute_rpaths(cwd, libs);

    // And a final backup rpath to the global library location.
    let fallback_rpaths = [get_install_prefix_rpath(cwd, target_triple)];

    fn log_rpaths(desc: str, rpaths: [str]) {
        log #fmt("%s rpaths:", desc);
        for rpath in rpaths {
            log #fmt("    %s", rpath);
        }
    }

    log_rpaths("relative", rel_rpaths);
    log_rpaths("absolute", abs_rpaths);
    log_rpaths("fallback", fallback_rpaths);

    let rpaths = rel_rpaths + abs_rpaths + fallback_rpaths;

    // Remove duplicates
    let rpaths = minimize_rpaths(rpaths);
    ret rpaths;
}

fn get_rpaths_relative_to_output(os: session::os,
                                 cwd: fs::path,
                                 output: fs::path,
                                 libs: [fs::path]) -> [str] {
    vec::map(bind get_rpath_relative_to_output(os, cwd, output, _), libs)
}

fn get_rpath_relative_to_output(os: session::os,
                                cwd: fs::path,
                                output: fs::path,
                                lib: fs::path) -> str {
    // Mac doesn't appear to support $ORIGIN
    let prefix = alt os {
        session::os_linux. { "$ORIGIN" + fs::path_sep() }
        session::os_macos. { "@executable_path" + fs::path_sep() }
    };

    prefix + get_relative_to(
        get_absolute(cwd, output),
        get_absolute(cwd, lib))
}

// Find the relative path from one file to another
fn get_relative_to(abs1: fs::path, abs2: fs::path) -> fs::path {
    assert fs::path_is_absolute(abs1);
    assert fs::path_is_absolute(abs2);
    log #fmt("finding relative path from %s to %s",
             abs1, abs2);
    let normal1 = fs::normalize(abs1);
    let normal2 = fs::normalize(abs2);
    let split1 = str::split(normal1, os_fs::path_sep as u8);
    let split2 = str::split(normal2, os_fs::path_sep as u8);
    let len1 = vec::len(split1);
    let len2 = vec::len(split2);
    assert len1 > 0u;
    assert len2 > 0u;

    let max_common_path = uint::min(len1, len2) - 1u;
    let start_idx = 0u;
    while start_idx < max_common_path
        && split1[start_idx] == split2[start_idx] {
        start_idx += 1u;
    }

    let path = [];

    for each _ in uint::range(start_idx, len1 - 1u) {
        path += [".."];
    }

    path += vec::slice(split2, start_idx, len2 - 1u);

    if check vec::is_not_empty(path) {
        ret fs::connect_many(path);
    } else {
        ret ".";
    }
}

fn get_absolute_rpaths(cwd: fs::path, libs: [fs::path]) -> [str] {
    vec::map(bind get_absolute_rpath(cwd, _), libs)
}

fn get_absolute_rpath(cwd: fs::path, lib: fs::path) -> str {
    fs::dirname(get_absolute(cwd, lib))
}

fn get_absolute(cwd: fs::path, lib: fs::path) -> fs::path {
    if fs::path_is_absolute(lib) {
        lib
    } else {
        fs::connect(cwd, lib)
    }
}

fn get_install_prefix_rpath(cwd: fs::path, target_triple: str) -> str {
    let install_prefix = #env("CFG_PREFIX");

    if install_prefix == "" {
        fail "rustc compiled without CFG_PREFIX environment variable";
    }

    let path = [install_prefix]
        + filesearch::relative_target_lib_path(target_triple);
    check vec::is_not_empty(path);
    get_absolute(cwd, fs::connect_many(path))
}

fn minimize_rpaths(rpaths: [str]) -> [str] {
    let set = map::new_str_hash::<()>();
    let minimized = [];
    for rpath in rpaths {
        if !set.contains_key(rpath) {
            minimized += [rpath];
            set.insert(rpath, ());
        }
    }
    ret minimized;
}

#[cfg(target_os = "linux")]
#[cfg(target_os = "macos")]
#[cfg(test)]
mod test {
    #[test]
    fn test_rpaths_to_flags() {
        let flags = rpaths_to_flags(["path1", "path2"]);
        assert flags == ["-Wl,-rpath,path1", "-Wl,-rpath,path2"];
    }

    #[test]
    fn test_get_absolute1() {
        let cwd = "/dir";
        let lib = "some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/dir/some/path/lib";
    }

    #[test]
    fn test_get_absolute2() {
        let cwd = "/dir";
        let lib = "/some/path/lib";
        let res = get_absolute(cwd, lib);
        assert res == "/some/path/lib";
    }

    #[test]
    fn test_prefix_rpath() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert str::ends_with(res, #env("CFG_PREFIX")
                              + "/lib/rustc/triple/lib");
    }

    #[test]
    fn test_prefix_rpath_abs() {
        let res = get_install_prefix_rpath("/usr/lib", "triple");
        assert fs::path_is_absolute(res);
    }

    #[test]
    fn test_minimize1() {
        let res = minimize_rpaths(["rpath1", "rpath2", "rpath1"]);
        assert res == ["rpath1", "rpath2"];
    }

    #[test]
    fn test_minimize2() {
        let res = minimize_rpaths(["1a", "2", "2", "1a", "4a",
                                   "1a", "2", "3", "4a", "3"]);
        assert res == ["1a", "2", "4a", "3"];
    }

    #[test]
    fn test_relative_to1() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to2() {
        let p1 = "/usr/bin/rustc";
        let p2 = "/usr/bin/../lib/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to3() {
        let p1 = "/usr/bin/whatever/rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../../lib/whatever";
    }

    #[test]
    fn test_relative_to4() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib/whatever";
    }

    #[test]
    fn test_relative_to5() {
        let p1 = "/usr/bin/whatever/../rustc";
        let p2 = "/usr/lib/whatever/../mylib";
        let res = get_relative_to(p1, p2);
        assert res == "../lib";
    }

    #[test]
    fn test_relative_to6() {
        let p1 = "/1";
        let p2 = "/2/3";
        let res = get_relative_to(p1, p2);
        assert res == "2";
    }

    #[test]
    fn test_relative_to7() {
        let p1 = "/1/2";
        let p2 = "/3";
        let res = get_relative_to(p1, p2);
        assert res == "..";
    }

    #[test]
    fn test_relative_to8() {
        let p1 = "/home/brian/Dev/rust/build/"
            + "stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so";
        let p2 = "/home/brian/Dev/rust/build/stage2/bin/.."
            + "/lib/rustc/i686-unknown-linux-gnu/lib/libstd.so";
        let res = get_relative_to(p1, p2);
        assert res == ".";
    }

    #[test]
    #[cfg(target_os = "linux")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_linux,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "$ORIGIN/../lib";
    }

    #[test]
    #[cfg(target_os = "macos")]
    fn test_rpath_relative() {
        let res = get_rpath_relative_to_output(session::os_macos,
            "/usr", "bin/rustc", "lib/libstd.so");
        assert res == "@executable_path/../lib";
    }

    #[test]
    fn test_get_absolute_rpath() {
        let res = get_absolute_rpath("/usr", "lib/libstd.so");
        assert res == "/usr/lib";
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused)]
use lift::{Higher, Monad};
use std::hash::Hash;
use std::collections::linked_list::LinkedList;
use std::collections::{BTreeSet, HashSet};

// Implementation of Monad for Vec
impl Monad for Vec {
    fn lift(x: A) -> <Self as Higher>::C {
        vec![x]
    }

    fn bind<F>(&self, mut f: F) -> Vec
        where F: FnMut(&B) -> Vec
    {
        self.iter().flat_map(f).collect::<Vec>()
    }
}

// Implementation of Monad for Option
impl Monad for Option {
    fn lift(x: A) -> <Self as Higher>::C {
        Some(x)
    }

    fn bind<F>(&self, mut f: F) -> Option
        where F: FnMut(&B) -> Option
    {
        match *self {
            Some(ref v) => f(v),
            None => None,
        }
    }
}

//implementation of Moand for Box
impl Monad for Box {
    fn lift(x:A) -> <Self as Higher>::C {
        Box::new(x)
    }

    fn bind<F>(&self, mut f: F) -> Box
        where F : FnMut(&B) -> Box
    {
        f(self)
    }
}

// Implementation of Monad for LinkedList
impl Monad for LinkedList {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = LinkedList::new();
        ret.push_back(x);
        ret
    }

    fn bind<F>(&self, mut f: F) -> LinkedList
        where F: FnMut(&B) -> LinkedList
    {
        self.iter().flat_map(f).collect::<LinkedList>()
    }
}

// Implementations of Monad for BTreeSet
impl Monad for BTreeSet {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = BTreeSet::new();
        ret.insert(x);
        ret
    }

    fn bind<F>(&self, f: F) -> BTreeSet
        where F: FnMut(&B) -> BTreeSet
    {
        self.iter().flat_map(f).collect::<BTreeSet>()
    }
}

// Implementations of Monad for HashSet
impl Monad for HashSet {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = HashSet::new();
        ret.insert(x);
        ret
    }

    fn bind<F>(&self, f: F) -> HashSet
        where F: FnMut(&B) -> HashSet
    {
        self.iter().flat_map(f).collect::<HashSet>()
    }
}

#[cfg(test)]
mod test {
    use lift::{Higher, Monad};

    #[test]
    fn test_option() {
        assert_eq!(Option::lift("a"), Some("a"));
        assert_eq!(Some(2).bind(|x| Some(x+1)), Some(3));
    }

    #[test]
    fn test_box() {
        assert_eq!(Box::lift(2), Box::new(2));
        assert_eq!(Box::new(2).bind(|x| Box::new(x+1)), Box::new(3));
    }

}
<commit_msg>working on finishing up monad, then going to work on applicative<commit_after>#![allow(dead_code, unused)]
use lift::{Higher, Monad};
use std::hash::Hash;
use std::collections::linked_list::LinkedList;
use std::collections::vec_deque::VecDeque;
use std::collections::{BTreeSet, HashSet, BinaryHeap};

// Implementation of Monad for Vec
impl Monad for Vec {
    fn lift(x: A) -> <Self as Higher>::C {
        vec![x]
    }

    fn bind<F>(&self, mut f: F) -> Vec
        where F: FnMut(&B) -> Vec
    {
        self.iter().flat_map(f).collect::<Vec>()
    }
}

// Implementation of Monad for Option
impl Monad for Option {
    fn lift(x: A) -> <Self as Higher>::C {
        Some(x)
    }

    fn bind<F>(&self, mut f: F) -> Option
        where F: FnMut(&B) -> Option
    {
        match *self {
            Some(ref v) => f(v),
            None => None,
        }
    }
}

//implementation of Moand for Box
impl Monad for Box {
    fn lift(x:A) -> <Self as Higher>::C {
        Box::new(x)
    }

    fn bind<F>(&self, mut f: F) -> Box
        where F : FnMut(&B) -> Box
    {
        f(self)
    }
}

// Implementation of Monad for LinkedList
impl Monad for LinkedList {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = LinkedList::new();
        ret.push_back(x);
        ret
    }

    fn bind<F>(&self, mut f: F) -> LinkedList
        where F: FnMut(&B) -> LinkedList
    {
        self.iter().flat_map(f).collect::<LinkedList>()
    }
}

// Implementations of Monad for BTreeSet
impl Monad for BTreeSet {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = BTreeSet::new();
        ret.insert(x);
        ret
    }

    fn bind<F>(&self, f: F) -> BTreeSet
        where F: FnMut(&B) -> BTreeSet
    {
        self.iter().flat_map(f).collect::<BTreeSet>()
    }
}

// Implementations of Monad for HashSet
impl Monad for HashSet {
    fn lift(x: A) -> <Self as Higher>::C {
        let mut ret = HashSet::new();
        ret.insert(x);
        ret
    }

    fn bind<F>(&self, f: F) -> HashSet
        where F: FnMut(&B) -> HashSet
    {
        self.iter().flat_map(f).collect::<HashSet>()
    }
}

#[cfg(test)]
mod test {
    use lift::{Higher, Monad};

    #[test]
    fn test_option() {
        assert_eq!(Option::lift("a"), Some("a"));
        assert_eq!(Some(2).bind(|x| Some(x+1)), Some(3));
    }

    #[test]
    fn test_box() {
        assert_eq!(Box::lift(2), Box::new(2));
        assert_eq!(Box::new(2).bind(|x| Box::new(x+1)), Box::new(3));
    }

}
<|endoftext|>


<commit_before><commit_msg>Connect to relay, wait a bit, and quit<commit_after><|endoftext|>


<commit_before>
// Std
use std::io::Write;
use std::ascii::AsciiExt;

// Internal
use app::App;
use app::parser::Parser;
use args::{ArgSettings, AnyArg};
use completions;
use INTERNAL_ERROR_MSG;

pub struct ZshGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> ZshGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self {
        debugln!("fn=ZshGen::new;");
        ZshGen { p: p }
    }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        debugln!("fn=generate_to;");
        w!(buf,
            format!("\
#compdef {name}

_{name}() {{
	typeset -A opt_args
	local ret=1

	local context curcontext=\"$curcontext\" state line
    {initial_args}
    {subcommands}
}}

{subcommand_details}

_{name} \"$@\"",
                   name = self.p.meta.bin_name.as_ref().unwrap(),
                   initial_args = get_args_of(self.p),
                   subcommands = get_subcommands_of(self.p),
                   subcommand_details = subcommand_details(self.p)).as_bytes());

    }
}

// Displays the positional args and commands of a subcommand
// (( $+functions[_[bin_name_underscore]_commands] )) ||
// _[bin_name_underscore]_commands() {
// 	local commands; commands=(
// 		'[arg_name]:[arg_help]'
// 	)
// 	_describe -t commands '[bin_name] commands' commands "$@"
//
// Where the following variables are present:
//    [bin_name_underscore]: The full space deliniated bin_name, where spaces have been replaced by
//                           underscore characters
//    [arg_name]: The name of the positional arg or subcommand
//    [arg_help]: The help message of the arg or subcommand
//    [bin_name]: The full space deliniated bin_name
//
// Here's a snippet from rustup:
//
// (( $+functions[_rustup_commands] )) ||
// _rustup_commands() {
// 	local commands; commands=(
// 		'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
//      # ... snip for brevity
//      'help:Prints this message or the help of the given subcommand(s)'
// 	)
// 	_describe -t commands 'rustup commands' commands "$@"
//
fn subcommand_details(p: &Parser) -> String {
    debugln!("fn=subcommand_details");
    // First we do ourself
    let mut ret = vec![format!("\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "_"),
            bin_name = p.meta.bin_name.as_ref().unwrap(),
            subcommands_and_args = subcommands_and_args_of(p))];

    // Next we start looping through all the children, grandchildren, etc.
    let mut all_subcommands = completions::all_subcommands(p);
    all_subcommands.sort();
    all_subcommands.dedup();
    for &(_, ref bin_name) in &all_subcommands {
        debugln!("iter;bin_name={}", bin_name);
        ret.push(format!("\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = bin_name.replace(" ", "_"),
            bin_name = bin_name,
            subcommands_and_args = subcommands_and_args_of(parser_of(p, bin_name))));
    }

    ret.join("\n")
}

// Generates subcommand and positional argument completions in form of
//
// 		'[arg_name]:[arg_help]'
//
// Where:
//    [arg_name]: the argument or subcommand's name
//    [arg_help]: the help message of the argument or subcommand
//
// A snippet from rustup:
// 		'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
fn subcommands_and_args_of(p: &Parser) -> String {
    debugln!("fn=subcommands_and_args_of;");
    let mut ret = vec![];
    fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
        let s = format!("\"{name}:{help}\" \\",
            name = n,
            help = sc.p.meta.about.unwrap_or(""));
        if !s.is_empty() {
            ret.push(s);
        }
    }

    // First the subcommands
    for sc in p.subcommands() {
        debugln!("iter;subcommand={}", sc.p.meta.name);
        add_sc(sc, &sc.p.meta.name, &mut ret);
        if let Some(ref v) = sc.p.meta.aliases {
            for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
                add_sc(sc, alias, &mut ret);
            }
        }
    }

    // Then the positional args
    for arg in p.positionals() {
        debugln!("iter;arg={}", arg.b.name);
        let a = format!("\"{name}:{help}\" \\",
            name = arg.b.name.to_ascii_uppercase(),
            help = arg.b.help.unwrap_or(""));

        if !a.is_empty() {
            ret.push(a);
        }
    }

    ret.join("\n")
}

// Get's the subcommand section of a completion file
// This looks roughly like:
//
// case $state in
// ([bin_name]_args)
//     curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
//     case $line[1] in
//
//         ([name])
//         _arguments -C -s -S \
//             [subcommand_args]
//         && ret=0
//
//         [RECURSIVE_CALLS]
//
//         ;;",
//
//         [repeat]
//
//     esac
// ;;
// esac",
//
// Where the following variables are present:
//    [name] = The subcommand name in the form of "install" for "rustup toolchain install"
//    [bin_name] = The full space deliniated bin_name such as "rustup toolchain install"
//    [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
//    [repeat] = From the same recursive calls, but for all subcommands
//    [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &Parser) -> String {
    debugln!("fn=get_subcommands");

    debug!("Has subcommands...");
    if !p.has_subcommands() {
        sdebugln!("No");
        return String::new();
    } else {
        sdebugln!("Yes");
    }

    let sc_names = completions::subcommands_of(p);

    let mut subcmds = vec![];
    for &(ref name, ref bin_name) in &sc_names {
        let mut v = vec![format!("({})", name)];
        let subcommand_args = get_args_of(parser_of(p, &*bin_name));
        if !subcommand_args.is_empty() {
            v.push(subcommand_args);
        }
        let subcommands = get_subcommands_of(parser_of(p, &*bin_name));
        if !subcommands.is_empty() {
            v.push(subcommands);
        }
        v.push(String::from(";;"));
        subcmds.push(v.join("\n"));
    }

    format!(
"case $state in
    ({name})
        curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$words[1]:\"
        case $line[1] in
            {subcommands}
        esac
    ;;
esac",
        name = p.meta.name,
        name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"),
        subcommands = subcmds.join("\n"))
}

fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
    debugln!("fn=parser_of;sc={}", sc);
    &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p
}

// Writes out the args section, which ends up being the flags and opts, and a jump to
// another ZSH function if there are positional args or subcommands.
// The structer works like this:
//    ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
//       ^-- list '-v -h'    ^--'*'          ^--'+'                   ^-- list 'one two three'
//
// An example from the rustup command:
//
// _arguments -C -s -S \
// 		'(-h --help --verbose)-v[Enable verbose output]' \
// 		'(-V -v --version --verbose --help)-h[Prints help information]' \
//      # ... snip for brevity
// 		'1:: :_rustup_commands' \   # <-- displays positional args and subcommands
// 		'*:: :->rustup' \           # <-- displays subcommand args and child subcommands
// 	&& ret=0
//
// The args used for _arguments are as follows:
//    -C: modify the $context internal variable
//    -s: Allow stacking of short args (i.e. -a -b -c => -abc)
//    -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &Parser) -> String {
    debugln!("fn=get_args_of");
    let mut ret = vec![String::from("_arguments -s -S -C \\")];
    let opts = write_opts_of(p);
    let flags = write_flags_of(p);
    let sc_or_a = if p.has_subcommands() || p.has_positionals() {
        format!("\"1:: :_{name}_commands\" \\",
                name = p.meta.bin_name.as_ref().unwrap().replace(" ", "_"))
    } else {
        String::new()
    };
    let sc = if p.has_subcommands() {
        format!("\"*:: :->{name}\" \\", name = p.meta.name)
    } else {
        String::new()
    };

    if !opts.is_empty() {
        ret.push(opts);
    }
    if !flags.is_empty() {
        ret.push(flags);
    }
    if !sc_or_a.is_empty() {
        ret.push(sc_or_a);
    }
    if !sc.is_empty() {
        ret.push(sc);
    }
    ret.push(String::from("&& ret=0"));

    ret.join("\n")
}

fn write_opts_of(p: &Parser) -> String {
    debugln!("fn=write_opts_of;");
    let mut ret = vec![];
    for o in p.opts() {
        debugln!("iter;o={}", o.name());
        let help = o.help().unwrap_or("");
        let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);
        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if o.is_set(ArgSettings::Multiple) {
            "*"
        } else {
            ""
        };
        let pv = if let Some(pv_vec) = o.possible_vals() {
            format!(": :({})", pv_vec.join(" "))
        } else {
            String::new()
        };
        if let Some(short) = o.short() {
            let s = format!("\"{conflicts}{multiple}-{arg}+[{help}]{possible_values}\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = short,
                possible_values = pv,
                help = help);

            debugln!("Wrote...{}", &*s);
            ret.push(s);
        }
        if let Some(long) = o.long() {
            let l = format!("\"{conflicts}{multiple}--{arg}+[{help}]{possible_values}\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                possible_values = pv,
                help = help);

            debugln!("Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_flags_of(p: &Parser) -> String {
    debugln!("fn=write_flags_of;");
    let mut ret = vec![];
    for f in p.flags() {
        debugln!("iter;f={}", f.name());
        let help = f.help().unwrap_or("");
        let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);
        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if f.is_set(ArgSettings::Multiple) {
            "*"
        } else {
            ""
        };
        if let Some(short) = f.short() {
            let s = format!("\"{conflicts}{multiple}-{arg}[{help}]\" \\",
                multiple = multiple,
                conflicts = conflicts,
                arg = short,
                help = help);

            debugln!("Wrote...{}", &*s);
            ret.push(s);
        }

        if let Some(long) = f.long() {
            let l = format!("\"{conflicts}{multiple}--{arg}[{help}]\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                help = help);

            debugln!("Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}
<commit_msg>fix(ZSH Completions): fixes an issue where zsh completions caused panics if there were no subcommands<commit_after>
// Std
use std::io::Write;
use std::ascii::AsciiExt;

// Internal
use app::App;
use app::parser::Parser;
use args::{ArgSettings, AnyArg};
use completions;
use INTERNAL_ERROR_MSG;

pub struct ZshGen<'a, 'b>
    where 'a: 'b
{
    p: &'b Parser<'a, 'b>,
}

impl<'a, 'b> ZshGen<'a, 'b> {
    pub fn new(p: &'b Parser<'a, 'b>) -> Self {
        debugln!("fn=ZshGen::new;");
        ZshGen { p: p }
    }

    pub fn generate_to<W: Write>(&self, buf: &mut W) {
        debugln!("fn=generate_to;");
        w!(buf,
            format!("\
#compdef {name}

_{name}() {{
	typeset -A opt_args
	local ret=1

	local context curcontext=\"$curcontext\" state line
    {initial_args}
    {subcommands}
}}

{subcommand_details}

_{name} \"$@\"",
                   name = self.p.meta.bin_name.as_ref().unwrap(),
                   initial_args = get_args_of(self.p),
                   subcommands = get_subcommands_of(self.p),
                   subcommand_details = subcommand_details(self.p)).as_bytes());

    }
}

// Displays the positional args and commands of a subcommand
// (( $+functions[_[bin_name_underscore]_commands] )) ||
// _[bin_name_underscore]_commands() {
// 	local commands; commands=(
// 		'[arg_name]:[arg_help]'
// 	)
// 	_describe -t commands '[bin_name] commands' commands "$@"
//
// Where the following variables are present:
//    [bin_name_underscore]: The full space deliniated bin_name, where spaces have been replaced by
//                           underscore characters
//    [arg_name]: The name of the positional arg or subcommand
//    [arg_help]: The help message of the arg or subcommand
//    [bin_name]: The full space deliniated bin_name
//
// Here's a snippet from rustup:
//
// (( $+functions[_rustup_commands] )) ||
// _rustup_commands() {
// 	local commands; commands=(
// 		'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
//      # ... snip for brevity
//      'help:Prints this message or the help of the given subcommand(s)'
// 	)
// 	_describe -t commands 'rustup commands' commands "$@"
//
fn subcommand_details(p: &Parser) -> String {
    debugln!("fn=subcommand_details");
    // First we do ourself
    let mut ret = vec![format!("\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = p.meta.bin_name.as_ref().unwrap().replace(" ", "_"),
            bin_name = p.meta.bin_name.as_ref().unwrap(),
            subcommands_and_args = subcommands_and_args_of(p))];

    // Next we start looping through all the children, grandchildren, etc.
    let mut all_subcommands = completions::all_subcommands(p);
    all_subcommands.sort();
    all_subcommands.dedup();
    for &(_, ref bin_name) in &all_subcommands {
        debugln!("iter;bin_name={}", bin_name);
        ret.push(format!("\
(( $+functions[_{bin_name_underscore}_commands] )) ||
_{bin_name_underscore}_commands() {{
    local commands; commands=(
        {subcommands_and_args}
    )
    _describe -t commands '{bin_name} commands' commands \"$@\"
}}",
            bin_name_underscore = bin_name.replace(" ", "_"),
            bin_name = bin_name,
            subcommands_and_args = subcommands_and_args_of(parser_of(p, bin_name))));
    }

    ret.join("\n")
}

// Generates subcommand and positional argument completions in form of
//
// 		'[arg_name]:[arg_help]'
//
// Where:
//    [arg_name]: the argument or subcommand's name
//    [arg_help]: the help message of the argument or subcommand
//
// A snippet from rustup:
// 		'show:Show the active and installed toolchains'
//      'update:Update Rust toolchains'
fn subcommands_and_args_of(p: &Parser) -> String {
    debugln!("fn=subcommands_and_args_of;");
    let mut ret = vec![];
    fn add_sc(sc: &App, n: &str, ret: &mut Vec<String>) {
        let s = format!("\"{name}:{help}\" \\",
            name = n,
            help = sc.p.meta.about.unwrap_or(""));
        if !s.is_empty() {
            ret.push(s);
        }
    }

    // First the subcommands
    for sc in p.subcommands() {
        debugln!("iter;subcommand={}", sc.p.meta.name);
        add_sc(sc, &sc.p.meta.name, &mut ret);
        if let Some(ref v) = sc.p.meta.aliases {
            for alias in v.iter().filter(|&&(_, vis)| vis).map(|&(n, _)| n) {
                add_sc(sc, alias, &mut ret);
            }
        }
    }

    // Then the positional args
    for arg in p.positionals() {
        debugln!("iter;arg={}", arg.b.name);
        let a = format!("\"{name}:{help}\" \\",
            name = arg.b.name.to_ascii_uppercase(),
            help = arg.b.help.unwrap_or(""));

        if !a.is_empty() {
            ret.push(a);
        }
    }

    ret.join("\n")
}

// Get's the subcommand section of a completion file
// This looks roughly like:
//
// case $state in
// ([bin_name]_args)
//     curcontext=\"${curcontext%:*:*}:[name_hyphen]-command-$words[1]:\"
//     case $line[1] in
//
//         ([name])
//         _arguments -C -s -S \
//             [subcommand_args]
//         && ret=0
//
//         [RECURSIVE_CALLS]
//
//         ;;",
//
//         [repeat]
//
//     esac
// ;;
// esac",
//
// Where the following variables are present:
//    [name] = The subcommand name in the form of "install" for "rustup toolchain install"
//    [bin_name] = The full space deliniated bin_name such as "rustup toolchain install"
//    [name_hyphen] = The full space deliniated bin_name, but replace spaces with hyphens
//    [repeat] = From the same recursive calls, but for all subcommands
//    [subcommand_args] = The same as zsh::get_args_of
fn get_subcommands_of(p: &Parser) -> String {
    debugln!("fn=get_subcommands_of");

    debug!("Has subcommands...");
    if !p.has_subcommands() {
        sdebugln!("No");
        return String::new();
    } else {
        sdebugln!("Yes");
    }

    let sc_names = completions::subcommands_of(p);

    let mut subcmds = vec![];
    for &(ref name, ref bin_name) in &sc_names {
        let mut v = vec![format!("({})", name)];
        let subcommand_args = get_args_of(parser_of(p, &*bin_name));
        if !subcommand_args.is_empty() {
            v.push(subcommand_args);
        }
        let subcommands = get_subcommands_of(parser_of(p, &*bin_name));
        if !subcommands.is_empty() {
            v.push(subcommands);
        }
        v.push(String::from(";;"));
        subcmds.push(v.join("\n"));
    }

    format!(
"case $state in
    ({name})
        curcontext=\"${{curcontext%:*:*}}:{name_hyphen}-command-$words[1]:\"
        case $line[1] in
            {subcommands}
        esac
    ;;
esac",
        name = p.meta.name,
        name_hyphen = p.meta.bin_name.as_ref().unwrap().replace(" ", "-"),
        subcommands = subcmds.join("\n"))
}

fn parser_of<'a, 'b>(p: &'b Parser<'a, 'b>, sc: &str) -> &'b Parser<'a, 'b> {
    debugln!("fn=parser_of;sc={}", sc);
    if sc == p.meta.bin_name.as_ref().unwrap_or(&String::new()) {
        return p;
    }
    &p.find_subcommand(sc).expect(INTERNAL_ERROR_MSG).p
}

// Writes out the args section, which ends up being the flags and opts, and a jump to
// another ZSH function if there are positional args or subcommands.
// The structer works like this:
//    ([conflicting_args]) [multiple] arg [takes_value] [[help]] [: :(possible_values)]
//       ^-- list '-v -h'    ^--'*'          ^--'+'                   ^-- list 'one two three'
//
// An example from the rustup command:
//
// _arguments -C -s -S \
// 		'(-h --help --verbose)-v[Enable verbose output]' \
// 		'(-V -v --version --verbose --help)-h[Prints help information]' \
//      # ... snip for brevity
// 		'1:: :_rustup_commands' \   # <-- displays positional args and subcommands
// 		'*:: :->rustup' \           # <-- displays subcommand args and child subcommands
// 	&& ret=0
//
// The args used for _arguments are as follows:
//    -C: modify the $context internal variable
//    -s: Allow stacking of short args (i.e. -a -b -c => -abc)
//    -S: Do not complete anything after '--' and treat those as argument values
fn get_args_of(p: &Parser) -> String {
    debugln!("fn=get_args_of");
    let mut ret = vec![String::from("_arguments -s -S -C \\")];
    let opts = write_opts_of(p);
    let flags = write_flags_of(p);
    let sc_or_a = if p.has_subcommands() || p.has_positionals() {
        format!("\"1:: :_{name}_commands\" \\",
                name = p.meta.bin_name.as_ref().unwrap().replace(" ", "_"))
    } else {
        String::new()
    };
    let sc = if p.has_subcommands() {
        format!("\"*:: :->{name}\" \\", name = p.meta.name)
    } else {
        String::new()
    };

    if !opts.is_empty() {
        ret.push(opts);
    }
    if !flags.is_empty() {
        ret.push(flags);
    }
    if !sc_or_a.is_empty() {
        ret.push(sc_or_a);
    }
    if !sc.is_empty() {
        ret.push(sc);
    }
    ret.push(String::from("&& ret=0"));

    ret.join("\n")
}

fn write_opts_of(p: &Parser) -> String {
    debugln!("fn=write_opts_of;");
    let mut ret = vec![];
    for o in p.opts() {
        debugln!("iter;o={}", o.name());
        let help = o.help().unwrap_or("");
        let mut conflicts = get_zsh_arg_conflicts!(p, o, INTERNAL_ERROR_MSG);
        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if o.is_set(ArgSettings::Multiple) {
            "*"
        } else {
            ""
        };
        let pv = if let Some(pv_vec) = o.possible_vals() {
            format!(": :({})", pv_vec.join(" "))
        } else {
            String::new()
        };
        if let Some(short) = o.short() {
            let s = format!("\"{conflicts}{multiple}-{arg}+[{help}]{possible_values}\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = short,
                possible_values = pv,
                help = help);

            debugln!("Wrote...{}", &*s);
            ret.push(s);
        }
        if let Some(long) = o.long() {
            let l = format!("\"{conflicts}{multiple}--{arg}+[{help}]{possible_values}\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                possible_values = pv,
                help = help);

            debugln!("Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}

fn write_flags_of(p: &Parser) -> String {
    debugln!("fn=write_flags_of;");
    let mut ret = vec![];
    for f in p.flags() {
        debugln!("iter;f={}", f.name());
        let help = f.help().unwrap_or("");
        let mut conflicts = get_zsh_arg_conflicts!(p, f, INTERNAL_ERROR_MSG);
        conflicts = if conflicts.is_empty() {
            String::new()
        } else {
            format!("({})", conflicts)
        };

        let multiple = if f.is_set(ArgSettings::Multiple) {
            "*"
        } else {
            ""
        };
        if let Some(short) = f.short() {
            let s = format!("\"{conflicts}{multiple}-{arg}[{help}]\" \\",
                multiple = multiple,
                conflicts = conflicts,
                arg = short,
                help = help);

            debugln!("Wrote...{}", &*s);
            ret.push(s);
        }

        if let Some(long) = f.long() {
            let l = format!("\"{conflicts}{multiple}--{arg}[{help}]\" \\",
                conflicts = conflicts,
                multiple = multiple,
                arg = long,
                help = help);

            debugln!("Wrote...{}", &*l);
            ret.push(l);
        }
    }

    ret.join("\n")
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc::{declare_lint, lint_array};
use rustc::hir::{Expr, ExprKind};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};

/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
/// `Drop`.
///
/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its
/// destructor, possibly causing leaks.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// mem::forget(Rc::new(55)))
/// ```
declare_clippy_lint! {
    pub MEM_FORGET,
    restriction,
    "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
}

pub struct MemForget;

impl LintPass for MemForget {
    fn get_lints(&self) -> LintArray {
        lint_array![MEM_FORGET]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Call(ref path_expr, ref args) = e.node {
            if let ExprKind::Path(ref qpath) = path_expr.node {
                if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) {
                    if match_def_path(cx.tcx, def_id, &paths::MEM_FORGET) {
                        let forgot_ty = cx.tables.expr_ty(&args[0]);

                        if match forgot_ty.ty_adt_def() {
                            Some(def) => def.has_dtor(cx.tcx),
                            _ => false,
                        } {
                            span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Use Option::map_or<commit_after>use rustc::lint::*;
use rustc::{declare_lint, lint_array};
use rustc::hir::{Expr, ExprKind};
use crate::utils::{match_def_path, opt_def_id, paths, span_lint};

/// **What it does:** Checks for usage of `std::mem::forget(t)` where `t` is
/// `Drop`.
///
/// **Why is this bad?** `std::mem::forget(t)` prevents `t` from running its
/// destructor, possibly causing leaks.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// mem::forget(Rc::new(55)))
/// ```
declare_clippy_lint! {
    pub MEM_FORGET,
    restriction,
    "`mem::forget` usage on `Drop` types, likely to cause memory leaks"
}

pub struct MemForget;

impl LintPass for MemForget {
    fn get_lints(&self) -> LintArray {
        lint_array![MEM_FORGET]
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemForget {
    fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, e: &'tcx Expr) {
        if let ExprKind::Call(ref path_expr, ref args) = e.node {
            if let ExprKind::Path(ref qpath) = path_expr.node {
                if let Some(def_id) = opt_def_id(cx.tables.qpath_def(qpath, path_expr.hir_id)) {
                    if match_def_path(cx.tcx, def_id, &paths::MEM_FORGET) {
                        let forgot_ty = cx.tables.expr_ty(&args[0]);

                        if forgot_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
                            span_lint(cx, MEM_FORGET, e.span, "usage of mem::forget on Drop type");
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>