<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSObject, JSString, JSGCTraceKind, JSTRACE_OBJECT, JSTRACE_STRING};

use libc::c_void;
use std::mem;

static JSVAL_TAG_SHIFT: int = 47;

#[repr(u8)]
enum ValueType {
    JSVAL_TYPE_DOUBLE              = 0x00,
    JSVAL_TYPE_INT32               = 0x01,
    JSVAL_TYPE_UNDEFINED           = 0x02,
    JSVAL_TYPE_BOOLEAN             = 0x03,
    JSVAL_TYPE_MAGIC               = 0x04,
    JSVAL_TYPE_STRING              = 0x05,
    JSVAL_TYPE_NULL                = 0x06,
    JSVAL_TYPE_OBJECT              = 0x07,

    /* These never appear in a jsval; they are only provided as an out-of-band value. */
    JSVAL_TYPE_UNKNOWN             = 0x20,
    JSVAL_TYPE_MISSING             = 0x21
}

static JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32;

#[repr(u32)]
enum ValueTag {
    JSVAL_TAG_DOUBLE               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_DOUBLE as u32),
    JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_INT32 as u32),
    JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_UNDEFINED as u32),
    JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_STRING as u32),
    JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_BOOLEAN as u32),
    JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_MAGIC as u32),
    JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_NULL as u32),
    JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_OBJECT as u32),
}

