<commit_before>extern crate env_logger;
#[macro_use]
extern crate gluon_codegen;
extern crate gluon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gluon_vm;

mod init;

use gluon::{
    import,
    vm::{
        self,
        api::{
            self,
            generic::{self, L, R},
            OpaqueValue,
        },
        ExternModule,
    },
    RootedThread, Thread, ThreadExt,
};
use init::new_vm;

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.TupleEnum")]
enum TupleEnum {
    Variant,
    OtherVariant,
    One(u32),
    LotsOfTupleThings(i32, String, f64),
}

fn load_tuple_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_enum_to_str => primitive!(1, tuple_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_enum_to_str(val: TupleEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_tuple_variants() {
    let vm = new_vm();

    let src = api::typ::make_source::<TupleEnum>(&vm).unwrap();
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_enum_mod);

    let script = r#"
        let { TupleEnum } = import! types
        let { tuple_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_enum_to_str Variant == "Variant")
        assert (tuple_enum_to_str OtherVariant == "OtherVariant")
        assert (tuple_enum_to_str (One 1) == "One(1)")
        assert (tuple_enum_to_str (LotsOfTupleThings 42 "Text" 0.0) == "LotsOfTupleThings(42, \"Text\", 0.0)")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.StructEnum")]
enum StructEnum {
    OneField { field: i32 },
    TwoFields { name: String, val: f64 },
}

fn load_struct_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_enum_to_str => primitive!(1, struct_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_enum_to_str(val: StructEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_struct_variants() {
    let vm = new_vm();

    let src = api::typ::make_source::<StructEnum>(&vm).unwrap();
    println!("Types:\n{}", src);
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_enum_mod);

    let script = r#"
        let { StructEnum } = import! types
        let { struct_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_enum_to_str (OneField { field = 1337 }) == "OneField { field: 1337 }")
        assert (struct_enum_to_str (TwoFields { name = "Pi", val = 3.14 }) == "TwoFields { name: \"Pi\", val: 3.14 }")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType)]
enum Either<L, R> {
    Left(L),
    Right(R),
}

fn load_either_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        type Either l r => Either<L, R>,
        left => primitive!(1, left),
        extract_str => primitive!(1, extract_str),
    };

    ExternModule::new(vm, module)
}

type GenericL = OpaqueValue<RootedThread, generic::L>;
type GenericR = OpaqueValue<RootedThread, generic::R>;

fn left(either: Either<GenericL, GenericR>) -> Option<GenericL> {
    match either {
        Either::Left(left) => Some(left),
        _ => None,
    }
}

fn extract_str(either: Either<String, String>) -> String {
    match either {
        Either::Left(string) => string,
        Either::Right(string) => string,
    }
}

#[test]
fn enum_generic_variants() {
    let _ = env_logger::try_init();

    let vm = new_vm();

    import::add_extern_module(&vm, "functions", load_either_mod);

    let script = r#"
        let { Either, left, extract_str } = import! functions
        let { assert } = import! std.test

        assert (left (Left 42) == Some 42)
        assert (left (Right 0.0) == None)

        assert (extract_str (Left "left") == "left")
        assert (extract_str (Right "right") == "right")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, Pushable, VmType)]
enum Enum {
    TestVariant,
    TestVariant2(i32),
}

#[test]
fn derive_generates_same_type_as_gluon_define() {
    let _ = env_logger::try_init();

    let vm = new_vm();
    vm.get_database_mut().implicit_prelude(false);

    import::add_extern_module(&vm, "test", |vm| {
        ExternModule::new(vm, primitive!(1, "test", |_: Enum| ()))
    });

    let script = r#"
        let test = import! test

        type Enum = | TestVariant | TestVariant2 Int

        test TestVariant
        test (TestVariant2 123)
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable)]
struct LifetimeStruct<'a> {
    _str: &'a str,
}

// TODO: impl tests for lifetimes, this requires
// a safe interface for Getable::from_value()

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.Struct")]
struct Struct {
    string: String,
    int: i32,
    tuple: (f64, f64),
}

fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_to_str => primitive!(1, struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_to_str(val: Struct) -> String {
    format!("{:?}", val)
}

#[test]
fn struct_derive() {
    let vm = new_vm();

    let src = api::typ::make_source::<Struct>(&vm).unwrap();
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_mod);

    let script = r#"
        let { Struct } = import! types
        let { struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_to_str { string = "test", int = 55, tuple = (0.0, 1.0) } == "Struct { string: \"test\", int: 55, tuple: (0.0, 1.0) }")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Serialize, Deserialize, Debug, VmType, Getable)]
#[gluon(vm_type = "types.TupleStruct")]
struct TupleStruct(i32, i32);

fn load_tuple_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_struct_to_str => primitive!(1, tuple_struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_struct_to_str(val: TupleStruct) -> String {
    format!("{:?}", val)
}

#[test]
fn tuple_struct_derive() {
    let vm = new_vm();

    let src = r#"
        type TupleStruct = (Int, Int)
        { TupleStruct }
    "#;

    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_struct_mod);

    let script = r#"
        let { TupleStruct } = import! types
        let { tuple_struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_struct_to_str (1, 2) == "TupleStruct(1, 2)")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}
<commit_msg>Fix type inference in test<commit_after>extern crate env_logger;
#[macro_use]
extern crate gluon_codegen;
extern crate gluon;
extern crate serde;
#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate gluon_vm;

mod init;

use gluon::{
    import,
    vm::{
        self,
        api::{
            self,
            generic::{self, L, R},
            OpaqueValue,
        },
        ExternModule,
    },
    RootedThread, Thread, ThreadExt,
};
use init::new_vm;

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.TupleEnum")]
enum TupleEnum {
    Variant,
    OtherVariant,
    One(u32),
    LotsOfTupleThings(i32, String, f64),
}

fn load_tuple_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_enum_to_str => primitive!(1, tuple_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_enum_to_str(val: TupleEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_tuple_variants() {
    let vm = new_vm();

    let src = api::typ::make_source::<TupleEnum>(&vm).unwrap();
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_enum_mod);

    let script = r#"
        let { TupleEnum } = import! types
        let { tuple_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_enum_to_str Variant == "Variant")
        assert (tuple_enum_to_str OtherVariant == "OtherVariant")
        assert (tuple_enum_to_str (One 1) == "One(1)")
        assert (tuple_enum_to_str (LotsOfTupleThings 42 "Text" 0.0) == "LotsOfTupleThings(42, \"Text\", 0.0)")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.StructEnum")]
enum StructEnum {
    OneField { field: i32 },
    TwoFields { name: String, val: f64 },
}

fn load_struct_enum_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_enum_to_str => primitive!(1, struct_enum_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_enum_to_str(val: StructEnum) -> String {
    format!("{:?}", val)
}

#[test]
fn enum_struct_variants() {
    let vm = new_vm();

    let src = api::typ::make_source::<StructEnum>(&vm).unwrap();
    println!("Types:\n{}", src);
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_enum_mod);

    let script = r#"
        let { StructEnum } = import! types
        let { struct_enum_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_enum_to_str (OneField { field = 1337 }) == "OneField { field: 1337 }")
        assert (struct_enum_to_str (TwoFields { name = "Pi", val = 3.14 }) == "TwoFields { name: \"Pi\", val: 3.14 }")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, VmType)]
enum Either<L, R> {
    Left(L),
    Right(R),
}

fn load_either_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        type Either l r => Either<L, R>,
        left => primitive!(1, left),
        extract_str => primitive!(1, extract_str),
    };

    ExternModule::new(vm, module)
}