#[repr(u64)]
enum ValueShiftedTag {
    JSVAL_SHIFTED_TAG_MAX_DOUBLE   = (((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64),
    JSVAL_SHIFTED_TAG_INT32        = ((JSVAL_TAG_INT32 as u64)      << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_UNDEFINED    = ((JSVAL_TAG_UNDEFINED as u64)  << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_STRING       = ((JSVAL_TAG_STRING as u64)     << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_BOOLEAN      = ((JSVAL_TAG_BOOLEAN as u64)    << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_MAGIC        = ((JSVAL_TAG_MAGIC as u64)      << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_NULL         = ((JSVAL_TAG_NULL as u64)       << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_OBJECT       = ((JSVAL_TAG_OBJECT as u64)     << JSVAL_TAG_SHIFT)
}

static JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF;

// JSVal was originally type of u64.
// now this become {u64} because of the union abi issue on ARM arch. See #398.
#[deriving(Eq,Clone)]
pub struct JSVal {
    pub v: u64
}

#[inline(always)]
fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal {
    JSVal {
        v: ((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload
    }
}

#[inline(always)]
pub fn NullValue() -> JSVal {
    BuildJSVal(JSVAL_TAG_NULL, 0)
}

#[inline(always)]
pub fn UndefinedValue() -> JSVal {
    BuildJSVal(JSVAL_TAG_UNDEFINED, 0)
}

#[inline(always)]
pub fn Int32Value(i: i32) -> JSVal {
    BuildJSVal(JSVAL_TAG_INT32, i as u32 as u64)
}

#[inline(always)]
pub fn DoubleValue(f: f64) -> JSVal {
    let bits: u64 = unsafe { mem::transmute(f) };
    assert!(bits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE as u64)
    JSVal {
        v: bits
    }
}

#[inline(always)]
pub fn UInt32Value(ui: u32) -> JSVal {
    if ui > 0x7fffffff {
        DoubleValue(ui as f64)
    } else {
        Int32Value(ui as i32)
    }
}

#[inline(always)]
pub fn StringValue(s: &JSString) -> JSVal {
    let bits = s as *JSString as uint as u64;
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
    BuildJSVal(JSVAL_TAG_STRING, bits)
}

#[inline(always)]
pub fn BooleanValue(b: bool) -> JSVal {
    BuildJSVal(JSVAL_TAG_BOOLEAN, b as u64)
}

#[inline(always)]
pub fn ObjectValue(o: &JSObject) -> JSVal {
    let bits = o as *JSObject as uint as u64;
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
    BuildJSVal(JSVAL_TAG_OBJECT, bits)
}

#[inline(always)]
pub fn ObjectOrNullValue(o: *mut JSObject) -> JSVal {
    if o.is_null() {
        NullValue()
    } else {
        ObjectValue(unsafe { &*o })
    }
}

#[inline(always)]
pub fn PrivateValue(o: *c_void) -> JSVal {
    let ptrBits = o as uint as u64;
    assert!((ptrBits & 1) == 0);
    JSVal {
        v: ptrBits >> 1
    }
}

impl JSVal {
    pub fn is_undefined(&self) -> bool {
        self.v == JSVAL_SHIFTED_TAG_UNDEFINED as u64
    }

    pub fn is_null(&self) -> bool {
        self.v == JSVAL_SHIFTED_TAG_NULL as u64
    }

    pub fn is_null_or_undefined(&self) -> bool {
        self.is_null() || self.is_undefined()
    }

    pub fn is_double(&self) -> bool {
        self.v <= JSVAL_SHIFTED_TAG_MAX_DOUBLE as u64
    }

    pub fn is_primitive(&self) -> bool {
        static JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = JSVAL_SHIFTED_TAG_OBJECT as u64;
        self.v < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET
    }

    pub fn is_string(&self) -> bool {
        (self.v >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING as u64
    }

    pub fn is_object(&self) -> bool {
        assert!((self.v >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT as u64);
        self.v >= JSVAL_SHIFTED_TAG_OBJECT as u64
    }

    pub fn to_object(&self) -> *mut JSObject {
        assert!(self.is_object());
        self.to_object_or_null()
    }

    pub fn is_object_or_null(&self) -> bool {
        static JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET: u64 = JSVAL_SHIFTED_TAG_NULL as u64;
        assert!((self.v >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT as u64);
        self.v >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET
    }

    pub fn to_object_or_null(&self) -> *mut JSObject {
        assert!(self.is_object_or_null());
        let ptrBits = self.v & JSVAL_PAYLOAD_MASK;
        assert!((ptrBits & 0x7) == 0);
        ptrBits as uint as *mut JSObject
    }

    pub fn to_private(&self) -> *c_void {
        assert!(self.is_double());
        assert!((self.v & 0x8000000000000000u64) == 0);
        (self.v << 1) as uint as *c_void
    }

    pub fn is_gcthing(&self) -> bool {
        static JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = JSVAL_SHIFTED_TAG_STRING as u64;
        self.v >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET
    }

    pub fn to_gcthing(&self) -> *mut c_void {
        assert!(self.is_gcthing());
        let ptrBits = self.v & JSVAL_PAYLOAD_MASK;
        assert!((ptrBits & 0x7) == 0);
        ptrBits as *mut c_void
    }

    pub fn is_markable(&self) -> bool {
        self.is_gcthing() && !self.is_null()
    }

    pub fn trace_kind(&self) -> JSGCTraceKind {
        assert!(self.is_markable());
        if self.is_object() {
            JSTRACE_OBJECT
        } else {
            JSTRACE_STRING
        }

    }
}
<commit_msg>Update Rust<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */

use jsapi::{JSObject, JSString, JSGCTraceKind, JSTRACE_OBJECT, JSTRACE_STRING};

use libc::c_void;
use std::mem;

static JSVAL_TAG_SHIFT: int = 47;

#[repr(u8)]
enum ValueType {
    JSVAL_TYPE_DOUBLE              = 0x00,
    JSVAL_TYPE_INT32               = 0x01,
    JSVAL_TYPE_UNDEFINED           = 0x02,
    JSVAL_TYPE_BOOLEAN             = 0x03,
    JSVAL_TYPE_MAGIC               = 0x04,
    JSVAL_TYPE_STRING              = 0x05,
    JSVAL_TYPE_NULL                = 0x06,
    JSVAL_TYPE_OBJECT              = 0x07,

    /* These never appear in a jsval; they are only provided as an out-of-band value. */
    JSVAL_TYPE_UNKNOWN             = 0x20,
    JSVAL_TYPE_MISSING             = 0x21
}

static JSVAL_TAG_MAX_DOUBLE: u32 = 0x1FFF0u32;

#[repr(u32)]
enum ValueTag {
    JSVAL_TAG_DOUBLE               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_DOUBLE as u32),
    JSVAL_TAG_INT32                = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_INT32 as u32),
    JSVAL_TAG_UNDEFINED            = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_UNDEFINED as u32),
    JSVAL_TAG_STRING               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_STRING as u32),
    JSVAL_TAG_BOOLEAN              = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_BOOLEAN as u32),
    JSVAL_TAG_MAGIC                = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_MAGIC as u32),
    JSVAL_TAG_NULL                 = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_NULL as u32),
    JSVAL_TAG_OBJECT               = JSVAL_TAG_MAX_DOUBLE | (JSVAL_TYPE_OBJECT as u32),
}

#[repr(u64)]
enum ValueShiftedTag {
    JSVAL_SHIFTED_TAG_MAX_DOUBLE   = (((JSVAL_TAG_MAX_DOUBLE as u64) << JSVAL_TAG_SHIFT) | 0xFFFFFFFFu64),
    JSVAL_SHIFTED_TAG_INT32        = ((JSVAL_TAG_INT32 as u64)      << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_UNDEFINED    = ((JSVAL_TAG_UNDEFINED as u64)  << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_STRING       = ((JSVAL_TAG_STRING as u64)     << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_BOOLEAN      = ((JSVAL_TAG_BOOLEAN as u64)    << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_MAGIC        = ((JSVAL_TAG_MAGIC as u64)      << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_NULL         = ((JSVAL_TAG_NULL as u64)       << JSVAL_TAG_SHIFT),
    JSVAL_SHIFTED_TAG_OBJECT       = ((JSVAL_TAG_OBJECT as u64)     << JSVAL_TAG_SHIFT)
}

static JSVAL_PAYLOAD_MASK: u64 = 0x00007FFFFFFFFFFF;

// JSVal was originally type of u64.
// now this become {u64} because of the union abi issue on ARM arch. See #398.
#[deriving(PartialEq,Clone)]
pub struct JSVal {
    pub v: u64
}

#[inline(always)]
fn BuildJSVal(tag: ValueTag, payload: u64) -> JSVal {
    JSVal {
        v: ((tag as u32 as u64) << JSVAL_TAG_SHIFT) | payload
    }
}

#[inline(always)]
pub fn NullValue() -> JSVal {
    BuildJSVal(JSVAL_TAG_NULL, 0)
}

#[inline(always)]
pub fn UndefinedValue() -> JSVal {
    BuildJSVal(JSVAL_TAG_UNDEFINED, 0)
}

#[inline(always)]
pub fn Int32Value(i: i32) -> JSVal {
    BuildJSVal(JSVAL_TAG_INT32, i as u32 as u64)
}

#[inline(always)]
pub fn DoubleValue(f: f64) -> JSVal {
    let bits: u64 = unsafe { mem::transmute(f) };
    assert!(bits <= JSVAL_SHIFTED_TAG_MAX_DOUBLE as u64)
    JSVal {
        v: bits
    }
}

#[inline(always)]
pub fn UInt32Value(ui: u32) -> JSVal {
    if ui > 0x7fffffff {
        DoubleValue(ui as f64)
    } else {
        Int32Value(ui as i32)
    }
}

#[inline(always)]
pub fn StringValue(s: &JSString) -> JSVal {
    let bits = s as *JSString as uint as u64;
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
    BuildJSVal(JSVAL_TAG_STRING, bits)
}

#[inline(always)]
pub fn BooleanValue(b: bool) -> JSVal {
    BuildJSVal(JSVAL_TAG_BOOLEAN, b as u64)
}

#[inline(always)]
pub fn ObjectValue(o: &JSObject) -> JSVal {
    let bits = o as *JSObject as uint as u64;
    assert!((bits >> JSVAL_TAG_SHIFT) == 0);
    BuildJSVal(JSVAL_TAG_OBJECT, bits)
}

#[inline(always)]
pub fn ObjectOrNullValue(o: *mut JSObject) -> JSVal {
    if o.is_null() {
        NullValue()
    } else {
        ObjectValue(unsafe { &*o })
    }
}

#[inline(always)]
pub fn PrivateValue(o: *c_void) -> JSVal {
    let ptrBits = o as uint as u64;
    assert!((ptrBits & 1) == 0);
    JSVal {
        v: ptrBits >> 1
    }
}

impl JSVal {
    pub fn is_undefined(&self) -> bool {
        self.v == JSVAL_SHIFTED_TAG_UNDEFINED as u64
    }

    pub fn is_null(&self) -> bool {
        self.v == JSVAL_SHIFTED_TAG_NULL as u64
    }

    pub fn is_null_or_undefined(&self) -> bool {
        self.is_null() || self.is_undefined()
    }

    pub fn is_double(&self) -> bool {
        self.v <= JSVAL_SHIFTED_TAG_MAX_DOUBLE as u64
    }

    pub fn is_primitive(&self) -> bool {
        static JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET: u64 = JSVAL_SHIFTED_TAG_OBJECT as u64;
        self.v < JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET
    }

    pub fn is_string(&self) -> bool {
        (self.v >> JSVAL_TAG_SHIFT) == JSVAL_TAG_STRING as u64
    }

    pub fn is_object(&self) -> bool {
        assert!((self.v >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT as u64);
        self.v >= JSVAL_SHIFTED_TAG_OBJECT as u64
    }

    pub fn to_object(&self) -> *mut JSObject {
        assert!(self.is_object());
        self.to_object_or_null()
    }

    pub fn is_object_or_null(&self) -> bool {
        static JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET: u64 = JSVAL_SHIFTED_TAG_NULL as u64;
        assert!((self.v >> JSVAL_TAG_SHIFT) <= JSVAL_TAG_OBJECT as u64);
        self.v >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET
    }

    pub fn to_object_or_null(&self) -> *mut JSObject {
        assert!(self.is_object_or_null());
        let ptrBits = self.v & JSVAL_PAYLOAD_MASK;
        assert!((ptrBits & 0x7) == 0);
        ptrBits as uint as *mut JSObject
    }

    pub fn to_private(&self) -> *c_void {
        assert!(self.is_double());
        assert!((self.v & 0x8000000000000000u64) == 0);
        (self.v << 1) as uint as *c_void
    }

    pub fn is_gcthing(&self) -> bool {
        static JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET: u64 = JSVAL_SHIFTED_TAG_STRING as u64;
        self.v >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET
    }

    pub fn to_gcthing(&self) -> *mut c_void {
        assert!(self.is_gcthing());
        let ptrBits = self.v & JSVAL_PAYLOAD_MASK;
        assert!((ptrBits & 0x7) == 0);
        ptrBits as *mut c_void
    }

    pub fn is_markable(&self) -> bool {
        self.is_gcthing() && !self.is_null()
    }

    pub fn trace_kind(&self) -> JSGCTraceKind {
        assert!(self.is_markable());
        if self.is_object() {
            JSTRACE_OBJECT
        } else {
            JSTRACE_STRING
        }

    }
}
<|endoftext|>


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

// ignore-windows failing on win32 bot
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
// min-gdb-version 7.7
// min-lldb-version: 310

// === GDB TESTS ===================================================================================

// gdb-command: run

// gdb-command: print slice
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}

// gdb-command: print vec
// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}

// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"

// gdb-command: print string
// gdb-check:$4 = "IAMA string!"

// gdb-command: print some
// gdb-check:$5 = Some = {8}

// gdb-command: print none
// gdbg-check:$6 = None
// gdbr-check:$6 = core::option::Option::None

// gdbr-command: print os_string
// gdbr-check:$7 = "IAMA OS string 😃"

// gdbr-command: print some_string
// gdbr-check:$8 = Some = {"IAMA optional string!"}

// === LLDB TESTS ==================================================================================

// lldb-command: run

// lldb-command: print slice
// lldb-check:[...]$0 = &[0, 1, 2, 3]

// lldb-command: print vec
// lldb-check:[...]$1 = vec![4, 5, 6, 7]

// lldb-command: print str_slice
// lldb-check:[...]$2 = "IAMA string slice!"

// lldb-command: print string
// lldb-check:[...]$3 = "IAMA string!"

// lldb-command: print some
// lldb-check:[...]$4 = Some(8)

// lldb-command: print none
// lldb-check:[...]$5 = None

#![allow(unused_variables)]
use std::ffi::OsString;

fn main() {

    // &[]
    let slice: &[i32] = &[0, 1, 2, 3];

    // Vec
    let vec = vec![4u64, 5, 6, 7];

    // &str
    let str_slice = "IAMA string slice!";

    // String
    let string = "IAMA string!".to_string();

    // OsString
    let os_string = OsString::from("IAMA OS string \u{1F603}");

    // Option
    let some = Some(8i16);
    let none: Option<i64> = None;

    let some_string = Some("IAMA optional string!".to_owned());

    zzz(); // #break
}

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

// ignore-windows failing on win32 bot
// ignore-freebsd: gdb package too new
// ignore-android: FIXME(#10381)
// compile-flags:-g
// min-gdb-version 7.7
// min-lldb-version: 310

// === GDB TESTS ===================================================================================

// gdb-command: run

// gdb-command: print slice
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}

// gdb-command: print vec
// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}

// gdb-command: print str_slice
// gdb-check:$3 = "IAMA string slice!"

// gdb-command: print string
// gdb-check:$4 = "IAMA string!"

// gdb-command: print some
// gdb-check:$5 = Some = {8}

// gdb-command: print none
// gdbg-check:$6 = None
// gdbr-check:$6 = core::option::Option::None

// gdb-command: print os_string
// gdb-check:$7 = "IAMA OS string 😃"

// gdb-command: print some_string
// gdb-check:$8 = Some = {"IAMA optional string!"}

// === LLDB TESTS ==================================================================================

// lldb-command: run

// lldb-command: print slice
// lldb-check:[...]$0 = &[0, 1, 2, 3]

// lldb-command: print vec
// lldb-check:[...]$1 = vec![4, 5, 6, 7]

// lldb-command: print str_slice
// lldb-check:[...]$2 = "IAMA string slice!"

// lldb-command: print string
// lldb-check:[...]$3 = "IAMA string!"

// lldb-command: print some
// lldb-check:[...]$4 = Some(8)

// lldb-command: print none
// lldb-check:[...]$5 = None

#![allow(unused_variables)]
use std::ffi::OsString;

fn main() {

    // &[]
    let slice: &[i32] = &[0, 1, 2, 3];

    // Vec
    let vec = vec![4u64, 5, 6, 7];

    // &str
    let str_slice = "IAMA string slice!";

    // String
    let string = "IAMA string!".to_string();

    // OsString
    let os_string = OsString::from("IAMA OS string \u{1F603}");

    // Option
    let some = Some(8i16);
    let none: Option<i64> = None;

    let some_string = Some("IAMA optional string!".to_owned());

    zzz(); // #break
}

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


<commit_before>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::io::stderr;
use std::io::IoError;
use std::io::ALL_PERMISSIONS;
use std::os::{set_exit_status, self_exe_path};
use std::path::BytesContainer;
use std::from_str::FromStr;
use std::io::fs::{copy, rmdir_recursive, mkdir, readdir, rename};
use std::io::fs::{readlink, symlink, File};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::io::process::{Command, InheritFd, ExitStatus};

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::signal;
use lithos::sha256::{Sha256,Digest};

fn copy_dir(source: &Path, target: &Path) -> Result<(), IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let tmpdir = Path::new(target.dirname())
        .join(b".tmp.".to_vec() + target.filename().unwrap());
    if tmpdir.exists() {
        try!(rmdir_recursive(&tmpdir));
    }
    try!(mkdir(&tmpdir, ALL_PERMISSIONS));
    for file in try!(readdir(source))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        try!(copy(&file, &tmpdir.join(file.filename().unwrap())));
    }
    try!(rename(&tmpdir, target));
    return Ok(());
}

fn hash_dir(dir: &Path) -> Result<String, IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut hash = Sha256::new();
    let mut files: Vec<Path> = try!(readdir(dir))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
        .collect();
    files.sort();
    for file in files.iter() {
        hash.input(file.container_as_bytes());
        hash.input(b"\x00");
        hash.input(try!(try!(File::open(file)).read_to_end()).as_slice());
        hash.input(b"\x00");
    }
    return Ok(hash.result_str().as_slice().slice_to(8).to_string());
}

fn switch_config(master_cfg: Path, tree_name: String, config_dir: Path,
    name_prefix: Option<String>)
    -> Result<(), String>
{
    match Command::new(self_exe_path().unwrap().join("lithos_check"))
        .stdin(InheritFd(0))
        .stdout(InheritFd(1))
        .stderr(InheritFd(2))
        .arg("--config")
        .arg(&master_cfg)
        .arg("--tree")
        .arg(tree_name.as_slice())
        .arg("--config-dir")
        .arg(&config_dir)
        .output()
    {
        Ok(ref po) if po.status == ExitStatus(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let tree_fn = master.config_dir.join(tree_name + ".yaml");
    let tree: TreeConfig = match parse_config(&tree_fn,
        &*TreeConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse tree config: {}", e));
        }
    };

    let config_fn = if let Some(prefix) = name_prefix {
        prefix.to_string() + try!(hash_dir(&config_dir)
            .map_err(|e| format!("Can't read dir: {}", e)))
    } else {
        config_dir.filename_str().unwrap().to_string()
    };
    let target_fn = Path::new(tree.config_dir.dirname())
                    .join(config_fn.as_slice());
    if target_fn == tree.config_dir {
        return Err(format!(concat!(
            "Target config dir ({}) is the current dir ({}). ",
            "You must have unique name for each new configuration"),
            target_fn.display(), tree.config_dir.display()));
    }
    let lnk = readlink(&tree.config_dir);
    match lnk.as_ref().map(|f| f.dirname()) {
        Ok(b".") => {},
        _ => return Err(format!(concat!(
            "The path {} must be a directory which points to the directory ",
            "at the same level of hierarchy."), tree.config_dir.display())),
    };
    if lnk.unwrap().filename() == target_fn.filename() {
        warn!("Target config dir is the active one. Nothing to do.");
        return Ok(());
    }
    if target_fn.exists() {
        warn!(concat!("Target directory {} exists. ",
            "Probably already copied. Skipping copying step."),
            target_fn.display());
    } else {
        info!("Seems everything nice. Copying");
        match copy_dir(&config_dir, &target_fn) {
            Ok(()) => {}
            Err(e) => return Err(format!("Error copying config dir: {}", e)),
        }
    }
    info!("Ok files are there. Making symlink");
    let symlink_fn = tree.config_dir.with_filename(
        b".tmp.".to_vec() + tree.config_dir.filename().unwrap());
    try!(symlink(&Path::new(config_fn.as_slice()), &symlink_fn)
        .map_err(|e| format!("Error symlinking dir: {}", e)));
    try!(rename(&symlink_fn, &tree.config_dir)
        .map_err(|e| format!("Error replacing symlink: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    match File::open(&pid_file)
            .and_then(|mut f| f.read_to_string())
            .ok()
            .and_then(|s| FromStr::from_str(s.as_slice())) {
        Some(pid) if signal::is_process_alive(pid) => {
            signal::send_signal(pid, signal::SIGQUIT as int);
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut name_prefix = None;
    let mut config_dir = Path::new("");
    let mut tree_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut name_prefix)
          .add_option(["--hashed-name"], box StoreOption::<String>, "
            Do not last component of DIR as a name, but create an unique name
            based on the PREFIX and hash of the contents.
            ")
          .metavar("PREFIX");
        ap.refer(&mut tree_name)
          .add_argument("tree", box Store::<String>,
            "Name of the tree which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_dir)
          .add_argument("dir", box Store::<Path>, "
            Name of the configuration directory to switch to. It doesn't
            have to be a directory inside `config-dir`, and it will be copied
            there. However, if directory with the same name exists in the
            `config-dir` it's assumed that it's already copied and will not
            be updated. Be sure to use unique directory for each deployment.
            ")
          .required();
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match switch_config(master_config, tree_name, config_dir, name_prefix) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<commit_msg>Fixed typo in error message<commit_after>#![feature(phase, macro_rules, if_let)]

extern crate serialize;
extern crate libc;
#[phase(plugin, link)] extern crate log;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;
extern crate time;
extern crate debug;

extern crate argparse;
extern crate quire;
#[phase(plugin, link)] extern crate lithos;

use std::io::stderr;
use std::io::IoError;
use std::io::ALL_PERMISSIONS;
use std::os::{set_exit_status, self_exe_path};
use std::path::BytesContainer;
use std::from_str::FromStr;
use std::io::fs::{copy, rmdir_recursive, mkdir, readdir, rename};
use std::io::fs::{readlink, symlink, File};
use std::io::fs::PathExtensions;
use std::default::Default;
use std::io::process::{Command, InheritFd, ExitStatus};

use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use quire::parse_config;

use lithos::master_config::MasterConfig;
use lithos::tree_config::TreeConfig;
use lithos::signal;
use lithos::sha256::{Sha256,Digest};

fn copy_dir(source: &Path, target: &Path) -> Result<(), IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let tmpdir = Path::new(target.dirname())
        .join(b".tmp.".to_vec() + target.filename().unwrap());
    if tmpdir.exists() {
        try!(rmdir_recursive(&tmpdir));
    }
    try!(mkdir(&tmpdir, ALL_PERMISSIONS));
    for file in try!(readdir(source))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
    {
        try!(copy(&file, &tmpdir.join(file.filename().unwrap())));
    }
    try!(rename(&tmpdir, target));
    return Ok(());
}

fn hash_dir(dir: &Path) -> Result<String, IoError> {
    let name_re = regex!(r"^([\w-]+)\.yaml$");
    let mut hash = Sha256::new();
    let mut files: Vec<Path> = try!(readdir(dir))
        .into_iter()
        .filter(|f| f.filename_str()
                     .map(|s| name_re.is_match(s))
                     .unwrap_or(false))
        .collect();
    files.sort();
    for file in files.iter() {
        hash.input(file.container_as_bytes());
        hash.input(b"\x00");
        hash.input(try!(try!(File::open(file)).read_to_end()).as_slice());
        hash.input(b"\x00");
    }
    return Ok(hash.result_str().as_slice().slice_to(8).to_string());
}

fn switch_config(master_cfg: Path, tree_name: String, config_dir: Path,
    name_prefix: Option<String>)
    -> Result<(), String>
{
    match Command::new(self_exe_path().unwrap().join("lithos_check"))
        .stdin(InheritFd(0))
        .stdout(InheritFd(1))
        .stderr(InheritFd(2))
        .arg("--config")
        .arg(&master_cfg)
        .arg("--tree")
        .arg(tree_name.as_slice())
        .arg("--config-dir")
        .arg(&config_dir)
        .output()
    {
        Ok(ref po) if po.status == ExitStatus(0) => { }
        Ok(ref po) => {
            return Err(format!(
                "Configuration check failed with exit status: {}",
                po.status));
        }
        Err(e) => {
            return Err(format!("Can't check configuration: {}", e));
        }
    }
    info!("Checked. Proceeding");

    let master: MasterConfig = match parse_config(&master_cfg,
        &*MasterConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse master config: {}", e));
        }
    };
    let tree_fn = master.config_dir.join(tree_name + ".yaml");
    let tree: TreeConfig = match parse_config(&tree_fn,
        &*TreeConfig::validator(), Default::default())
    {
        Ok(cfg) => cfg,
        Err(e) => {
            return Err(format!("Can't parse tree config: {}", e));
        }
    };

    let config_fn = if let Some(prefix) = name_prefix {
        prefix.to_string() + try!(hash_dir(&config_dir)
            .map_err(|e| format!("Can't read dir: {}", e)))
    } else {
        config_dir.filename_str().unwrap().to_string()
    };
    let target_fn = Path::new(tree.config_dir.dirname())
                    .join(config_fn.as_slice());
    if target_fn == tree.config_dir {
        return Err(format!(concat!(
            "Target config dir ({}) is the current dir ({}). ",
            "You must have unique name for each new configuration"),
            target_fn.display(), tree.config_dir.display()));
    }
    let lnk = readlink(&tree.config_dir);
    match lnk.as_ref().map(|f| f.dirname()) {
        Ok(b".") => {},
        _ => return Err(format!(concat!(
            "The path {} must be a symlink which points to the directory ",
            "at the same level of hierarchy."), tree.config_dir.display())),
    };
    if lnk.unwrap().filename() == target_fn.filename() {
        warn!("Target config dir is the active one. Nothing to do.");
        return Ok(());
    }
    if target_fn.exists() {
        warn!(concat!("Target directory {} exists. ",
            "Probably already copied. Skipping copying step."),
            target_fn.display());
    } else {
        info!("Seems everything nice. Copying");
        match copy_dir(&config_dir, &target_fn) {
            Ok(()) => {}
            Err(e) => return Err(format!("Error copying config dir: {}", e)),
        }
    }
    info!("Ok files are there. Making symlink");
    let symlink_fn = tree.config_dir.with_filename(
        b".tmp.".to_vec() + tree.config_dir.filename().unwrap());
    try!(symlink(&Path::new(config_fn.as_slice()), &symlink_fn)
        .map_err(|e| format!("Error symlinking dir: {}", e)));
    try!(rename(&symlink_fn, &tree.config_dir)
        .map_err(|e| format!("Error replacing symlink: {}", e)));

    info!("Done. Sending SIGQUIT to lithos_tree");
    let pid_file = master.runtime_dir.join("master.pid");
    match File::open(&pid_file)
            .and_then(|mut f| f.read_to_string())
            .ok()
            .and_then(|s| FromStr::from_str(s.as_slice())) {
        Some(pid) if signal::is_process_alive(pid) => {
            signal::send_signal(pid, signal::SIGQUIT as int);
        }
        Some(pid) => {
            warn!("Process with pid {} is not running...", pid);
        }
        None => {
            warn!("Can't read pid file {}. Probably daemon is not running.",
                pid_file.display());
        }
    };

    return Ok(());
}

fn main() {
    let mut master_config = Path::new("/etc/lithos.yaml");
    let mut verbose = false;
    let mut name_prefix = None;
    let mut config_dir = Path::new("");
    let mut tree_name = "".to_string();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Checks if lithos configuration is ok");
        ap.refer(&mut master_config)
          .add_option(["--master"], box Store::<Path>,
            "Name of the master configuration file (default /etc/lithos.yaml)")
          .metavar("FILE");
        ap.refer(&mut verbose)
          .add_option(["-v", "--verbose"], box StoreTrue,
            "Verbose configuration");
        ap.refer(&mut name_prefix)
          .add_option(["--hashed-name"], box StoreOption::<String>, "
            Do not last component of DIR as a name, but create an unique name
            based on the PREFIX and hash of the contents.
            ")
          .metavar("PREFIX");
        ap.refer(&mut tree_name)
          .add_argument("tree", box Store::<String>,
            "Name of the tree which configuration will be switched for")
          .required()
          .metavar("NAME");
        ap.refer(&mut config_dir)
          .add_argument("dir", box Store::<Path>, "
            Name of the configuration directory to switch to. It doesn't
            have to be a directory inside `config-dir`, and it will be copied
            there. However, if directory with the same name exists in the
            `config-dir` it's assumed that it's already copied and will not
            be updated. Be sure to use unique directory for each deployment.
            ")
          .required();
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                set_exit_status(x);
                return;
            }
        }
    }
    match switch_config(master_config, tree_name, config_dir, name_prefix) {
        Ok(()) => {
            set_exit_status(0);
        }
        Err(e) => {
            (write!(stderr(), "Fatal error: {}\n", e)).ok();
            set_exit_status(1);
        }
    }
}
<|endoftext|>


<commit_before>use super::*;

#[test]
fn inner_item_smoke() {
    check_at(
        r#"
//- /lib.rs
struct inner {}
fn outer() {
    $0
    fn inner() {}
}
"#,
        expect![[r#"
            block scope
            inner: v
            crate
            inner: t
            outer: v
        "#]],
    );
}

#[test]
fn use_from_crate() {
    check_at(
        r#"
//- /lib.rs
struct Struct;
fn outer() {
    use Struct;
    use crate::Struct as CrateStruct;
    use self::Struct as SelfStruct;
    $0
}
"#,
        expect![[r#"
            block scope
            CrateStruct: t v
            SelfStruct: t v
            Struct: t v
            crate
            Struct: t v
            outer: v
        "#]],
    );
}
<commit_msg>Add test that merges inner and outer names<commit_after>use super::*;

#[test]
fn inner_item_smoke() {
    check_at(
        r#"
//- /lib.rs
struct inner {}
fn outer() {
    $0
    fn inner() {}
}
"#,
        expect![[r#"
            block scope
            inner: v
            crate
            inner: t
            outer: v
        "#]],
    );
}

#[test]
fn use_from_crate() {
    check_at(
        r#"
//- /lib.rs
struct Struct;
fn outer() {
    use Struct;
    use crate::Struct as CrateStruct;
    use self::Struct as SelfStruct;
    $0
}
"#,
        expect![[r#"
            block scope
            CrateStruct: t v
            SelfStruct: t v
            Struct: t v
            crate
            Struct: t v
            outer: v
        "#]],
    );
}

#[test]
fn merge_namespaces() {
    check_at(
        r#"
//- /lib.rs
struct name {}
fn outer() {
    fn name() {}

    use name as imported; // should import both `name`s

    $0
}
"#,
        expect![[r#"
            block scope
            imported: t v
            name: v
            crate
            name: t
            outer: v
        "#]],
    );
}
<|endoftext|>


<commit_before>use super::*;

pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
    let m;
    if p.at(T![::]) && p.nth(2) == T![<] {
        m = p.start();
        p.bump(T![::]);
        p.bump(T![<]);
    } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
        m = p.start();
        p.bump(T![<]);
    } else {
        return;
    }

    while !p.at(EOF) && !p.at(T![>]) {
        generic_arg(p);
        if !p.at(T![>]) && !p.expect(T![,]) {
            break;
        }
    }
    p.expect(T![>]);
    m.complete(p, GENERIC_ARG_LIST);
}

// test type_arg
// type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;
fn generic_arg(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        LIFETIME_IDENT => {
            lifetime(p);
            m.complete(p, LIFETIME_ARG);
        }
        // test associated_type_bounds
        // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => {
            let path_ty = p.start();
            let path = p.start();
            let path_seg = p.start();
            name_ref(p);
            opt_generic_arg_list(p, false);
            match p.current() {
                // NameRef<...> =
                T![=] => {
                    p.bump_any();
                    types::type_(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                T![:] if p.at(T![::]) => {
                    // NameRef::, this is a path type
                    path_seg.complete(p, PATH_SEGMENT);
                    let qual = path.complete(p, PATH);
                    opt_generic_arg_list(p, false);
                    paths::type_path_for_qualifier(p, qual);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
                // NameRef<...>:
                T![:] => {
                    generic_params::bounds(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                // NameRef, this is a single segment path type
                _ => {
                    path_seg.complete(p, PATH_SEGMENT);
                    path.complete(p, PATH);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
            }
        }
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        // test const_generic_negated_literal
        // fn f() { S::<-1> }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            types::type_(p);
            m.complete(p, TYPE_ARG);
        }
    }
}

pub(super) fn const_arg(p: &mut Parser) {
    let m = p.start();
    // FIXME: duplicates the code above
    match p.current() {
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            let lm = p.start();
            paths::use_path(p);
            lm.complete(p, PATH_EXPR);
            m.complete(p, CONST_ARG);
        }
    }
}
<commit_msg>minor: reduce duplication<commit_after>use super::*;

pub(super) fn opt_generic_arg_list(p: &mut Parser, colon_colon_required: bool) {
    let m;
    if p.at(T![::]) && p.nth(2) == T![<] {
        m = p.start();
        p.bump(T![::]);
        p.bump(T![<]);
    } else if !colon_colon_required && p.at(T![<]) && p.nth(1) != T![=] {
        m = p.start();
        p.bump(T![<]);
    } else {
        return;
    }

    while !p.at(EOF) && !p.at(T![>]) {
        generic_arg(p);
        if !p.at(T![>]) && !p.expect(T![,]) {
            break;
        }
    }
    p.expect(T![>]);
    m.complete(p, GENERIC_ARG_LIST);
}

// test type_arg
// type A = B<'static, i32, 1, { 2 }, Item=u64, true, false>;
fn generic_arg(p: &mut Parser) {
    match p.current() {
        LIFETIME_IDENT => {
            let m = p.start();
            lifetime(p);
            m.complete(p, LIFETIME_ARG);
        }
        // test associated_type_bounds
        // fn print_all<T: Iterator<Item, Item::Item, Item::<true>, Item: Display, Item<'a> = Item>>(printables: T) {}
        IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => {
            let m = p.start();
            let path_ty = p.start();
            let path = p.start();
            let path_seg = p.start();
            name_ref(p);
            opt_generic_arg_list(p, false);
            match p.current() {
                // NameRef<...> =
                T![=] => {
                    p.bump_any();
                    types::type_(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                T![:] if p.at(T![::]) => {
                    // NameRef::, this is a path type
                    path_seg.complete(p, PATH_SEGMENT);
                    let qual = path.complete(p, PATH);
                    opt_generic_arg_list(p, false);
                    paths::type_path_for_qualifier(p, qual);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
                // NameRef<...>:
                T![:] => {
                    generic_params::bounds(p);

                    path_seg.abandon(p);
                    path.abandon(p);
                    path_ty.abandon(p);
                    m.complete(p, ASSOC_TYPE_ARG);
                }
                // NameRef, this is a single segment path type
                _ => {
                    path_seg.complete(p, PATH_SEGMENT);
                    path.complete(p, PATH);
                    path_ty.complete(p, PATH_TYPE);
                    m.complete(p, TYPE_ARG);
                }
            }
        }
        // test const_generic_negated_literal
        // fn f() { S::<-1> }
        T!['{'] | T![true] | T![false] | T![-] => const_arg(p),
        k if k.is_literal() => const_arg(p),
        _ => {
            let m = p.start();
            types::type_(p);
            m.complete(p, TYPE_ARG);
        }
    }
}

pub(super) fn const_arg(p: &mut Parser) {
    let m = p.start();
    match p.current() {
        T!['{'] => {
            expressions::block_expr(p);
            m.complete(p, CONST_ARG);
        }
        k if k.is_literal() => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![true] | T![false] => {
            expressions::literal(p);
            m.complete(p, CONST_ARG);
        }
        T![-] => {
            let lm = p.start();
            p.bump(T![-]);
            expressions::literal(p);
            lm.complete(p, PREFIX_EXPR);
            m.complete(p, CONST_ARG);
        }
        _ => {
            let lm = p.start();
            paths::use_path(p);
            lm.complete(p, PATH_EXPR);
            m.complete(p, CONST_ARG);
        }
    }
}
<|endoftext|>


<commit_before>//! Handle network connections for a varlink service

//#![feature(getpid)]
//use std::process;
// FIXME
use libc::getpid;
use std::env;
use std::fs;
use std::io::{Read, Write};
use std::net::{Shutdown, TcpListener, TcpStream};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixListener as AbstractUnixListener;

use {ErrorKind, Result};

#[derive(Debug)]
enum VarlinkListener {
    TCP(TcpListener),
    UNIX(UnixListener),
}

#[derive(Debug)]
enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream),
}

impl<'a> VarlinkStream {
    pub fn split(&mut self) -> Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }
    pub fn shutdown(&mut self) -> Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both)?,
            VarlinkStream::UNIX(ref mut s) => s.shutdown(Shutdown::Both)?,
        }
        Ok(())
    }
}

fn activation_listener() -> Result<Option<i32>> {
    let nfds: u32;

    match env::var("LISTEN_FDS") {
        Ok(ref n) => match n.parse::<u32>() {
            Ok(n) if n >= 1 => nfds = n,
            _ => return Ok(None),
        },
        _ => return Ok(None),
    }

    unsafe {
        match env::var("LISTEN_PID") {
            //FIXME: replace Ok(getpid()) with Ok(process::id())
            Ok(ref pid) if pid.parse::<i32>() == Ok(getpid()) => {}
            _ => return Ok(None),
        }
    }

    if nfds == 1 {
        return Ok(Some(3));
    }

    let fdnames: String;

    match env::var("LISTEN_FDNAMES") {
        Ok(n) => {
            fdnames = n;
        }
        _ => return Ok(None),
    }

    for (i, v) in fdnames.split(":").enumerate() {
        if v == "varlink" {
            return Ok(Some(3 + i as i32));
        }
    }

    Ok(None)
}

//FIXME: add Drop with shutdown() and unix file removal
impl VarlinkListener {
    pub fn new<S: ?Sized + AsRef<str>>(address: &S, timeout: u64) -> Result<Self> {
        let address = address.as_ref();
        if let Some(l) = activation_listener()? {
            if address.starts_with("tcp:") {
                unsafe {
                    let s = TcpStream::from_raw_fd(l);
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::TCP(TcpListener::from_raw_fd(
                        s.into_raw_fd(),
                    )));
                }
            } else if address.starts_with("unix:") {
                unsafe {
                    let s = UnixStream::from_raw_fd(l);
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::UNIX(UnixListener::from_raw_fd(
                        s.into_raw_fd(),
                    )));
                }
            } else {
                return Err(ErrorKind::InvalidAddress.into());
            }
        }

        if address.starts_with("tcp:") {
            let l = TcpListener::bind(&address[4..])?;
            unsafe {
                let s = TcpStream::from_raw_fd(l.into_raw_fd());
                if timeout != 0 {
                    s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                }
                Ok(VarlinkListener::TCP(TcpListener::from_raw_fd(
                    s.into_raw_fd(),
                )))
            }
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(";").next().unwrap());
            if addr.starts_with("@") {
                addr = addr.replacen("@", "\0", 1);
                let l = AbstractUnixListener::bind(addr)?;
                unsafe {
                    let s = UnixStream::from_raw_fd(l.into_raw_fd());
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::UNIX(UnixListener::from_raw_fd(
                        s.into_raw_fd(),
                    )));
                }
            }
            // ignore error on non-existant file
            let _ = fs::remove_file(&*addr);
            let l = UnixListener::bind(addr)?;
            unsafe {
                let s = UnixStream::from_raw_fd(l.into_raw_fd());
                if timeout != 0 {
                    s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                }
                Ok(VarlinkListener::UNIX(UnixListener::from_raw_fd(
                    s.into_raw_fd(),
                )))
            }
        } else {
            Err(ErrorKind::InvalidAddress.into())
        }
    }

    pub fn accept(&self) -> Result<VarlinkStream> {
        match self {
            &VarlinkListener::TCP(ref l) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::TCP(s))
            }
            &VarlinkListener::UNIX(ref l) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::UNIX(s))
            }
        }
    }
    pub fn set_nonblocking(&self, b: bool) -> Result<()> {
        match self {
            &VarlinkListener::TCP(ref l) => l.set_nonblocking(b)?,
            &VarlinkListener::UNIX(ref l) => l.set_nonblocking(b)?,
        }
        Ok(())
    }
}

impl Drop for VarlinkListener {
    fn drop(&mut self) {
        match *self {
            VarlinkListener::UNIX(ref listener) => {
                if let Ok(local_addr) = listener.local_addr() {
                    if let Some(path) = local_addr.as_pathname() {
                        let _ = fs::remove_file(path);
                    }
                }
            }
            _ => {}
        }
    }
}

enum Message {
    NewJob(Job),
    Terminate,
}

struct ThreadPool {
    workers: Vec<Worker>,
    sender: mpsc::Sender<Message>,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Job = Box<FnBox + Send + 'static>;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        for _ in 0..size {
            workers.push(Worker::new(Arc::clone(&receiver)));
        }

        ThreadPool { workers, sender }
    }

    pub fn execute<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);

        self.sender.send(Message::NewJob(job)).unwrap();
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        for worker in &mut self.workers {
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv().unwrap();

            match message {
                Message::NewJob(job) => {
                    job.call_box();
                }
                Message::Terminate => {
                    break;
                }
            }
        });

        Worker {
            thread: Some(thread),
        }
    }
}

/// `listen` creates a server, with `num_worker` threads listening on `varlink_uri`.
///
/// If an `accept_timeout` != 0 is specified, this function returns after the specified
/// amount of seconds, if no new connection is made in that time frame. It still waits for
/// all pending connections to finish.
///
///# Examples
///
///```
/// extern crate failure;
/// extern crate varlink;
/// use failure::Fail;
///
/// let service = varlink::VarlinkService::new(
///     "org.varlink",
///     "test service",
///     "0.1",
///     "http://varlink.org",
///     vec![/* Your varlink interfaces go here */],
/// );
///
/// if let Err(e) = varlink::listen(service, "unix:/tmp/test_listen_timeout", 10, 1) {
///     if e.kind() != varlink::ErrorKind::Timeout {
///         panic!("Error listen: {:?}", e.cause());
///     }
/// }
///```
///# Note
/// You don't have to use this simple server. With the `VarlinkService::handle()` method you
/// can implement your own server model using whatever framework you prefer.
pub fn listen<S: ?Sized + AsRef<str>>(
    service: ::VarlinkService,
    address: &S,
    workers: usize,
    accept_timeout: u64,
) -> Result<()> {
    let service = Arc::new(service);
    let listener = Arc::new(VarlinkListener::new(address, accept_timeout)?);
    listener.set_nonblocking(false)?;
    let pool = ThreadPool::new(workers);

    loop {
        let mut stream: VarlinkStream = match listener.accept() {
            Err(ref e) if e.kind() == ErrorKind::Io(::std::io::ErrorKind::WouldBlock) => {
                return Err(ErrorKind::Timeout.into());
            }
            r => r?,
        };
        let service = service.clone();

        pool.execute(move || {
            let (mut r, mut w) = stream.split().expect("Could not split stream");

            if let Err(_e) = service.handle(&mut r, &mut w) {
                //println!("Handle Error: {}", e);
                let _ = stream.shutdown();
            }
        });
    }
}
<commit_msg>add counter of busy workers for timeout<commit_after>//! Handle network connections for a varlink service

use {ErrorKind, Result};
//#![feature(getpid)]
//use std::process;
// FIXME
use libc::getpid;
use std::env;
use std::fs;
use std::io::{Read, Write};
use std::net::{Shutdown, TcpListener, TcpStream};
use std::os::unix::io::{FromRawFd, IntoRawFd};
use std::os::unix::net::{UnixListener, UnixStream};
use std::sync::RwLock;
use std::sync::mpsc;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
// FIXME: abstract unix domains sockets still not in std
// FIXME: https://github.com/rust-lang/rust/issues/14194
use unix_socket::UnixListener as AbstractUnixListener;

#[derive(Debug)]
enum VarlinkListener {
    TCP(Option<TcpListener>, bool),
    UNIX(Option<UnixListener>, bool),
}

#[derive(Debug)]
enum VarlinkStream {
    TCP(TcpStream),
    UNIX(UnixStream),
}

impl<'a> VarlinkStream {
    pub fn split(&mut self) -> Result<(Box<Read + Send + Sync>, Box<Write + Send + Sync>)> {
        match *self {
            VarlinkStream::TCP(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
            VarlinkStream::UNIX(ref mut s) => {
                Ok((Box::new(s.try_clone()?), Box::new(s.try_clone()?)))
            }
        }
    }
    pub fn shutdown(&mut self) -> Result<()> {
        match *self {
            VarlinkStream::TCP(ref mut s) => s.shutdown(Shutdown::Both)?,
            VarlinkStream::UNIX(ref mut s) => s.shutdown(Shutdown::Both)?,
        }
        Ok(())
    }
}

fn activation_listener() -> Result<Option<i32>> {
    let nfds: u32;

    match env::var("LISTEN_FDS") {
        Ok(ref n) => match n.parse::<u32>() {
            Ok(n) if n >= 1 => nfds = n,
            _ => return Ok(None),
        },
        _ => return Ok(None),
    }

    unsafe {
        match env::var("LISTEN_PID") {
            //FIXME: replace Ok(getpid()) with Ok(process::id())
            Ok(ref pid) if pid.parse::<i32>() == Ok(getpid()) => {}
            _ => return Ok(None),
        }
    }

    if nfds == 1 {
        return Ok(Some(3));
    }

    let fdnames: String;

    match env::var("LISTEN_FDNAMES") {
        Ok(n) => {
            fdnames = n;
        }
        _ => return Ok(None),
    }

    for (i, v) in fdnames.split(":").enumerate() {
        if v == "varlink" {
            return Ok(Some(3 + i as i32));
        }
    }

    Ok(None)
}

//FIXME: add Drop with shutdown() and unix file removal
impl VarlinkListener {
    pub fn new<S: ?Sized + AsRef<str>>(address: &S, timeout: u64) -> Result<Self> {
        let address = address.as_ref();
        if let Some(l) = activation_listener()? {
            if address.starts_with("tcp:") {
                unsafe {
                    let s = TcpStream::from_raw_fd(l);
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::TCP(
                        Some(TcpListener::from_raw_fd(s.into_raw_fd())),
                        true,
                    ));
                }
            } else if address.starts_with("unix:") {
                unsafe {
                    let s = UnixStream::from_raw_fd(l);
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(s.into_raw_fd())),
                        true,
                    ));
                }
            } else {
                return Err(ErrorKind::InvalidAddress.into());
            }
        }

        if address.starts_with("tcp:") {
            let l = TcpListener::bind(&address[4..])?;
            unsafe {
                let s = TcpStream::from_raw_fd(l.into_raw_fd());
                if timeout != 0 {
                    s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                }
                Ok(VarlinkListener::TCP(
                    Some(TcpListener::from_raw_fd(s.into_raw_fd())),
                    false,
                ))
            }
        } else if address.starts_with("unix:") {
            let mut addr = String::from(address[5..].split(";").next().unwrap());
            if addr.starts_with("@") {
                addr = addr.replacen("@", "\0", 1);
                let l = AbstractUnixListener::bind(addr)?;
                unsafe {
                    let s = UnixStream::from_raw_fd(l.into_raw_fd());
                    if timeout != 0 {
                        s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                    }
                    return Ok(VarlinkListener::UNIX(
                        Some(UnixListener::from_raw_fd(s.into_raw_fd())),
                        false,
                    ));
                }
            }
            // ignore error on non-existant file
            let _ = fs::remove_file(&*addr);
            let l = UnixListener::bind(addr)?;
            unsafe {
                let s = UnixStream::from_raw_fd(l.into_raw_fd());
                if timeout != 0 {
                    s.set_read_timeout(Some(Duration::from_secs(timeout)))?;
                }
                Ok(VarlinkListener::UNIX(
                    Some(UnixListener::from_raw_fd(s.into_raw_fd())),
                    false,
                ))
            }
        } else {
            Err(ErrorKind::InvalidAddress.into())
        }
    }

    pub fn accept(&self) -> Result<VarlinkStream> {
        match self {
            &VarlinkListener::TCP(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::TCP(s))
            }
            &VarlinkListener::UNIX(Some(ref l), _) => {
                let (mut s, _addr) = l.accept()?;
                Ok(VarlinkStream::UNIX(s))
            }
            _ => Err(ErrorKind::ConnectionClosed.into()),
        }
    }
    pub fn set_nonblocking(&self, b: bool) -> Result<()> {
        match self {
            &VarlinkListener::TCP(Some(ref l), _) => l.set_nonblocking(b)?,
            &VarlinkListener::UNIX(Some(ref l), _) => l.set_nonblocking(b)?,
            _ => Err(ErrorKind::ConnectionClosed)?,
        }
        Ok(())
    }
}

impl Drop for VarlinkListener {
    fn drop(&mut self) {
        match *self {
            VarlinkListener::UNIX(Some(ref listener), false) => {
                if let Ok(local_addr) = listener.local_addr() {
                    if let Some(path) = local_addr.as_pathname() {
                        let _ = fs::remove_file(path);
                    }
                }
            }
            VarlinkListener::UNIX(ref mut listener, true) => {
                if let Some(l) = listener.take() {
                    unsafe {
                        let s = UnixStream::from_raw_fd(l.into_raw_fd());
                        let _ = s.set_read_timeout(None);
                    }
                }
            }
            _ => {}
        }
    }
}

enum Message {
    NewJob(Job),
    Terminate,
}

struct ThreadPool {
    workers: Vec<Worker>,
    num_busy: Arc<RwLock<i64>>,
    sender: mpsc::Sender<Message>,
}

trait FnBox {
    fn call_box(self: Box<Self>);
}

impl<F: FnOnce()> FnBox for F {
    fn call_box(self: Box<F>) {
        (*self)()
    }
}

type Job = Box<FnBox + Send + 'static>;

impl ThreadPool {
    /// Create a new ThreadPool.
    ///
    /// The size is the number of threads in the pool.
    ///
    /// # Panics
    ///
    /// The `new` function will panic if the size is zero.
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);