type GenericL = OpaqueValue<RootedThread, generic::L>;
type GenericR = OpaqueValue<RootedThread, generic::R>;

fn left(either: Either<GenericL, GenericR>) -> Option<GenericL> {
    match either {
        Either::Left(left) => Some(left),
        _ => None,
    }
}

fn extract_str(either: Either<String, String>) -> String {
    match either {
        Either::Left(string) => string,
        Either::Right(string) => string,
    }
}

#[test]
fn enum_generic_variants() {
    let _ = env_logger::try_init();

    let vm = new_vm();

    import::add_extern_module(&vm, "functions", load_either_mod);

    let script = r#"
        let { Either, left, extract_str } = import! functions
        let { assert } = import! std.test

        let l: Either Int Float  = Left 42
        assert (left l == Some 42)
        let r: Either Int Float  = Right 0.0
        assert (left r == None)

        assert (extract_str (Left "left") == "left")
        assert (extract_str (Right "right") == "right")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable, Pushable, VmType)]
enum Enum {
    TestVariant,
    TestVariant2(i32),
}

#[test]
fn derive_generates_same_type_as_gluon_define() {
    let _ = env_logger::try_init();

    let vm = new_vm();
    vm.get_database_mut().implicit_prelude(false);

    import::add_extern_module(&vm, "test", |vm| {
        ExternModule::new(vm, primitive!(1, "test", |_: Enum| ()))
    });

    let script = r#"
        let test = import! test

        type Enum = | TestVariant | TestVariant2 Int

        test TestVariant
        test (TestVariant2 123)
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Getable)]
struct LifetimeStruct<'a> {
    _str: &'a str,
}

// TODO: impl tests for lifetimes, this requires
// a safe interface for Getable::from_value()

#[derive(Getable, VmType, Debug, Serialize, Deserialize)]
#[gluon(vm_type = "types.Struct")]
struct Struct {
    string: String,
    int: i32,
    tuple: (f64, f64),
}

fn load_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        struct_to_str => primitive!(1, struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn struct_to_str(val: Struct) -> String {
    format!("{:?}", val)
}

#[test]
fn struct_derive() {
    let vm = new_vm();

    let src = api::typ::make_source::<Struct>(&vm).unwrap();
    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_struct_mod);

    let script = r#"
        let { Struct } = import! types
        let { struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (struct_to_str { string = "test", int = 55, tuple = (0.0, 1.0) } == "Struct { string: \"test\", int: 55, tuple: (0.0, 1.0) }")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}

#[derive(Serialize, Deserialize, Debug, VmType, Getable)]
#[gluon(vm_type = "types.TupleStruct")]
struct TupleStruct(i32, i32);

fn load_tuple_struct_mod(vm: &Thread) -> vm::Result<ExternModule> {
    let module = record! {
        tuple_struct_to_str => primitive!(1, tuple_struct_to_str),
    };

    ExternModule::new(vm, module)
}

fn tuple_struct_to_str(val: TupleStruct) -> String {
    format!("{:?}", val)
}

#[test]
fn tuple_struct_derive() {
    let vm = new_vm();

    let src = r#"
        type TupleStruct = (Int, Int)
        { TupleStruct }
    "#;

    vm.load_script("types", &src).unwrap();
    import::add_extern_module(&vm, "functions", load_tuple_struct_mod);

    let script = r#"
        let { TupleStruct } = import! types
        let { tuple_struct_to_str } = import! functions
        let { assert } = import! std.test

        assert (tuple_struct_to_str (1, 2) == "TupleStruct(1, 2)")
    "#;

    if let Err(why) = vm.run_expr::<()>("test", script) {
        panic!("{}", why);
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Joseph Crail <jbcrail@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[cfg(unix)]
use libc::{
    mode_t, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRGRP,
    S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH,
    S_IXUSR,
};
use std::borrow::Cow;
use std::env;
use std::fs;
#[cfg(target_os = "redox")]
use std::io;
use std::io::Result as IOResult;
use std::io::{Error, ErrorKind};
#[cfg(any(unix, target_os = "redox"))]
use std::os::unix::fs::MetadataExt;
use std::path::{Component, Path, PathBuf};

#[cfg(unix)]
#[macro_export]
macro_rules! has {
    ($mode:expr, $perm:expr) => {
        $mode & $perm != 0
    };
}

pub fn resolve_relative_path(path: &Path) -> Cow<Path> {
    if path.components().all(|e| e != Component::ParentDir) {
        return path.into();
    }
    let root = Component::RootDir.as_os_str();
    let mut result = env::current_dir().unwrap_or_else(|_| PathBuf::from(root));
    for comp in path.components() {
        match comp {
            Component::ParentDir => {
                if let Ok(p) = result.read_link() {
                    result = p;
                }
                result.pop();
            }
            Component::CurDir => (),
            Component::RootDir | Component::Normal(_) | Component::Prefix(_) => {
                result.push(comp.as_os_str())
            }
        }
    }
    result.into()
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    None,
    Normal,
    Existing,
    Missing,
}

// copied from https://github.com/rust-lang/cargo/blob/2e4cfc2b7d43328b207879228a2ca7d427d188bb/src/cargo/util/paths.rs#L65-L90
// both projects are MIT https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT
// for std impl progress see rfc https://github.com/rust-lang/rfcs/issues/2208
// replace this once that lands
pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "maximum links followed",
            ));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    }
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        dunce::canonicalize(env::current_dir().unwrap())
            .unwrap()
            .join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec![];

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) | Component::RootDir => {
                result.push(part.as_os_str());
            }
            Component::CurDir => (),
            Component::ParentDir => {
                parts.pop();
            }
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len() - 1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => match can_mode {
                    CanonicalizeMode::Missing => continue,
                    _ => return Err(e),
                },
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        match resolve(&result) {
            Err(e) => {
                if can_mode == CanonicalizeMode::Existing {
                    return Err(e);
                }
            }
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stdin_interactive() -> bool {
    termion::is_tty(&io::stdin())
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stdout_interactive() -> bool {
    termion::is_tty(&io::stdout())
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stderr_interactive() -> bool {
    termion::is_tty(&io::stderr())
}

#[cfg(not(unix))]
#[allow(unused_variables)]
pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
    if display_file_type {
        return String::from("----------");
    }
    String::from("---------")
}

#[cfg(unix)]
pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
    let mode: mode_t = metadata.mode() as mode_t;
    display_permissions_unix(mode, display_file_type)
}

#[cfg(unix)]
pub fn display_permissions_unix(mode: mode_t, display_file_type: bool) -> String {
    let mut result;
    if display_file_type {
        result = String::with_capacity(10);
        result.push(match mode & S_IFMT {
            S_IFDIR => 'd',
            S_IFCHR => 'c',
            S_IFBLK => 'b',
            S_IFREG => '-',
            S_IFIFO => 'p',
            S_IFLNK => 'l',
            S_IFSOCK => 's',
            // TODO: Other file types
            _ => '?',
        });
    } else {
        result = String::with_capacity(9);
    }

    result.push(if has!(mode, S_IRUSR) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWUSR) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISUID as mode_t) {
        if has!(mode, S_IXUSR) {
            's'
        } else {
            'S'
        }
    } else if has!(mode, S_IXUSR) {
        'x'
    } else {
        '-'
    });

    result.push(if has!(mode, S_IRGRP) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWGRP) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISGID as mode_t) {
        if has!(mode, S_IXGRP) {
            's'
        } else {
            'S'
        }
    } else if has!(mode, S_IXGRP) {
        'x'
    } else {
        '-'
    });

    result.push(if has!(mode, S_IROTH) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWOTH) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISVTX as mode_t) {
        if has!(mode, S_IXOTH) {
            't'
        } else {
            'T'
        }
    } else if has!(mode, S_IXOTH) {
        'x'
    } else {
        '-'
    });

    result
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;

    struct NormalizePathTestCase<'a> {
        path: &'a str,
        test: &'a str,
    }

    const NORMALIZE_PATH_TESTS: [NormalizePathTestCase; 8] = [
        NormalizePathTestCase {
            path: "./foo/bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "bar/../foo/bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "foo///bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "foo///bar",
            test: "foo/bar",
        },
        NormalizePathTestCase {
            path: "foo//./bar",
            test: "foo/bar",
        },
        NormalizePathTestCase {
            path: "/foo//./bar",
            test: "/foo/bar",
        },
        NormalizePathTestCase {
            path: r"C:/you/later/",
            test: "C:/you/later",
        },
        NormalizePathTestCase {
            path: "\\networkshare/a//foo//./bar",
            test: "\\networkshare/a/foo/bar",
        },
    ];

    #[test]
    fn test_normalize_path() {
        for test in NORMALIZE_PATH_TESTS.iter() {
            let path = Path::new(test.path);
            let normalized = normalize_path(path);
            assert_eq!(
                test.test
                    .replace("/", std::path::MAIN_SEPARATOR.to_string().as_str()),
                normalized.to_str().expect("Path is not valid utf-8!")
            );
        }
    }

    #[cfg(unix)]
    #[test]
    fn test_display_permissions() {
        assert_eq!(
            "drwxr-xr-x",
            display_permissions_unix(S_IFDIR | 0o755, true)
        );
        assert_eq!(
            "rwxr-xr-x",
            display_permissions_unix(S_IFDIR | 0o755, false)
        );
        assert_eq!(
            "-rw-r--r--",
            display_permissions_unix(S_IFREG | 0o644, true)
        );
        assert_eq!(
            "srw-r-----",
            display_permissions_unix(S_IFSOCK | 0o640, true)
        );
        assert_eq!(
            "lrw-r-xr-x",
            display_permissions_unix(S_IFLNK | 0o655, true)
        );
        assert_eq!("?rw-r-xr-x", display_permissions_unix(0o655, true));

        assert_eq!(
            "brwSr-xr-x",
            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o655, true)
        );
        assert_eq!(
            "brwsr-xr-x",
            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o755, true)
        );

        assert_eq!(
            "prw---sr--",
            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o614, true)
        );
        assert_eq!(
            "prw---Sr--",
            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o604, true)
        );

        assert_eq!(
            "c---r-xr-t",
            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o055, true)
        );
        assert_eq!(
            "c---r-xr-T",
            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o054, true)
        );
    }
}
<commit_msg>uucore::fs: don't canonicalize last component<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Joseph Crail <jbcrail@gmail.com>
// (c) Jian Zeng <anonymousknight96 AT gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

#[cfg(unix)]
use libc::{
    mode_t, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO, S_IFLNK, S_IFMT, S_IFREG, S_IFSOCK, S_IRGRP,
    S_IROTH, S_IRUSR, S_ISGID, S_ISUID, S_ISVTX, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH,
    S_IXUSR,
};
use std::borrow::Cow;
use std::env;
use std::fs;
#[cfg(target_os = "redox")]
use std::io;
use std::io::Result as IOResult;
use std::io::{Error, ErrorKind};
#[cfg(any(unix, target_os = "redox"))]
use std::os::unix::fs::MetadataExt;
use std::path::{Component, Path, PathBuf};

#[cfg(unix)]
#[macro_export]
macro_rules! has {
    ($mode:expr, $perm:expr) => {
        $mode & $perm != 0
    };
}

pub fn resolve_relative_path(path: &Path) -> Cow<Path> {
    if path.components().all(|e| e != Component::ParentDir) {
        return path.into();
    }
    let root = Component::RootDir.as_os_str();
    let mut result = env::current_dir().unwrap_or_else(|_| PathBuf::from(root));
    for comp in path.components() {
        match comp {
            Component::ParentDir => {
                if let Ok(p) = result.read_link() {
                    result = p;
                }
                result.pop();
            }
            Component::CurDir => (),
            Component::RootDir | Component::Normal(_) | Component::Prefix(_) => {
                result.push(comp.as_os_str())
            }
        }
    }
    result.into()
}

/// Controls how symbolic links should be handled when canonicalizing a path.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CanonicalizeMode {
    /// Do not resolve any symbolic links.
    None,

    /// Resolve all symbolic links.
    Normal,

    /// Resolve symbolic links, ignoring errors on the final component.
    Existing,

    /// Resolve symbolic links, ignoring errors on the non-final components.
    Missing,
}

// copied from https://github.com/rust-lang/cargo/blob/2e4cfc2b7d43328b207879228a2ca7d427d188bb/src/cargo/util/paths.rs#L65-L90
// both projects are MIT https://github.com/rust-lang/cargo/blob/master/LICENSE-MIT
// for std impl progress see rfc https://github.com/rust-lang/rfcs/issues/2208
// replace this once that lands
pub fn normalize_path(path: &Path) -> PathBuf {
    let mut components = path.components().peekable();
    let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() {
        components.next();
        PathBuf::from(c.as_os_str())
    } else {
        PathBuf::new()
    };

    for component in components {
        match component {
            Component::Prefix(..) => unreachable!(),
            Component::RootDir => {
                ret.push(component.as_os_str());
            }
            Component::CurDir => {}
            Component::ParentDir => {
                ret.pop();
            }
            Component::Normal(c) => {
                ret.push(c);
            }
        }
    }
    ret
}

fn resolve<P: AsRef<Path>>(original: P) -> IOResult<PathBuf> {
    const MAX_LINKS_FOLLOWED: u32 = 255;
    let mut followed = 0;
    let mut result = original.as_ref().to_path_buf();
    loop {
        if followed == MAX_LINKS_FOLLOWED {
            return Err(Error::new(
                ErrorKind::InvalidInput,
                "maximum links followed",
            ));
        }

        match fs::symlink_metadata(&result) {
            Err(e) => return Err(e),
            Ok(ref m) if !m.file_type().is_symlink() => break,
            Ok(..) => {
                followed += 1;
                match fs::read_link(&result) {
                    Ok(path) => {
                        result.pop();
                        result.push(path);
                    }
                    Err(e) => {
                        return Err(e);
                    }
                }
            }
        }
    }
    Ok(result)
}