        let (sender, receiver) = mpsc::channel();

        let receiver = Arc::new(Mutex::new(receiver));

        let mut workers = Vec::with_capacity(size);

        let num_busy = Arc::new(RwLock::new(0 as i64));

        for _ in 0..size {
            workers.push(Worker::new(Arc::clone(&receiver), Arc::clone(&num_busy)));
        }

        ThreadPool {
            workers,
            sender,
            num_busy,
        }
    }

    pub fn execute<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        let job = Box::new(f);

        self.sender.send(Message::NewJob(job)).unwrap();
    }

    pub fn num_busy(&self) -> i64 {
        let num_busy = self.num_busy.read().unwrap();
        *num_busy
    }
}

impl Drop for ThreadPool {
    fn drop(&mut self) {
        for _ in &mut self.workers {
            self.sender.send(Message::Terminate).unwrap();
        }

        for worker in &mut self.workers {
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}

struct Worker {
    thread: Option<thread::JoinHandle<()>>,
}

impl Worker {
    fn new(receiver: Arc<Mutex<mpsc::Receiver<Message>>>, num_busy: Arc<RwLock<i64>>) -> Worker {
        let thread = thread::spawn(move || loop {
            let message = receiver.lock().unwrap().recv().unwrap();

            match message {
                Message::NewJob(job) => {
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy += 1;
                    }
                    job.call_box();
                    {
                        let mut num_busy = num_busy.write().unwrap();
                        *num_busy -= 1;
                    }
                }
                Message::Terminate => {
                    break;
                }
            }
        });

        Worker {
            thread: Some(thread),
        }
    }
}

/// `listen` creates a server, with `num_worker` threads listening on `varlink_uri`.
///
/// If an `accept_timeout` != 0 is specified, this function returns after the specified
/// amount of seconds, if no new connection is made in that time frame. It still waits for
/// all pending connections to finish.
///
///# Examples
///
///```
/// extern crate failure;
/// extern crate varlink;
/// use failure::Fail;
///
/// let service = varlink::VarlinkService::new(
///     "org.varlink",
///     "test service",
///     "0.1",
///     "http://varlink.org",
///     vec![/* Your varlink interfaces go here */],
/// );
///
/// if let Err(e) = varlink::listen(service, "unix:/tmp/test_listen_timeout", 10, 1) {
///     if e.kind() != varlink::ErrorKind::Timeout {
///         panic!("Error listen: {:?}", e.cause());
///     }
/// }
///```
///# Note
/// You don't have to use this simple server. With the `VarlinkService::handle()` method you
/// can implement your own server model using whatever framework you prefer.
pub fn listen<S: ?Sized + AsRef<str>>(
    service: ::VarlinkService,
    address: &S,
    workers: usize,
    accept_timeout: u64,
) -> Result<()> {
    let service = Arc::new(service);
    let listener = Arc::new(VarlinkListener::new(address, accept_timeout)?);
    listener.set_nonblocking(false)?;
    let pool = ThreadPool::new(workers);

    loop {
        let mut stream: VarlinkStream = match listener.accept() {
            Err(ref e) if e.kind() == ErrorKind::Io(::std::io::ErrorKind::WouldBlock) => {
                if pool.num_busy() == 0 {
                    return Err(ErrorKind::Timeout.into());
                }
                continue;
            }
            r => r?,
        };
        let service = service.clone();

        pool.execute(move || {
            let (mut r, mut w) = stream.split().expect("Could not split stream");

            if let Err(_e) = service.handle(&mut r, &mut w) {
                //println!("Handle Error: {}", e);
                let _ = stream.shutdown();
            }
        });
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;

use anyhow::{anyhow, Result};
use config::Config;
use rand::Rng;
use serde_derive::{Deserialize, Serialize};

use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    pub port: String,
    pub secret: String,
    pub pueue_directory: String,
    pub use_unix_socket: bool,
    pub unix_socket_path: String,
}

/// All settings which are used by the client
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    pub read_local_logs: bool,
    pub print_remove_warnings: bool,
}

/// All settings which are used by the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    pub default_parallel_tasks: usize,
    #[serde(default = "pause_on_failure_default")]
    pub pause_on_failure: bool,
    pub callback: Option<String>,
    pub groups: HashMap<String, usize>,
}

fn pause_on_failure_default() -> bool {
    false
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub shared: Shared,
    pub client: Client,
    pub daemon: Daemon,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option.
    /// If a local config file already exists it is parsed and
    /// overwrites the default option values.
    /// The local config is located at "~/.config/pueue.yml".
    pub fn new() -> Result<Settings> {
        let mut config = Config::new();

        config.set_default("shared.port", "6924")?;
        config.set_default("shared.secret", gen_random_secret())?;
        config.set_default("shared.pueue_directory", default_pueue_path()?)?;
        config.set_default("shared.use_unix_socket", false)?;
        config.set_default("shared.unix_socket_path", get_unix_socket_path()?)?;

        // Client specific config
        config.set_default("client.read_local_logs", true)?;
        config.set_default("client.read_local_logs", false)?;

        // Daemon specific config
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.pause_on_failure", false)?;
        config.set_default("daemon.callback", None::<String>)?;
        config.set_default("daemon.groups", HashMap::<String, i64>::new())?;

        // Add in the home config file
        parse_config(&mut config)?;

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the configuration path.
    /// The file is written to the main configuration directory of the respective OS.
    pub fn save(&self) -> Result<()> {
        let config_path = default_config_directory()?.join("pueue.yml");
        let config_dir = config_path
            .parent()
            .ok_or_else(|| anyhow!("Couldn't resolve config dir"))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
fn parse_config(settings: &mut Config) -> Result<()> {
    //println!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        //println!("Checking path: {:?}", &path);
        if path.exists() {
            //println!("Parsing config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    Ok(())
}

/// Simple helper function to generate a random secret
fn gen_random_secret() -> String {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    const PASSWORD_LEN: usize = 20;
    let mut rng = rand::thread_rng();

    let secret: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0, CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();

    secret
}
<commit_msg>Fix config default<commit_after>use std::collections::HashMap;
use std::fs::{create_dir_all, File};
use std::io::prelude::*;

use anyhow::{anyhow, Result};
use config::Config;
use rand::Rng;
use serde_derive::{Deserialize, Serialize};

use crate::platform::directories::*;

/// All settings which are used by both, the client and the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Shared {
    pub port: String,
    pub secret: String,
    pub pueue_directory: String,
    pub use_unix_socket: bool,
    pub unix_socket_path: String,
}

/// All settings which are used by the client
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Client {
    pub read_local_logs: bool,
    pub print_remove_warnings: bool,
}

/// All settings which are used by the daemon
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Daemon {
    pub default_parallel_tasks: usize,
    #[serde(default = "pause_on_failure_default")]
    pub pause_on_failure: bool,
    pub callback: Option<String>,
    pub groups: HashMap<String, usize>,
}

fn pause_on_failure_default() -> bool {
    false
}

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Settings {
    pub shared: Shared,
    pub client: Client,
    pub daemon: Daemon,
}

impl Settings {
    /// This function creates a new configuration instance and
    /// populates it with default values for every option.
    /// If a local config file already exists it is parsed and
    /// overwrites the default option values.
    /// The local config is located at "~/.config/pueue.yml".
    pub fn new() -> Result<Settings> {
        let mut config = Config::new();

        config.set_default("shared.port", "6924")?;
        config.set_default("shared.secret", gen_random_secret())?;
        config.set_default("shared.pueue_directory", default_pueue_path()?)?;
        config.set_default("shared.use_unix_socket", false)?;
        config.set_default("shared.unix_socket_path", get_unix_socket_path()?)?;

        // Client specific config
        config.set_default("client.read_local_logs", true)?;
        config.set_default("client.print_remove_warnings", false)?;

        // Daemon specific config
        config.set_default("daemon.default_parallel_tasks", 1)?;
        config.set_default("daemon.pause_on_failure", false)?;
        config.set_default("daemon.callback", None::<String>)?;
        config.set_default("daemon.groups", HashMap::<String, i64>::new())?;

        // Add in the home config file
        parse_config(&mut config)?;

        // Try to can deserialize the entire configuration
        Ok(config.try_into()?)
    }

    /// Save the current configuration as a file to the configuration path.
    /// The file is written to the main configuration directory of the respective OS.
    pub fn save(&self) -> Result<()> {
        let config_path = default_config_directory()?.join("pueue.yml");
        let config_dir = config_path
            .parent()
            .ok_or_else(|| anyhow!("Couldn't resolve config dir"))?;

        // Create the config dir, if it doesn't exist yet
        if !config_dir.exists() {
            create_dir_all(config_dir)?;
        }

        let content = serde_yaml::to_string(self)?;
        let mut file = File::create(config_path)?;
        file.write_all(content.as_bytes())?;

        Ok(())
    }
}

/// Get all possible configuration paths and check if there are
/// configuration files at those locations.
/// All configs will be merged by importance.
fn parse_config(settings: &mut Config) -> Result<()> {
    //println!("Parsing config files");
    for directory in get_config_directories()?.into_iter() {
        let path = directory.join("pueue.yml");
        //println!("Checking path: {:?}", &path);
        if path.exists() {
            //println!("Parsing config file at: {:?}", path);
            let config_file = config::File::with_name(path.to_str().unwrap());
            settings.merge(config_file)?;
        }
    }

    Ok(())
}

/// Simple helper function to generate a random secret
fn gen_random_secret() -> String {
    const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                            abcdefghijklmnopqrstuvwxyz\
                            0123456789)(*&^%$#@!~";
    const PASSWORD_LEN: usize = 20;
    let mut rng = rand::thread_rng();

    let secret: String = (0..PASSWORD_LEN)
        .map(|_| {
            let idx = rng.gen_range(0, CHARSET.len());
            CHARSET[idx] as char
        })
        .collect();

    secret
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::path::Path;
use Pid;
use ProcessExt;

/// Enum describing the different status of a process.
#[derive(Clone, Copy, Debug)]
pub struct ProcessStatus;

/// Struct containing a process' information.
#[derive(Clone)]
pub struct Process {
    pid: Pid,
    parent: Option<Pid>,
}

impl ProcessExt for Process {
    fn new(pid: Pid, parent: Option<Pid>, _start_time: u64) -> Process {
        Process { pid, parent }
    }

    fn kill(&self, _signal: ::Signal) -> bool {
        false
    }

    fn name(&self) -> &str {
        ""
    }

    fn cmd(&self) -> &[String] {
        &[]
    }

    fn exe(&self) -> &Path {
        &Path::new("")
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &[]
    }

    fn cwd(&self) -> &Path {
        &Path::new("")
    }

    fn root(&self) -> &Path {
        &Path::new("")
    }

    fn memory(&self) -> u64 {
        0
    }

    fn virtual_memory(&self) -> u64 {
        0
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        ProcessStatus
    }

    fn start_time(&self) -> u64 {
        0
    }

    fn cpu_usage(&self) -> f32 {
        0.0
    }
}
<commit_msg>Update unknown targets API<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use std::path::Path;
use DiskUsage;
use Pid;
use ProcessExt;

/// Enum describing the different status of a process.
#[derive(Clone, Copy, Debug)]
pub struct ProcessStatus;

/// Struct containing a process' information.
#[derive(Clone)]
pub struct Process {
    pid: Pid,
    parent: Option<Pid>,
}

impl ProcessExt for Process {
    fn new(pid: Pid, parent: Option<Pid>, _start_time: u64) -> Process {
        Process { pid, parent }
    }

    fn kill(&self, _signal: ::Signal) -> bool {
        false
    }

    fn name(&self) -> &str {
        ""
    }

    fn cmd(&self) -> &[String] {
        &[]
    }

    fn exe(&self) -> &Path {
        &Path::new("")
    }

    fn pid(&self) -> Pid {
        self.pid
    }

    fn environ(&self) -> &[String] {
        &[]
    }

    fn cwd(&self) -> &Path {
        &Path::new("")
    }

    fn root(&self) -> &Path {
        &Path::new("")
    }

    fn memory(&self) -> u64 {
        0
    }

    fn virtual_memory(&self) -> u64 {
        0
    }

    fn parent(&self) -> Option<Pid> {
        self.parent
    }

    fn status(&self) -> ProcessStatus {
        ProcessStatus
    }

    fn start_time(&self) -> u64 {
        0
    }

    fn cpu_usage(&self) -> f32 {
        0.0
    }

    fn get_disk_usage(&self) -> DiskUsage {
        DiskUsage::default()
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use super::util::*;
use super::cluster::{Cluster, Simulator};
use super::transport_simulate::*;
use super::node::new_node_cluster;
use super::server::new_server_cluster;
use kvproto::eraftpb::MessageType;
use std::time::Duration;
use std::thread;

fn test_basic_transfer_leader<T: Simulator>(cluster: &mut Cluster<T>) {
    cluster.cfg.raft_store.raft_heartbeat_ticks = 20;
    let reserved_time = Duration::from_millis(cluster.cfg.raft_store.raft_base_tick_interval *
                                              cluster.cfg.raft_store.raft_heartbeat_ticks as u64);
    cluster.run();

    // transfer leader to (2, 2)
    cluster.must_transfer_leader(1, new_peer(2, 2));

    let mut region = cluster.get_region(b"k3");

    // check if transfer leader is fast enough.
    let admin_req = new_transfer_leader_cmd(new_peer(3, 3));
    let mut req = new_admin_request(1, region.get_region_epoch(), admin_req);
    req.mut_header().set_peer(new_peer(2, 2));
    cluster.call_command(req, Duration::from_secs(3)).unwrap();
    thread::sleep(reserved_time);
    assert_eq!(cluster.query_leader(3, 1), Some(new_peer(3, 3)));

    let mut req = new_request(region.get_id(),
                              region.take_region_epoch(),
                              vec![new_put_cmd(b"k3", b"v3")],
                              false);
    req.mut_header().set_peer(new_peer(3, 3));
    // transfer leader to (4, 4)
    cluster.must_transfer_leader(1, new_peer(4, 4));
    // send request to old leader (3, 3) directly and verify it fails
    let resp = cluster.call_command(req, Duration::from_secs(5)).unwrap();
    assert!(resp.get_header().get_error().has_not_leader());
}

#[test]
fn test_server_basic_transfer_leader() {
    let mut cluster = new_server_cluster(0, 5);
    test_basic_transfer_leader(&mut cluster);
}

#[test]
fn test_node_basic_transfer_leader() {
    let mut cluster = new_node_cluster(0, 5);
    test_basic_transfer_leader(&mut cluster);
}

fn test_pd_transfer_leader<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_rule();

    cluster.run();

    cluster.must_put(b"k", b"v");

    // call command on this leader directly, must successfully.
    let mut region = cluster.get_region(b"");
    let mut req = new_request(region.get_id(),
                              region.take_region_epoch(),
                              vec![new_get_cmd(b"k")],
                              false);

    for id in 1..4 {
        // select a new leader to transfer
        pd_client.set_rule(box move |_, peer| {
            if peer.get_id() == id {
                return None;
            }
            new_pd_transfer_leader(new_peer(id, id))
        });

        for _ in 0..100 {
            // reset leader and wait transfer successfully.
            cluster.reset_leader_of_region(1);

            sleep_ms(20);

            if let Some(leader) = cluster.leader_of_region(1) {
                if leader.get_id() == id {
                    break;
                }
            }
        }

        assert_eq!(cluster.leader_of_region(1), Some(new_peer(id, id)));
        req.mut_header().set_peer(new_peer(id, id));
        debug!("requesting {:?}", req);
        let resp = cluster.call_command(req.clone(), Duration::from_secs(5)).unwrap();
        assert!(!resp.get_header().has_error(), "{:?}", resp);
        assert_eq!(resp.get_responses()[0].get_get().get_value(), b"v");
    }
}

#[test]
fn test_server_pd_transfer_leader() {
    let mut cluster = new_server_cluster(0, 3);
    test_pd_transfer_leader(&mut cluster);
}

#[test]
fn test_node_pd_transfer_leader() {
    let mut cluster = new_node_cluster(0, 3);
    test_pd_transfer_leader(&mut cluster);
}

fn test_transfer_leader_during_snapshot<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer count check.
    pd_client.disable_default_rule();
    cluster.cfg.raft_store.raft_log_gc_tick_interval = 20;
    cluster.cfg.raft_store.raft_log_gc_count_limit = 2;

    let r1 = cluster.run_conf_change();
    pd_client.must_add_peer(r1, new_peer(2, 2));

    for i in 0..1024 {
        let key = format!("{:01024}", i);
        let value = format!("{:01024}", i);
        cluster.must_put(key.as_bytes(), value.as_bytes());
    }

    cluster.must_transfer_leader(r1, new_peer(1, 1));

    // hook transport and drop all snapshot packet, so follower's status
    // will stay at snapshot.
    cluster.add_send_filter(DefaultFilterFactory::<SnapshotFilter>::default());
    // don't allow leader transfer succeed if it is actually triggered.
    cluster.add_send_filter(CloneFilterFactory(RegionPacketFilter::new(1, 2)
        .msg_type(MessageType::MsgTimeoutNow)
        .direction(Direction::Recv)));

    pd_client.must_add_peer(r1, new_peer(3, 3));
    // a just added peer needs wait a couple of ticks, it'll communicate with leader
    // before getting snapshot
    sleep_ms(1000);

    let epoch = cluster.get_region_epoch(1);
    let put = new_request(1, epoch, vec![new_put_cmd(b"k1", b"v1")], false);
    cluster.transfer_leader(r1, new_peer(2, 2));
    let resp = cluster.call_command_on_leader(put, Duration::from_secs(5));
    // if it's transfering leader, resp will timeout.
    assert!(resp.is_ok(), "{:?}", resp);
}

#[test]
fn test_server_transfer_leader_during_snapshot() {
    let mut cluster = new_server_cluster(0, 3);
    test_transfer_leader_during_snapshot(&mut cluster);
}

#[test]
fn test_node_transfer_leader_during_snapshot() {
    let mut cluster = new_node_cluster(0, 3);
    test_transfer_leader_during_snapshot(&mut cluster);
}
<commit_msg>tests: ensure follower progress (#1954)<commit_after>// Copyright 2016 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

use std::time::Duration;
use std::thread;

use kvproto::eraftpb::MessageType;

use super::util::*;
use super::cluster::{Cluster, Simulator};
use super::transport_simulate::*;
use super::node::new_node_cluster;
use super::server::new_server_cluster;

fn test_basic_transfer_leader<T: Simulator>(cluster: &mut Cluster<T>) {
    cluster.cfg.raft_store.raft_heartbeat_ticks = 20;
    let reserved_time = Duration::from_millis(cluster.cfg.raft_store.raft_base_tick_interval *
                                              cluster.cfg.raft_store.raft_heartbeat_ticks as u64);
    cluster.run();

    // transfer leader to (2, 2)
    cluster.must_transfer_leader(1, new_peer(2, 2));

    let mut region = cluster.get_region(b"k3");

    // ensure follower has latest entries before transfer leader.
    cluster.must_put(b"k1", b"v1");
    must_get_equal(&cluster.get_engine(3), b"k1", b"v1");

    // check if transfer leader is fast enough.
    let leader = cluster.leader_of_region(1).unwrap();
    let admin_req = new_transfer_leader_cmd(new_peer(3, 3));
    let mut req = new_admin_request(1, region.get_region_epoch(), admin_req);
    req.mut_header().set_peer(leader);
    cluster.call_command(req, Duration::from_secs(3)).unwrap();
    thread::sleep(reserved_time);
    assert_eq!(cluster.query_leader(3, 1), Some(new_peer(3, 3)));

    let mut req = new_request(region.get_id(),
                              region.take_region_epoch(),
                              vec![new_put_cmd(b"k3", b"v3")],
                              false);
    req.mut_header().set_peer(new_peer(3, 3));
    // transfer leader to (4, 4)
    cluster.must_transfer_leader(1, new_peer(4, 4));
    // send request to old leader (3, 3) directly and verify it fails
    let resp = cluster.call_command(req, Duration::from_secs(5)).unwrap();
    assert!(resp.get_header().get_error().has_not_leader());
}

#[test]
fn test_server_basic_transfer_leader() {
    let mut cluster = new_server_cluster(0, 5);
    test_basic_transfer_leader(&mut cluster);
}

#[test]
fn test_node_basic_transfer_leader() {
    let mut cluster = new_node_cluster(0, 5);
    test_basic_transfer_leader(&mut cluster);
}

fn test_pd_transfer_leader<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_rule();

    cluster.run();

    cluster.must_put(b"k", b"v");

    // call command on this leader directly, must successfully.
    let mut region = cluster.get_region(b"");
    let mut req = new_request(region.get_id(),
                              region.take_region_epoch(),
                              vec![new_get_cmd(b"k")],
                              false);

    for id in 1..4 {
        // select a new leader to transfer
        pd_client.set_rule(box move |_, peer| {
            if peer.get_id() == id {
                return None;
            }
            new_pd_transfer_leader(new_peer(id, id))
        });

        for _ in 0..100 {
            // reset leader and wait transfer successfully.
            cluster.reset_leader_of_region(1);

            sleep_ms(20);

            if let Some(leader) = cluster.leader_of_region(1) {
                if leader.get_id() == id {
                    break;
                }
            }
        }

        assert_eq!(cluster.leader_of_region(1), Some(new_peer(id, id)));
        req.mut_header().set_peer(new_peer(id, id));
        debug!("requesting {:?}", req);
        let resp = cluster.call_command(req.clone(), Duration::from_secs(5)).unwrap();
        assert!(!resp.get_header().has_error(), "{:?}", resp);
        assert_eq!(resp.get_responses()[0].get_get().get_value(), b"v");
    }
}

#[test]
fn test_server_pd_transfer_leader() {
    let mut cluster = new_server_cluster(0, 3);
    test_pd_transfer_leader(&mut cluster);
}

#[test]
fn test_node_pd_transfer_leader() {
    let mut cluster = new_node_cluster(0, 3);
    test_pd_transfer_leader(&mut cluster);
}

fn test_transfer_leader_during_snapshot<T: Simulator>(cluster: &mut Cluster<T>) {
    let pd_client = cluster.pd_client.clone();
    // Disable default max peer count check.
    pd_client.disable_default_rule();
    cluster.cfg.raft_store.raft_log_gc_tick_interval = 20;
    cluster.cfg.raft_store.raft_log_gc_count_limit = 2;

    let r1 = cluster.run_conf_change();
    pd_client.must_add_peer(r1, new_peer(2, 2));

    for i in 0..1024 {
        let key = format!("{:01024}", i);
        let value = format!("{:01024}", i);
        cluster.must_put(key.as_bytes(), value.as_bytes());
    }

    cluster.must_transfer_leader(r1, new_peer(1, 1));

    // hook transport and drop all snapshot packet, so follower's status
    // will stay at snapshot.
    cluster.add_send_filter(DefaultFilterFactory::<SnapshotFilter>::default());
    // don't allow leader transfer succeed if it is actually triggered.
    cluster.add_send_filter(CloneFilterFactory(RegionPacketFilter::new(1, 2)
        .msg_type(MessageType::MsgTimeoutNow)
        .direction(Direction::Recv)));

    pd_client.must_add_peer(r1, new_peer(3, 3));
    // a just added peer needs wait a couple of ticks, it'll communicate with leader
    // before getting snapshot
    sleep_ms(1000);

    let epoch = cluster.get_region_epoch(1);
    let put = new_request(1, epoch, vec![new_put_cmd(b"k1", b"v1")], false);
    cluster.transfer_leader(r1, new_peer(2, 2));
    let resp = cluster.call_command_on_leader(put, Duration::from_secs(5));
    // if it's transfering leader, resp will timeout.
    assert!(resp.is_ok(), "{:?}", resp);
}

#[test]
fn test_server_transfer_leader_during_snapshot() {
    let mut cluster = new_server_cluster(0, 3);
    test_transfer_leader_during_snapshot(&mut cluster);
}

#[test]
fn test_node_transfer_leader_during_snapshot() {
    let mut cluster = new_node_cluster(0, 3);
    test_transfer_leader_during_snapshot(&mut cluster);
}
<|endoftext|>


<commit_before>use crate::{
    codegen::{function, general},
    env::Env,
    file_saver,
};
use log::info;
use std::path::Path;

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    info!("Generate global functions");

    let functions = match env.analysis.global_functions {
        Some(ref functions) => functions,
        None => return,
    };

    let path = root_path.join("functions.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &functions.imports, None)?;

        writeln!(w)?;

        mod_rs.push("\npub mod functions;".into());

        for func_analysis in &functions.functions {
            function::generate(w, env, func_analysis, None, None, false, false, 0)?;
        }

        Ok(())
    });
}
<commit_msg>codgen: don't generate a functions mod if it's empty<commit_after>use crate::{
    codegen::{function, general},
    env::Env,
    file_saver,
};
use log::info;
use std::path::Path;

pub fn generate(env: &Env, root_path: &Path, mod_rs: &mut Vec<String>) {
    info!("Generate global functions");

    let functions = match env.analysis.global_functions {
        Some(ref functions) => functions,
        None => return,
    };
    // Don't generate anything if we have no functions
    if functions.functions.is_empty() {
        return;
    }

    let path = root_path.join("functions.rs");
    file_saver::save_to_file(path, env.config.make_backup, |w| {
        general::start_comments(w, &env.config)?;
        general::uses(w, env, &functions.imports, None)?;

        writeln!(w)?;

        mod_rs.push("\npub mod functions;".into());

        for func_analysis in &functions.functions {
            function::generate(w, env, func_analysis, None, None, false, false, 0)?;
        }

        Ok(())
    });
}
<|endoftext|>