/// Return the canonical, absolute form of a path.
///
/// This function is a generalization of [`std::fs::canonicalize`] that
/// allows controlling how symbolic links are resolved and how to deal
/// with missing components. It returns the canonical, absolute form of
/// a path. The `can_mode` parameter controls how symbolic links are
/// resolved:
///
/// * [`CanonicalizeMode::Normal`] makes this function behave like
///   [`std::fs::canonicalize`], resolving symbolic links and returning
///   an error if the path does not exist.
/// * [`CanonicalizeMode::Missing`] makes this function ignore non-final
///   components of the path that could not be resolved.
/// * [`CanonicalizeMode::Existing`] makes this function return an error
///   if the final component of the path does not exist.
/// * [`CanonicalizeMode::None`] makes this function not try to resolve
///   any symbolic links.
///
pub fn canonicalize<P: AsRef<Path>>(original: P, can_mode: CanonicalizeMode) -> IOResult<PathBuf> {
    // Create an absolute path
    let original = original.as_ref();
    let original = if original.is_absolute() {
        original.to_path_buf()
    } else {
        dunce::canonicalize(env::current_dir().unwrap())
            .unwrap()
            .join(original)
    };

    let mut result = PathBuf::new();
    let mut parts = vec![];

    // Split path by directory separator; add prefix (Windows-only) and root
    // directory to final path buffer; add remaining parts to temporary
    // vector for canonicalization.
    for part in original.components() {
        match part {
            Component::Prefix(_) | Component::RootDir => {
                result.push(part.as_os_str());
            }
            Component::CurDir => (),
            Component::ParentDir => {
                parts.pop();
            }
            Component::Normal(_) => {
                parts.push(part.as_os_str());
            }
        }
    }

    // Resolve the symlinks where possible
    if !parts.is_empty() {
        for part in parts[..parts.len() - 1].iter() {
            result.push(part);

            if can_mode == CanonicalizeMode::None {
                continue;
            }

            match resolve(&result) {
                Err(e) => match can_mode {
                    CanonicalizeMode::Missing => continue,
                    _ => return Err(e),
                },
                Ok(path) => {
                    result.pop();
                    result.push(path);
                }
            }
        }

        result.push(parts.last().unwrap());

        if can_mode == CanonicalizeMode::None {
            return Ok(result);
        }

        match resolve(&result) {
            Err(e) => {
                if can_mode == CanonicalizeMode::Existing {
                    return Err(e);
                }
            }
            Ok(path) => {
                result.pop();
                result.push(path);
            }
        }
    }
    Ok(result)
}

#[cfg(unix)]
pub fn is_stdin_interactive() -> bool {
    unsafe { libc::isatty(libc::STDIN_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdin_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stdin_interactive() -> bool {
    termion::is_tty(&io::stdin())
}

#[cfg(unix)]
pub fn is_stdout_interactive() -> bool {
    unsafe { libc::isatty(libc::STDOUT_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stdout_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stdout_interactive() -> bool {
    termion::is_tty(&io::stdout())
}

#[cfg(unix)]
pub fn is_stderr_interactive() -> bool {
    unsafe { libc::isatty(libc::STDERR_FILENO) == 1 }
}

#[cfg(windows)]
pub fn is_stderr_interactive() -> bool {
    false
}

#[cfg(target_os = "redox")]
pub fn is_stderr_interactive() -> bool {
    termion::is_tty(&io::stderr())
}

#[cfg(not(unix))]
#[allow(unused_variables)]
pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
    if display_file_type {
        return String::from("----------");
    }
    String::from("---------")
}

#[cfg(unix)]
pub fn display_permissions(metadata: &fs::Metadata, display_file_type: bool) -> String {
    let mode: mode_t = metadata.mode() as mode_t;
    display_permissions_unix(mode, display_file_type)
}

#[cfg(unix)]
pub fn display_permissions_unix(mode: mode_t, display_file_type: bool) -> String {
    let mut result;
    if display_file_type {
        result = String::with_capacity(10);
        result.push(match mode & S_IFMT {
            S_IFDIR => 'd',
            S_IFCHR => 'c',
            S_IFBLK => 'b',
            S_IFREG => '-',
            S_IFIFO => 'p',
            S_IFLNK => 'l',
            S_IFSOCK => 's',
            // TODO: Other file types
            _ => '?',
        });
    } else {
        result = String::with_capacity(9);
    }

    result.push(if has!(mode, S_IRUSR) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWUSR) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISUID as mode_t) {
        if has!(mode, S_IXUSR) {
            's'
        } else {
            'S'
        }
    } else if has!(mode, S_IXUSR) {
        'x'
    } else {
        '-'
    });

    result.push(if has!(mode, S_IRGRP) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWGRP) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISGID as mode_t) {
        if has!(mode, S_IXGRP) {
            's'
        } else {
            'S'
        }
    } else if has!(mode, S_IXGRP) {
        'x'
    } else {
        '-'
    });

    result.push(if has!(mode, S_IROTH) { 'r' } else { '-' });
    result.push(if has!(mode, S_IWOTH) { 'w' } else { '-' });
    result.push(if has!(mode, S_ISVTX as mode_t) {
        if has!(mode, S_IXOTH) {
            't'
        } else {
            'T'
        }
    } else if has!(mode, S_IXOTH) {
        'x'
    } else {
        '-'
    });

    result
}

#[cfg(test)]
mod tests {
    // Note this useful idiom: importing names from outer (for mod tests) scope.
    use super::*;

    struct NormalizePathTestCase<'a> {
        path: &'a str,
        test: &'a str,
    }

    const NORMALIZE_PATH_TESTS: [NormalizePathTestCase; 8] = [
        NormalizePathTestCase {
            path: "./foo/bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "bar/../foo/bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "foo///bar.txt",
            test: "foo/bar.txt",
        },
        NormalizePathTestCase {
            path: "foo///bar",
            test: "foo/bar",
        },
        NormalizePathTestCase {
            path: "foo//./bar",
            test: "foo/bar",
        },
        NormalizePathTestCase {
            path: "/foo//./bar",
            test: "/foo/bar",
        },
        NormalizePathTestCase {
            path: r"C:/you/later/",
            test: "C:/you/later",
        },
        NormalizePathTestCase {
            path: "\\networkshare/a//foo//./bar",
            test: "\\networkshare/a/foo/bar",
        },
    ];

    #[test]
    fn test_normalize_path() {
        for test in NORMALIZE_PATH_TESTS.iter() {
            let path = Path::new(test.path);
            let normalized = normalize_path(path);
            assert_eq!(
                test.test
                    .replace("/", std::path::MAIN_SEPARATOR.to_string().as_str()),
                normalized.to_str().expect("Path is not valid utf-8!")
            );
        }
    }

    #[cfg(unix)]
    #[test]
    fn test_display_permissions() {
        assert_eq!(
            "drwxr-xr-x",
            display_permissions_unix(S_IFDIR | 0o755, true)
        );
        assert_eq!(
            "rwxr-xr-x",
            display_permissions_unix(S_IFDIR | 0o755, false)
        );
        assert_eq!(
            "-rw-r--r--",
            display_permissions_unix(S_IFREG | 0o644, true)
        );
        assert_eq!(
            "srw-r-----",
            display_permissions_unix(S_IFSOCK | 0o640, true)
        );
        assert_eq!(
            "lrw-r-xr-x",
            display_permissions_unix(S_IFLNK | 0o655, true)
        );
        assert_eq!("?rw-r-xr-x", display_permissions_unix(0o655, true));

        assert_eq!(
            "brwSr-xr-x",
            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o655, true)
        );
        assert_eq!(
            "brwsr-xr-x",
            display_permissions_unix(S_IFBLK | S_ISUID as mode_t | 0o755, true)
        );

        assert_eq!(
            "prw---sr--",
            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o614, true)
        );
        assert_eq!(
            "prw---Sr--",
            display_permissions_unix(S_IFIFO | S_ISGID as mode_t | 0o604, true)
        );

        assert_eq!(
            "c---r-xr-t",
            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o055, true)
        );
        assert_eq!(
            "c---r-xr-T",
            display_permissions_unix(S_IFCHR | S_ISVTX as mode_t | 0o054, true)
        );
    }
}
<|endoftext|>


<commit_before>/*

----------------------------------------
Grammatik:

LL(1)
----------------------------------------|
S -> Passage S2                         |
S2 -> S                                 |
S2 -> ɛ                                 |
Passage -> PassageName PassageContent   |
PassageContent -> TextPassage B         |
PassageContent -> Formatting B          |
PassageContent -> Newline B             |
B -> PassageContent                     |
B -> ɛ                                  |
----------------------------------------|

Hello World im LL(1)-Parser:
token: [TokPassageName("Start"), TokText("Hello World\n")]

input                   | stack                         | output                              |
------------------------+-------------------------------+-------------------------------------+---------------------------------------------------
PassageName TextPassage | S                             | S->Passage S'                       | passage and s' as child of S
        --||--          | Passage S2                    | Passage->PassageName PassageContent | passageName and passagecontent as child of passage
        --||--          | PassageName PassageContent S2 |                                     | gehe bei den token 1 weiter
TextPassage             | PassageContent S2             | PassageContent->TextPassage B       | textpassage and b as child of PassageContent
        --||--          | TextPassage B S'              |                                     | gehe bei den token 1 weiter
empty                   | B S'                          | B->ɛ                                |
empty                   | S'                            | S' -> ɛ                             |
empty                   | empty                         | ACCEPT                              |
------------------------+-------------------------------+-------------------------------------|---------------------------------------------------

*/

pub use super::frontend::lexer::Token;

//==============================
// grammar

#[derive(Debug)]
enum NonTerminalType {
    S,
    S2,
    Passage,
    PassageContent,
    B
}

//==============================

struct SyntaxTree {
    root: NodeType
}

//#[derive(Debug)]
enum NodeType {
    NonTerminal (NodeNonTerminal),
    Terminal (NodeTerminal)
}

// ================================
// node types

struct NodeNonTerminal {
    category: NonTerminalType,
    childs: Vec<NodeType>
}

struct NodeTerminal {
    category: Token
}

impl NodeType {

    pub fn new_terminal(terminal: Token) -> NodeType {
        NodeType::Terminal(NodeTerminal  { category: terminal })
    }

    pub fn new_non_terminal(non_terminal: NonTerminalType) -> NodeType {
        NodeType::NonTerminal(NodeNonTerminal { category: non_terminal, childs: Vec::new() })
    }

    // prints a node
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &NodeType::NonTerminal(ref t) => {
                debug!("{}|- Node: {:?}", spaces, t.category);

                for child in &t.childs {
                    child.print(indent+2);
                }
            }
            &NodeType::Terminal(ref t) => {
                debug!("{}|- Terminal: {:?}", spaces, t.category);
            }
        }
    }

    // returns a non_terminal of the path
    pub fn get_non_terminal(&self, path: Vec<usize>) -> &NonTerminalType {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].get_non_terminal(new_path);
                } else {
                    return &node.category;
                }
            },
            _ => panic!("error")
        }
    }

    // adds a node to the childs in path
    pub fn add_child_at(&mut self, path: &[usize], child: NodeType) {
        match self {
            &mut NodeType::NonTerminal (ref mut node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    node.childs[*index].add_child_at(&new_path, child);
                } else {
                    node.childs.push(child);
                }
            },
            _ => panic!("error")
        }
    }

    // checks if the node of the path is a terminal or not
    pub fn is_terminal(&self, path: Vec<usize>) -> bool {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].is_terminal(new_path);
                }

                return false
            },
            &NodeType::Terminal(_) => return true
        }

        false
    }
}

impl SyntaxTree {
    pub fn new() -> SyntaxTree {
        SyntaxTree {
            root: NodeType::new_non_terminal(NonTerminalType::S)
        }
    }

    // adds one nodes to childs at the path
    pub fn add_one_node(&mut self, child: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child);
    }

    // adds two nodes to childs at the path
    pub fn add_two_nodes(&mut self, child1: NodeType, child2: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child1);
        self.root.add_child_at(&to_add_path, child2);
    }
}

pub fn temp_create_parse_tree(tokens: Vec<Token>) {
    let mut tree: SyntaxTree = SyntaxTree::new();
    let mut stack: Vec<Vec<usize>> = Vec::new();

    stack.push(vec![]);
    let mut token_index = 0;

    // stack parser...
    while !stack.is_empty() {
        //println!("stack loop");
        let mut is_terminal;
        let top_path;

        if let Some(top) = stack.last() {
            is_terminal = tree.root.is_terminal( top.to_vec() );
            top_path = top.to_vec();
        } else {
            panic!("error")
        }

        stack.pop();

        if is_terminal {
            token_index = token_index + 1;

        } else {
            // parse table in code
            let to_add_path: Vec<usize> = top_path.to_vec();
            match tree.root.get_non_terminal(top_path) {
                &NonTerminalType::S => {
                    tree.add_two_nodes(NodeType::new_non_terminal(NonTerminalType::Passage), NodeType::new_non_terminal(NonTerminalType::S2), &to_add_path);
                    add_two_to_stack(&mut stack, to_add_path);

                },
                &NonTerminalType::S2 => {
                    // check follow...
                    if let Some(token) = tokens.get(token_index) {
                        match token {
                            &Token::TokPassageName (_) => {
                                tree.add_one_node(NodeType::new_non_terminal(NonTerminalType::S), &to_add_path);
                                add_one_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }
                },
                &NonTerminalType::Passage => {
                    if let Some(token) = tokens.get(token_index) {
                        match token {
                            &Token::TokPassageName (ref name) => {
                                let new_token: Token = Token::TokPassageName(name.clone());
                                tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::PassageContent), &to_add_path);
                                add_two_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }

                },
                &NonTerminalType::PassageContent => {
                     if let Some(token) = tokens.get(token_index) {
                        match token {
                            &Token::TokText (ref text) => {
                                let new_token: Token = Token::TokText(text.clone());
                                tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::B), &to_add_path);
                                add_two_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }
                },
                &NonTerminalType::B => {
                    /*
                    debug!("B: {}", token_index);

                    don't supportet at the moment
                    // check follow...
                    if let Some(token) = tokens.get(token_index) {
                        match token {
                            &Token::TokText (_) | &Token::TokFormatBold => {
                                let child = NodeType::new_non_terminal(NonTerminalType::PassageContent);
                                tree.root.add_child_at(&to_add_path, child);
                                add_one_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }*/
                }
            }
        }
    }

    debug!("Parse Tree");
    tree.root.print(0);
}

// save the path to the node in the tree in the stack
// todo: add_child_at should return the path
// the right part of the production
// should be on the stack in reverse order
fn add_two_to_stack(stack: &mut Vec<Vec<usize>>, to_add_path: Vec<usize>) {
    let mut path1: Vec<usize> = to_add_path.to_vec();
    let mut path2: Vec<usize> = to_add_path.to_vec();

    path1.push(1);
    path2.push(0);

    stack.push(path1);
    stack.push(path2);
}

fn add_one_to_stack(stack: &mut Vec<Vec<usize>>, to_add_path: Vec<usize>) {
    let mut path1: Vec<usize> = to_add_path.to_vec();
    path1.push(0);
    stack.push(path1);
}

#[test]
fn it_works() {
}
<commit_msg>small changes<commit_after>/*

----------------------------------------
Grammatik:

LL(1)
----------------------------------------|
S -> Passage S2                         |
S2 -> S                                 |
S2 -> ɛ                                 |
Passage -> PassageName PassageContent   |
PassageContent -> TextPassage B         |
PassageContent -> Formatting B          |
PassageContent -> Newline B             |
B -> PassageContent                     |
B -> ɛ                                  |
----------------------------------------|

Hello World im LL(1)-Parser:
token: [TokPassageName("Start"), TokText("Hello World\n")]

input                   | stack                         | output                              |
------------------------+-------------------------------+-------------------------------------+---------------------------------------------------
PassageName TextPassage | S                             | S->Passage S'                       | passage and s' as child of S
        --||--          | Passage S2                    | Passage->PassageName PassageContent | passageName and passagecontent as child of passage
        --||--          | PassageName PassageContent S2 |                                     | gehe bei den token 1 weiter
TextPassage             | PassageContent S2             | PassageContent->TextPassage B       | textpassage and b as child of PassageContent
        --||--          | TextPassage B S'              |                                     | gehe bei den token 1 weiter
empty                   | B S'                          | B->ɛ                                |
empty                   | S'                            | S' -> ɛ                             |
empty                   | empty                         | ACCEPT                              |
------------------------+-------------------------------+-------------------------------------|---------------------------------------------------

*/

pub use super::frontend::lexer::Token;

//==============================
// grammar

#[derive(Debug)]
enum NonTerminalType {
    S,
    S2,
    Passage,
    PassageContent,
    B
}

//==============================

struct SyntaxTree {
    root: NodeType
}

//#[derive(Debug)]
enum NodeType {
    NonTerminal (NodeNonTerminal),
    Terminal (NodeTerminal)
}

// ================================
// node types

struct NodeNonTerminal {
    category: NonTerminalType,
    childs: Vec<NodeType>
}

struct NodeTerminal {
    category: Token
}

impl NodeType {

    pub fn new_terminal(terminal: Token) -> NodeType {
        NodeType::Terminal(NodeTerminal  { category: terminal })
    }

    pub fn new_non_terminal(non_terminal: NonTerminalType) -> NodeType {
        NodeType::NonTerminal(NodeNonTerminal { category: non_terminal, childs: Vec::new() })
    }

    // prints a node
    pub fn print(&self, indent: usize) {
        let mut spaces = "".to_string();
        for _ in 0..indent {
            spaces.push_str(" ");
        }

        match self {
            &NodeType::NonTerminal(ref t) => {
                debug!("{}|- Node: {:?}", spaces, t.category);

                for child in &t.childs {
                    child.print(indent+2);
                }
            }
            &NodeType::Terminal(ref t) => {
                debug!("{}|- Terminal: {:?}", spaces, t.category);
            }
        }
    }

    // returns a non_terminal of the path
    pub fn get_non_terminal(&self, path: Vec<usize>) -> &NonTerminalType {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].get_non_terminal(new_path);
                } else {
                    return &node.category;
                }
            },
            _ => panic!("error")
        }
    }

    // adds a node to the childs in path
    pub fn add_child_at(&mut self, path: &[usize], child: NodeType) {
        match self {
            &mut NodeType::NonTerminal (ref mut node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    node.childs[*index].add_child_at(&new_path, child);
                } else {
                    node.childs.push(child);
                }
            },
            _ => panic!("error")
        }
    }

    // checks if the node of the path is a terminal or not
    pub fn is_terminal(&self, path: Vec<usize>) -> bool {
        match self {
            &NodeType::NonTerminal(ref node) => {
                if let Some(index) = path.first() {
                    let mut new_path: Vec<usize> = path.to_vec();
                    new_path.remove(0);
                    return node.childs[*index].is_terminal(new_path);
                }

                return false
            },
            &NodeType::Terminal(_) => return true
        }

        false
    }
}

impl SyntaxTree {
    pub fn new() -> SyntaxTree {
        SyntaxTree {
            root: NodeType::new_non_terminal(NonTerminalType::S)
        }
    }

    // adds one nodes to childs at the path
    pub fn add_one_node(&mut self, child: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child);
    }

    // adds two nodes to childs at the path
    pub fn add_two_nodes(&mut self, child1: NodeType, child2: NodeType, to_add_path: &Vec<usize>) {
        self.root.add_child_at(&to_add_path, child1);
        self.root.add_child_at(&to_add_path, child2);
    }
}

pub fn temp_create_parse_tree(tokens: Vec<Token>) {
    let mut tree: SyntaxTree = SyntaxTree::new();
    let mut stack: Vec<Vec<usize>> = Vec::new();

    stack.push(vec![]);
    let mut lookahead = 0;

    // stack parser...
    while !stack.is_empty() {
        let mut is_terminal;
        let top_path;

        // check if the top-element of the stack is a terminal or non terminal
        if let Some(top) = stack.last() {
            is_terminal = tree.root.is_terminal( top.to_vec() );
            top_path = top.to_vec();
        } else {
            panic!("error");
        }

        stack.pop();

        if is_terminal {
            // lookahead looks to the next token
            lookahead = lookahead + 1;

        } else {
            // parse table in code
            let to_add_path: Vec<usize> = top_path.to_vec();
            match tree.root.get_non_terminal(top_path) {
                &NonTerminalType::S => {
                    tree.add_two_nodes(NodeType::new_non_terminal(NonTerminalType::Passage), NodeType::new_non_terminal(NonTerminalType::S2), &to_add_path);
                    add_two_to_stack(&mut stack, to_add_path);

                },
                &NonTerminalType::S2 => {
                    // check follow...
                    if let Some(token) = tokens.get(lookahead) {
                        match token {
                            &Token::TokPassageName (_) => {
                                tree.add_one_node(NodeType::new_non_terminal(NonTerminalType::S), &to_add_path);
                                add_one_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }
                },
                &NonTerminalType::Passage => {
                    if let Some(token) = tokens.get(lookahead) {
                        match token {
                            &Token::TokPassageName (ref name) => {
                                let new_token: Token = Token::TokPassageName(name.clone());
                                tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::PassageContent), &to_add_path);
                                add_two_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }

                },
                &NonTerminalType::PassageContent => {
                     if let Some(token) = tokens.get(lookahead) {
                        match token {
                            &Token::TokText (ref text) => {
                                let new_token: Token = Token::TokText(text.clone());
                                tree.add_two_nodes(NodeType::new_terminal(new_token), NodeType::new_non_terminal(NonTerminalType::B), &to_add_path);
                                add_two_to_stack(&mut stack, to_add_path);
                            },
                            _ => { }
                        }
                    }
                },
                &NonTerminalType::B => {
                    // not implemented
                }
            }
        }
    }

    debug!("Parse Tree");
    tree.root.print(0);
}

// save the path of the nodes in the tree to the stack
// the right part of the production
// should be on the stack in reverse order
fn add_two_to_stack(stack: &mut Vec<Vec<usize>>, to_add_path: Vec<usize>) {
    let mut path1: Vec<usize> = to_add_path.to_vec();
    let mut path2: Vec<usize> = to_add_path.to_vec();

    path1.push(1);
    path2.push(0);

    stack.push(path1);
    stack.push(path2);
}

fn add_one_to_stack(stack: &mut Vec<Vec<usize>>, to_add_path: Vec<usize>) {
    let mut path1: Vec<usize> = to_add_path.to_vec();
    path1.push(0);
    stack.push(path1);
}

#[test]
fn it_works() {
}
<|endoftext|>


<commit_before>extern crate serial;
extern crate time;
extern crate crc16;
extern crate toml;

mod messages;

use std::io;
use std::io::prelude::*;
use serial::prelude::*;
use time::Duration;
use crc16::*;
use std::fs::File;
use std::env::home_dir;
use messages::*;

const HEADER: [u8; 4] = [5, 5, 3, 3];
const FOOTER: [u8; 2] = [13, 10];
const EOM: u8 = 10;
const CRC_SIZE: usize = 4;

struct Protocol<R> {
    reader: io::BufReader<R>
}

impl<R: Read + Write> Protocol<R> {
    /// Wrap IO entity for Plugwise protocol handling
    fn new(port: R) -> Protocol<R> {
        Protocol {
            reader: io::BufReader::with_capacity(1000, port)
        }
    }

    /// Send payload
    fn send_message_raw(&mut self, payload: &[u8]) -> io::Result<()> {
        let crc = format!("{:04X}", State::<XMODEM>::calculate(payload)).into_bytes();

        try!(self.reader.get_mut().write(&HEADER));
        try!(self.reader.get_mut().write(payload));
        try!(self.reader.get_mut().write(&crc));
        try!(self.reader.get_mut().write(&FOOTER));

        Ok(())
    }

    /// Wait until a Plugwise message has been received (and skip debugging stuff)
    fn receive_plugwise_message_raw(&mut self) -> io::Result<(Vec<u8>, usize, usize)> {
        loop {
            let mut buf = vec![];

            let _ = try!(self.reader.read_until(EOM, &mut buf));

            let header_pos = buf.windows(HEADER.len()).position(|x| *x==HEADER);

            if header_pos.is_some() {
                let header_pos = header_pos.unwrap(); // that would be a surprise when this panics

                let footer_pos = match buf.windows(FOOTER.len()).rposition(|x| *x==FOOTER){
                    None => return Err(io::Error::new(io::ErrorKind::Other,
                                                      "unable to locate footer in received message")),
                                                      Some(v) => v
                };

                return Ok((buf, header_pos, footer_pos))
            }
        }
    }

    /// Wait until a complete and valid message has been received
    fn receive_message_raw(&mut self) -> io::Result<Vec<u8>> {
        let (buf, header_pos, footer_pos) = try!(self.receive_plugwise_message_raw());

        // chop off header, footer and CRC
        let payload = buf.iter().take(footer_pos - CRC_SIZE).skip(header_pos + HEADER.len());
        let crc = buf.iter().skip(footer_pos - CRC_SIZE).take(CRC_SIZE);
        let crc = crc.take(4).fold(0, |acc, &item| {
            acc << 4 | match item {
                b'0' => 0, b'1' => 1, b'2' => 2,  b'3' => 3,  b'4' => 4,  b'5' => 5,  b'6' => 6,  b'7' => 7,
                b'8' => 8, b'9' => 9, b'A' => 10, b'B' => 11, b'C' => 12, b'D' => 13, b'E' => 14, b'F' => 15,
                _ => 0
            }
        });

        // CRC check
        let mut state = State::<XMODEM>::new();
        for byte in payload {
            state.update(&[*byte]);
        }

        if crc != state.get() {
            return Err(io::Error::new(io::ErrorKind::Other, "CRC error"));
        }

        let payload = buf.iter().take(footer_pos - CRC_SIZE).skip(header_pos + HEADER.len());

        Ok(payload.cloned().collect())
    }

    /// Keep receiving messages until the given message identifier has been received
    fn expect_message(&mut self, expected_message_id: MessageId) -> io::Result<Message> {
        loop {
            let msg = try!(self.receive_message_raw());
            let msg = try!(Message::from_payload(&msg));

            println!("< {:?}", msg); // XXX

            if msg.to_message_id() == expected_message_id {
                return Ok(msg)
            }
        }
    }

    /// Initialize the Plugwise USB stick
    fn initialize(&mut self) -> io::Result<ResInitialize> {
        let msg = try!(Message::ReqInitialize.to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResInitialize));

        match msg {
            Message::ResInitialize(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected initialization response"))
        }
    }

    /// Get info from a circle
    fn get_info(&mut self, mac: u64) -> io::Result<ResInfo> {
        let msg = try!(Message::ReqInfo(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResInfo));

        match msg {
            Message::ResInfo(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Switch a circle
    fn switch(&mut self, mac: u64, on: bool) -> io::Result<()> {
        let msg = try!(Message::ReqSwitch(ReqHeader{mac: mac}, ReqSwitch{on: on}).to_payload());
        try!(self.send_message_raw(&msg));

        let _ = try!(self.expect_message(MessageId::Ack));

        Ok(())
    }

    /// Calibrate a circle
    fn calibrate(&mut self, mac: u64) -> io::Result<ResCalibration> {
        let msg = try!(Message::ReqCalibration(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResCalibration));

        match msg {
            Message::ResCalibration(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve power buffer
    fn get_power_buffer(&mut self, mac: u64, addr: u32) -> io::Result<ResPowerBuffer> {
        let msg = try!(Message::ReqPowerBuffer(ReqHeader{mac: mac},
                                               ReqPowerBuffer{logaddr: addr}).to_payload());

        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResPowerBuffer));

        match msg {
            Message::ResPowerBuffer(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve actual power usage
    fn get_power_usage(&mut self, mac: u64) -> io::Result<ResPowerUse> {
        let msg = try!(Message::ReqPowerUse(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResPowerUse));

        match msg {
            Message::ResPowerUse(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve actual power usage
    fn get_clock_info(&mut self, mac: u64) -> io::Result<ResClockInfo> {
        let msg = try!(Message::ReqClockInfo(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResClockInfo));

        match msg {
            Message::ResClockInfo(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Set clock
    fn set_clock(&mut self, mac: u64, clock_set: ReqClockSet) -> io::Result<()> {
        let msg = try!(Message::ReqClockSet(ReqHeader{mac: mac}, clock_set).to_payload());

        try!(self.send_message_raw(&msg));

        let _ = try!(self.expect_message(MessageId::Ack));

        Ok(())
    }
}

fn run() -> io::Result<()> {
    let mut path = home_dir().unwrap(); // XXX
    path.push("plugwise.toml");
    let mut file = try!(File::open(&path));
    let mut config = String::new();
    try!(file.read_to_string(&mut config));
    let config = toml::Parser::new(&config).parse().unwrap(); // XXX

    let mut port = try!(serial::open("/dev/ttyUSB0"));
    try!(port.configure(|settings| {
        settings.set_baud_rate(serial::Baud115200);
        settings.set_char_size(serial::Bits8);
        settings.set_parity(serial::ParityNone);
        settings.set_stop_bits(serial::Stop1);
    }));

    port.set_timeout(Duration::milliseconds(1000));

    let mut plugwise = Protocol::new(port);

    let _ = try!(plugwise.initialize());

    for (_, item) in config {
        if let Some(mac) = item.as_table().unwrap().get("mac") { // XXX
            let mac = mac.as_str().unwrap(); // XXX
            let mac = u64::from_str_radix(mac, 16).unwrap(); // XXX

            //try!(plugwise.set_clock(mac, ReqClockSet::new_from_tm(now())));

            let info = try!(plugwise.get_info(mac));

            println!("{}", info.datetime.to_tm().unwrap().asctime());

            //try!(plugwise.switch(mac, !info.relay_state));
            //let _ = try!(plugwise.calibrate(mac));
            //let _ = try!(plugwise.get_power_buffer(mac, 0));
            //let _ = try!(plugwise.get_power_usage(mac));
            let _ = try!(plugwise.get_clock_info(mac));
        }
    }

    Ok(())
}

fn main() {
    run().unwrap();
}
<commit_msg>Improve Ack handling (when applicable)<commit_after>extern crate serial;
extern crate time;
extern crate crc16;
extern crate toml;

mod messages;

use std::io;
use std::io::prelude::*;
use serial::prelude::*;
use time::Duration;
use crc16::*;
use std::fs::File;
use std::env::home_dir;
use messages::*;

const HEADER: [u8; 4] = [5, 5, 3, 3];
const FOOTER: [u8; 2] = [13, 10];
const EOM: u8 = 10;
const CRC_SIZE: usize = 4;

struct Protocol<R> {
    reader: io::BufReader<R>
}

impl<R: Read + Write> Protocol<R> {
    /// Wrap IO entity for Plugwise protocol handling
    fn new(port: R) -> Protocol<R> {
        Protocol {
            reader: io::BufReader::with_capacity(1000, port)
        }
    }

    /// Send payload
    fn send_message_raw(&mut self, payload: &[u8]) -> io::Result<()> {
        let crc = format!("{:04X}", State::<XMODEM>::calculate(payload)).into_bytes();

        try!(self.reader.get_mut().write(&HEADER));
        try!(self.reader.get_mut().write(payload));
        try!(self.reader.get_mut().write(&crc));
        try!(self.reader.get_mut().write(&FOOTER));

        Ok(())
    }

    /// Wait until a Plugwise message has been received (and skip debugging stuff)
    fn receive_plugwise_message_raw(&mut self) -> io::Result<(Vec<u8>, usize, usize)> {
        loop {
            let mut buf = vec![];

            let _ = try!(self.reader.read_until(EOM, &mut buf));

            let header_pos = buf.windows(HEADER.len()).position(|x| *x==HEADER);

            if header_pos.is_some() {
                let header_pos = header_pos.unwrap(); // that would be a surprise when this panics

                let footer_pos = match buf.windows(FOOTER.len()).rposition(|x| *x==FOOTER){
                    None => return Err(io::Error::new(io::ErrorKind::Other,
                                                      "unable to locate footer in received message")),
                                                      Some(v) => v
                };

                return Ok((buf, header_pos, footer_pos))
            }
        }
    }

    /// Wait until a complete and valid message has been received
    fn receive_message_raw(&mut self) -> io::Result<Vec<u8>> {
        let (buf, header_pos, footer_pos) = try!(self.receive_plugwise_message_raw());

        // chop off header, footer and CRC
        let payload = buf.iter().take(footer_pos - CRC_SIZE).skip(header_pos + HEADER.len());
        let crc = buf.iter().skip(footer_pos - CRC_SIZE).take(CRC_SIZE);
        let crc = crc.take(4).fold(0, |acc, &item| {
            acc << 4 | match item {
                b'0' => 0, b'1' => 1, b'2' => 2,  b'3' => 3,  b'4' => 4,  b'5' => 5,  b'6' => 6,  b'7' => 7,
                b'8' => 8, b'9' => 9, b'A' => 10, b'B' => 11, b'C' => 12, b'D' => 13, b'E' => 14, b'F' => 15,
                _ => 0
            }
        });

        // CRC check
        let mut state = State::<XMODEM>::new();
        for byte in payload {
            state.update(&[*byte]);
        }

        if crc != state.get() {
            return Err(io::Error::new(io::ErrorKind::Other, "CRC error"));
        }

        let payload = buf.iter().take(footer_pos - CRC_SIZE).skip(header_pos + HEADER.len());

        Ok(payload.cloned().collect())
    }

    /// Keep receiving messages until the given message identifier has been received
    fn expect_message(&mut self, expected_message_id: MessageId) -> io::Result<Message> {
        loop {
            let msg = try!(self.receive_message_raw());
            let msg = try!(Message::from_payload(&msg));

            println!("< {:?}", msg); // XXX

            if msg.to_message_id() == expected_message_id {
                return Ok(msg)
            }
        }
    }

    fn wait_for_mac_ack(&mut self, expected_mac: u64) -> io::Result<()> {
        loop {
            let ack = try!(self.expect_message(MessageId::Ack));
            if let Message::Ack(_, ack) = ack {
                if let Some(ack_mac) = ack.mac {
                    if ack_mac == expected_mac {
                        break;
                    }
                }
            }
        }

        Ok(())
    }

    /// Initialize the Plugwise USB stick
    fn initialize(&mut self) -> io::Result<ResInitialize> {
        let msg = try!(Message::ReqInitialize.to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResInitialize));

        match msg {
            Message::ResInitialize(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected initialization response"))
        }
    }

    /// Get info from a circle
    fn get_info(&mut self, mac: u64) -> io::Result<ResInfo> {
        let msg = try!(Message::ReqInfo(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResInfo));

        match msg {
            Message::ResInfo(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Switch a circle
    fn switch(&mut self, mac: u64, on: bool) -> io::Result<()> {
        let msg = try!(Message::ReqSwitch(ReqHeader{mac: mac}, ReqSwitch{on: on}).to_payload());
        try!(self.send_message_raw(&msg));

        try!(self.wait_for_mac_ack(mac));

        Ok(())
    }

    /// Calibrate a circle
    fn calibrate(&mut self, mac: u64) -> io::Result<ResCalibration> {
        let msg = try!(Message::ReqCalibration(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResCalibration));

        match msg {
            Message::ResCalibration(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve power buffer
    fn get_power_buffer(&mut self, mac: u64, addr: u32) -> io::Result<ResPowerBuffer> {
        let msg = try!(Message::ReqPowerBuffer(ReqHeader{mac: mac},
                                               ReqPowerBuffer{logaddr: addr}).to_payload());

        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResPowerBuffer));

        match msg {
            Message::ResPowerBuffer(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve actual power usage
    fn get_power_usage(&mut self, mac: u64) -> io::Result<ResPowerUse> {
        let msg = try!(Message::ReqPowerUse(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResPowerUse));

        match msg {
            Message::ResPowerUse(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Retrieve actual power usage
    fn get_clock_info(&mut self, mac: u64) -> io::Result<ResClockInfo> {
        let msg = try!(Message::ReqClockInfo(ReqHeader{mac: mac}).to_payload());
        try!(self.send_message_raw(&msg));

        let msg = try!(self.expect_message(MessageId::ResClockInfo));

        match msg {
            Message::ResClockInfo(_, res) => Ok(res),
            _ => Err(io::Error::new(io::ErrorKind::Other, "unexpected information response"))
        }
    }

    /// Set clock
    fn set_clock(&mut self, mac: u64, clock_set: ReqClockSet) -> io::Result<()> {
        let msg = try!(Message::ReqClockSet(ReqHeader{mac: mac}, clock_set).to_payload());
        try!(self.send_message_raw(&msg));

        try!(self.wait_for_mac_ack(mac));

        Ok(())
    }
}

fn run() -> io::Result<()> {
    let mut path = home_dir().unwrap(); // XXX
    path.push("plugwise.toml");
    let mut file = try!(File::open(&path));
    let mut config = String::new();
    try!(file.read_to_string(&mut config));
    let config = toml::Parser::new(&config).parse().unwrap(); // XXX

    let mut port = try!(serial::open("/dev/ttyUSB0"));
    try!(port.configure(|settings| {
        settings.set_baud_rate(serial::Baud115200);
        settings.set_char_size(serial::Bits8);
        settings.set_parity(serial::ParityNone);
        settings.set_stop_bits(serial::Stop1);
    }));

    port.set_timeout(Duration::milliseconds(1000));

    let mut plugwise = Protocol::new(port);

    let _ = try!(plugwise.initialize());

    for (_, item) in config {
        if let Some(mac) = item.as_table().unwrap().get("mac") { // XXX
            let mac = mac.as_str().unwrap(); // XXX
            let mac = u64::from_str_radix(mac, 16).unwrap(); // XXX

            //try!(plugwise.set_clock(mac, ReqClockSet::new_from_tm(time::now())));

            let info = try!(plugwise.get_info(mac));

            println!("{}", info.datetime.to_tm().unwrap().asctime());

            //try!(plugwise.switch(mac, !info.relay_state));
            //let _ = try!(plugwise.calibrate(mac));
            //let _ = try!(plugwise.get_power_buffer(mac, 0));
            //let _ = try!(plugwise.get_power_usage(mac));
            let _ = try!(plugwise.get_clock_info(mac));
        }
    }

    Ok(())
}

fn main() {
    run().unwrap();
}
<|endoftext|>