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

extern crate quire;
extern crate argparse;
extern crate serialize;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

extern crate config;
#[phase(plugin, link)] extern crate container;

use std::io::stderr;
use std::io::ALL_PERMISSIONS;
use std::io::{TypeSymlink, TypeDirectory, PathDoesntExist, FileNotFound};
use std::os::{getcwd, set_exit_status, self_exe_path};
use std::io::fs::{mkdir, copy, readlink, symlink};
use std::io::fs::PathExtensions;

use config::find_config;
use container::signal;
use container::monitor::{Monitor, Executor};
use container::container::{Command};
use container::mount::{mount_tmpfs, bind_mount, unmount};
use container::mount::{mount_ro_recursive, mount_pseudo};
use container::root::change_root;
use settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List};

mod settings;

fn make_mountpoint(project_root: &Path) -> Result<(), String> {
    let vagga_dir = project_root.join(".vagga");
    match vagga_dir.lstat() {
        Ok(stat) if stat.kind == TypeSymlink => {
            return Err(concat!("The `.vagga` dir can't be a symlink. ",
                               "Please run `unlink .vagga`").to_string());
        }
        Ok(stat) if stat.kind == TypeDirectory => {
            // ok
        }
        Ok(_) => {
            return Err(concat!("The `.vagga` must be a directory. ",
                               "Please run `unlink .vagga`").to_string());
        }
        Err(ref e) if e.kind == PathDoesntExist => {
            try!(mkdir(&vagga_dir, ALL_PERMISSIONS)
                .map_err(|e| format!("Can't create {}: {}",
                                     vagga_dir.display(), e)));
        }
        Err(ref e) => {
            return Err(format!("Can't stat `.vagga`: {}", e));
        }
    }
    let mnt_dir = vagga_dir.join(".mnt");
    match mnt_dir.lstat() {
        Ok(stat) if stat.kind == TypeSymlink => {
            return Err(concat!("The `.vagga/.mnt` dir can't be a symlink. ",
                               "Please run `unlink .vagga/.mnt`").to_string());
        }
        Ok(stat) if stat.kind == TypeDirectory => {
            // ok
        }
        Ok(_) => {
            return Err(concat!("The `.vagga/.mnt` must be a directory. ",
                               "Please run `unlink .vagga/.mnt`").to_string());
        }
        Err(ref e) if e.kind == PathDoesntExist => {
            try!(mkdir(&mnt_dir, ALL_PERMISSIONS)
                .map_err(|e| format!("Can't create {}: {}",
                                     mnt_dir.display(), e)));
        }
        Err(ref e) => {
            return Err(format!("Can't stat `.vagga/.mnt`: {}", e));
        }
    }
    return Ok(());
}

fn create_storage_dir(storage_dir: &Path, project_root: &Path)
    -> Result<Path, String>
{
    let name = match project_root.filename_str() {
        Some(name) => name,
        None => return Err(format!(
            "Project dir `{}` is either root or has bad characters",
            project_root.display())),
    };
    let path = storage_dir.join(name);
    if !path.exists() {
        return Ok(path);
    }
    for i in range(1i, 101i) {
        let result = format!("{}-{}", name, i);
        let path = storage_dir.join(result);
        if !path.exists() {
            return Ok(path);
        }
    }
    return Err(format!("Too many similar paths named {} in {}",
        name, storage_dir.display()));
}

fn make_local_roots(project_root: &Path, settings: &MergedSettings)
    -> Result<Path, String>
{
    if let Some(ref dir) = settings.storage_dir {
        let lnkdir = project_root.join(".vagga/.lnk");
        match readlink(&lnkdir) {
            Ok(lnk) => {
                if let Some(name) = lnk.filename() {
                    let target = dir.join(name);
                    if Path::new(lnk.dirname()) != *dir {
                        return Err(concat!("You have set storage_dir to {}, ",
                            "but .vagga/.lnk points to {}. You probably need ",
                            "to run `ln -sfn {} .vagga/.lnk`").to_string());
                    }
                    if !lnkdir.exists() {
                        return Err(concat!("Your .vagga/.lnk points to a ",
                            "non-existent directory. Presumably you deleted ",
                            "dir {}. Just remove .vagga/.lnk now."
                            ).to_string());
                    }
                    return Ok(target);
                } else {
                    return Err(format!(concat!("Bad link .vagga/.lnk: {}.",
                        " You are pobably need to remove it now"),
                        lnk.display()));
                }
            }
            Err(ref e) if e.kind == FileNotFound => {
                let target = try!(create_storage_dir(dir, project_root));
                try_str!(mkdir(&target, ALL_PERMISSIONS));
                try_str!(symlink(&target, &lnkdir));
                return Ok(target)
            }
            Err(ref e) => {
                return Err(format!("Can't read link .vagga/.lnk: {}", e));
            }
        };
    } else {
        let local_roots = project_root.join(".vagga/.roots");
        if !local_roots.exists() {
            try_str!(mkdir(&local_roots, ALL_PERMISSIONS));
        }
        return Ok(local_roots);
    }
}

fn setup_filesystem(project_root: &Path, settings: &MergedSettings)
    -> Result<(), String>
{
    let mnt_dir = project_root.join(".vagga/.mnt");
    try!(make_mountpoint(project_root));
    try!(mount_tmpfs(&mnt_dir, "size=10m"));

    let proc_dir = mnt_dir.join("proc");
    try_str!(mkdir(&proc_dir, ALL_PERMISSIONS));
    try!(mount_pseudo(&proc_dir, "proc", "", false));

    let dev_dir = mnt_dir.join("dev");
    try_str!(mkdir(&dev_dir, ALL_PERMISSIONS));
    try!(bind_mount(&Path::new("/dev"), &dev_dir));

    let vagga_dir = mnt_dir.join("vagga");
    try_str!(mkdir(&vagga_dir, ALL_PERMISSIONS));

    let bin_dir = vagga_dir.join("bin");
    try_str!(mkdir(&bin_dir, ALL_PERMISSIONS));
    try!(bind_mount(&self_exe_path().unwrap(), &bin_dir));
    try!(mount_ro_recursive(&bin_dir));

    let etc_dir = mnt_dir.join("etc");
    try_str!(mkdir(&etc_dir, ALL_PERMISSIONS));
    try!(copy(&Path::new("/etc/hosts"), &etc_dir.join("hosts"))
        .map_err(|e| format!("Error copying /etc/hosts: {}", e)));
    try!(copy(&Path::new("/etc/resolv.conf"), &etc_dir.join("resolv.conf"))
        .map_err(|e| format!("Error copying /etc/resolv.conf: {}", e)));

    let roots_dir = vagga_dir.join("roots");
    try_str!(mkdir(&roots_dir, ALL_PERMISSIONS));
    {
        let local_roots = try!(make_local_roots(project_root, settings));
        try!(bind_mount(&local_roots, &roots_dir));
    }

    let work_dir = mnt_dir.join("work");
    try_str!(mkdir(&work_dir, ALL_PERMISSIONS));
    try!(bind_mount(project_root, &work_dir));

    let old_root = vagga_dir.join("old_root");
    try_str!(mkdir(&old_root, ALL_PERMISSIONS));
    try!(change_root(&mnt_dir, &old_root));
    try!(unmount(&Path::new("/vagga/old_root")));

    return Ok(());
}

pub fn run() -> int {
    let mut err = stderr();
    let mut cmd: String = "".to_string();
    let mut args: Vec<String> = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.refer(&mut cmd)
          .add_argument("command", box Store::<String>,
                "A vagga command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("args", box List::<String>,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    }

    let workdir = getcwd();

    let (config, project_root) = match find_config(&workdir) {
        Ok(tup) => tup,
        Err(e) => {
            err.write_line(e.as_slice()).ok();
            return 126;
        }
    };
    let (ext_settings, int_settings) = match read_settings(&project_root)
    {
        Ok(tup) => tup,
        Err(e) => {
            err.write_line(e.as_slice()).ok();
            return 126;
        }
    };

    match setup_filesystem(&project_root, &ext_settings) {
        Ok(()) => {
            return 0;
        }
        Err(text) =>  {
            err.write_line(text.as_slice()).ok();
            return 121;
        }
    }
}

fn main() {
    signal::block_all();
    let val = run();
    set_exit_status(val);
}
<commit_msg>Implement mounting cache dir<commit_after>#![feature(phase, if_let)]

extern crate quire;
extern crate argparse;
extern crate serialize;
extern crate regex;
#[phase(plugin)] extern crate regex_macros;

extern crate config;
#[phase(plugin, link)] extern crate container;

use std::io::stderr;
use std::io::ALL_PERMISSIONS;
use std::io::{TypeSymlink, TypeDirectory, FileNotFound};
use std::os::{getcwd, set_exit_status, self_exe_path};
use std::io::fs::{mkdir, copy, readlink, symlink};
use std::io::fs::PathExtensions;

use config::find_config;
use container::signal;
use container::monitor::{Monitor, Executor};
use container::container::{Command};
use container::mount::{mount_tmpfs, bind_mount, unmount};
use container::mount::{mount_ro_recursive, mount_pseudo};
use container::root::change_root;
use settings::{read_settings, MergedSettings};
use argparse::{ArgumentParser, Store, List};

mod settings;

fn safe_ensure_dir(dir: &Path) -> Result<(), String> {
    match dir.lstat() {
        Ok(stat) if stat.kind == TypeSymlink => {
            return Err(format!(concat!("The `{0}` dir can't be a symlink. ",
                               "Please run `unlink {0}`"), dir.display()));
        }
        Ok(stat) if stat.kind == TypeDirectory => {
            // ok
        }
        Ok(_) => {
            return Err(format!(concat!("The `{0}` must be a directory. ",
                               "Please run `unlink {0}`"), dir.display()));
        }
        Err(ref e) if e.kind == FileNotFound => {
            try!(mkdir(dir, ALL_PERMISSIONS)
                .map_err(|e| format!("Can't create `{}`: {}",
                                     dir.display(), e)));
        }
        Err(ref e) => {
            return Err(format!("Can't stat `{}`: {}", dir.display(), e));
        }
    }
    return Ok(());
}

fn make_mountpoint(project_root: &Path) -> Result<(), String> {
    let vagga_dir = project_root.join(".vagga");
    try!(safe_ensure_dir(&vagga_dir));
    let mnt_dir = vagga_dir.join(".mnt");
    try!(safe_ensure_dir(&mnt_dir));
    return Ok(());
}

fn create_storage_dir(storage_dir: &Path, project_root: &Path)
    -> Result<Path, String>
{
    let name = match project_root.filename_str() {
        Some(name) => name,
        None => return Err(format!(
            "Project dir `{}` is either root or has bad characters",
            project_root.display())),
    };
    let path = storage_dir.join(name);
    if !path.exists() {
        return Ok(path);
    }
    for i in range(1i, 101i) {
        let result = format!("{}-{}", name, i);
        let path = storage_dir.join(result);
        if !path.exists() {
            return Ok(path);
        }
    }
    return Err(format!("Too many similar paths named {} in {}",
        name, storage_dir.display()));
}

fn vagga_base(project_root: &Path, settings: &MergedSettings)
    -> Result<Path, String>
{
    if let Some(ref dir) = settings.storage_dir {
        let lnkdir = project_root.join(".vagga/.lnk");
        match readlink(&lnkdir) {
            Ok(lnk) => {
                if let Some(name) = lnk.filename() {
                    let target = dir.join(name);
                    if Path::new(lnk.dirname()) != *dir {
                        return Err(concat!("You have set storage_dir to {}, ",
                            "but .vagga/.lnk points to {}. You probably need ",
                            "to run `ln -sfn {} .vagga/.lnk`").to_string());
                    }
                    if !lnkdir.exists() {
                        return Err(concat!("Your .vagga/.lnk points to a ",
                            "non-existent directory. Presumably you deleted ",
                            "dir {}. Just remove .vagga/.lnk now."
                            ).to_string());
                    }
                    return Ok(target);
                } else {
                    return Err(format!(concat!("Bad link .vagga/.lnk: {}.",
                        " You are pobably need to remove it now"),
                        lnk.display()));
                }
            }
            Err(ref e) if e.kind == FileNotFound => {
                let target = try!(create_storage_dir(dir, project_root));
                try!(safe_ensure_dir(&target));
                try_str!(symlink(&target, &lnkdir));
                return Ok(target)
            }
            Err(ref e) => {
                return Err(format!("Can't read link .vagga/.lnk: {}", e));
            }
        };
    } else {
        return Ok(project_root.join(".vagga"));
    }
}

fn make_cache_dir(project_root: &Path, vagga_base: &Path,
    settings: &MergedSettings)
    -> Result<Path, String>
{
    match settings.cache_dir {
        Some(ref dir) if settings.shared_cache => {
            if !dir.exists() {
                return Err(format!(concat!("Cache directory `{}` must exists.",
                    " Please either create it or remove that configuration",
                    " setting"), dir.display()));
            }
            return Ok(dir.clone());
        }
        _ => {
            let dir = vagga_base.join(".cache");
            try!(safe_ensure_dir(&dir));
            return Ok(dir);
        }
   }
}

fn setup_filesystem(project_root: &Path, settings: &MergedSettings)
    -> Result<(), String>
{
    let mnt_dir = project_root.join(".vagga/.mnt");
    try!(make_mountpoint(project_root));
    try!(mount_tmpfs(&mnt_dir, "size=10m"));

    let proc_dir = mnt_dir.join("proc");
    try_str!(mkdir(&proc_dir, ALL_PERMISSIONS));
    try!(mount_pseudo(&proc_dir, "proc", "", false));

    let dev_dir = mnt_dir.join("dev");
    try_str!(mkdir(&dev_dir, ALL_PERMISSIONS));
    try!(bind_mount(&Path::new("/dev"), &dev_dir));

    let vagga_dir = mnt_dir.join("vagga");
    try_str!(mkdir(&vagga_dir, ALL_PERMISSIONS));

    let bin_dir = vagga_dir.join("bin");
    try_str!(mkdir(&bin_dir, ALL_PERMISSIONS));
    try!(bind_mount(&self_exe_path().unwrap(), &bin_dir));
    try!(mount_ro_recursive(&bin_dir));

    let etc_dir = mnt_dir.join("etc");
    try_str!(mkdir(&etc_dir, ALL_PERMISSIONS));
    try!(copy(&Path::new("/etc/hosts"), &etc_dir.join("hosts"))
        .map_err(|e| format!("Error copying /etc/hosts: {}", e)));
    try!(copy(&Path::new("/etc/resolv.conf"), &etc_dir.join("resolv.conf"))
        .map_err(|e| format!("Error copying /etc/resolv.conf: {}", e)));

    let roots_dir = vagga_dir.join("roots");
    try_str!(mkdir(&roots_dir, ALL_PERMISSIONS));
    let vagga_base = try!(vagga_base(project_root, settings));
    let local_roots = vagga_base.join(".roots");
    try!(safe_ensure_dir(&local_roots));
    try!(bind_mount(&local_roots, &roots_dir));

    let cache_dir = vagga_dir.join("cache");
    try_str!(mkdir(&cache_dir, ALL_PERMISSIONS));
    let locl_cache = try!(make_cache_dir(project_root, &vagga_base, settings));
    try!(bind_mount(&locl_cache, &cache_dir));

    let work_dir = mnt_dir.join("work");
    try_str!(mkdir(&work_dir, ALL_PERMISSIONS));
    try!(bind_mount(project_root, &work_dir));

    let old_root = vagga_dir.join("old_root");
    try_str!(mkdir(&old_root, ALL_PERMISSIONS));
    try!(change_root(&mnt_dir, &old_root));
    try!(unmount(&Path::new("/vagga/old_root")));

    return Ok(());
}

pub fn run() -> int {
    let mut err = stderr();
    let mut cmd: String = "".to_string();
    let mut args: Vec<String> = Vec::new();
    {
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Runs a command in container, optionally builds container if that
            does not exists or outdated.

            Run `vagga` without arguments to see the list of commands.
            ");
        ap.refer(&mut cmd)
          .add_argument("command", box Store::<String>,
                "A vagga command to run")
          .required();
        ap.refer(&mut args)
          .add_argument("args", box List::<String>,
                "Arguments for the command");
        ap.stop_on_first_argument(true);
        match ap.parse_args() {
            Ok(()) => {}
            Err(0) => return 0,
            Err(_) => return 122,
        }
    }

    let workdir = getcwd();

    let (config, project_root) = match find_config(&workdir) {
        Ok(tup) => tup,
        Err(e) => {
            err.write_line(e.as_slice()).ok();
            return 126;
        }
    };
    let (ext_settings, int_settings) = match read_settings(&project_root)
    {
        Ok(tup) => tup,
        Err(e) => {
            err.write_line(e.as_slice()).ok();
            return 126;
        }
    };

    match setup_filesystem(&project_root, &ext_settings) {
        Ok(()) => {
            return 0;
        }
        Err(text) =>  {
            err.write_line(text.as_slice()).ok();
            return 121;
        }
    }
}

fn main() {
    signal::block_all();
    let val = run();
    set_exit_status(val);
}
<|endoftext|>


<commit_before>#![deny(unused_import_braces,
        unused_comparisons, unused_must_use,
        unused_variables, non_shorthand_field_patterns,
        unreachable_code)]

extern crate trie;
extern crate sputnikvm;
extern crate sha3;
extern crate block;
extern crate rlp;

use sputnikvm::{H256, U256, M256, Address};
use sputnikvm::vm::{self, ValidTransaction, HeaderParams, Memory, TransactionVM, VM,
                    AccountCommitment, Patch, SeqMemory, AccountState};
use sputnikvm::vm::errors::{PreExecutionError, RequireError};
use sha3::{Keccak256, Digest};
use trie::{Trie, SecureTrie, FixedSecureTrie, DatabaseGuard, MemoryDatabase, MemoryDatabaseGuard, Database, DatabaseOwned};
use block::{Account, Transaction};
use std::collections::HashMap;
use std::cmp::min;

pub struct Stateful<G, D> {
    database: D,
    code_hashes: G,
    root: H256,
}

impl<G, D> Stateful<G, D> {
    pub fn new(database: D, code_hashes: G, root: H256) -> Self {
        Self {
            database,
            code_hashes,
            root
        }
    }
}

impl<G: Default, D: Default> Default for Stateful<G, D> {
    fn default() -> Self {
        Self {
            database: D::default(),
            code_hashes: G::default(),
            root: MemoryDatabase::new().create_empty().root(),
        }
    }
}

impl<G: DatabaseGuard, D: DatabaseOwned> Stateful<G, D> {
    fn is_empty_hash(hash: H256) -> bool {
        hash == H256::from(Keccak256::digest(&[]).as_slice())
    }

    pub fn call<M: Memory + Default>(
        &self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        assert!(U256::from(most_recent_block_hashes.len()) >=
                min(block.number, U256::from(256)));

        let mut vm = TransactionVM::new(transaction, block.clone(), patch);
        let state = self.database.create_fixed_secure_trie(self.root);

        loop {
            match vm.fire() {
                Ok(()) => break,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            vm.commit_account(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(number)) => {
                    let index = (block.number - number).as_usize();
                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
                },
            }
        }

        vm
    }

    pub fn transit(
        &mut self, accounts: &[vm::Account]
    ) {
        let mut state = self.database.create_fixed_secure_trie(self.root);

        for account in accounts {
            match account.clone() {
                vm::Account::Full {
                    nonce, address, balance, changing_storage, code
                } => {
                    let changing_storage: HashMap<U256, M256> = changing_storage.into();

                    let mut account: Account = state.get(&address).unwrap();

                    let mut storage_trie = self.database.create_fixed_secure_trie(account.storage_root);
                    for (key, value) in changing_storage {
                        storage_trie.insert(H256::from(key), value);
                    }

                    account.balance = balance;
                    account.nonce = nonce;
                    account.storage_root = storage_trie.root();
                    assert!(account.code_hash == H256::from(Keccak256::digest(&code).as_slice()));

                    state.insert(address, account);
                },
                vm::Account::IncreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance + value;

                    state.insert(address, account);
                },
                vm::Account::DecreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance - value;

                    state.insert(address, account);
                },
                vm::Account::Create {
                    nonce, address, balance, storage, code, exists
                } => {
                    if !exists {
                        state.remove(&address);
                    } else {
                        let storage: HashMap<U256, M256> = storage.into();

                        let mut storage_trie = self.database.create_fixed_secure_empty();
                        for (key, value) in storage {
                            storage_trie.insert(H256::from(key), value);
                        }

                        let code_hash = H256::from(Keccak256::digest(&code).as_slice());
                        self.code_hashes.set(code_hash, code);

                        let account = Account {
                            nonce: nonce,
                            balance: balance,
                            storage_root: storage_trie.root(),
                            code_hash
                        };

                        state.insert(address, account);
                    }
                },
            }
        }

        self.root = state.root();
    }

    pub fn execute<M: Memory + Default>(
        &mut self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        let vm = self.call(transaction, block, patch, most_recent_block_hashes);
        let mut accounts = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        self.transit(&accounts);
        vm
    }

    pub fn to_valid(
        &self, transaction: Transaction, patch: &'static Patch
    ) -> Result<ValidTransaction, PreExecutionError> {
        let state = self.database.create_fixed_secure_trie(self.root);
        let mut account_state = AccountState::default();

        loop {
            match ValidTransaction::from_transaction(&transaction, &account_state, patch) {
                Ok(val) => return val,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            account_state.commit(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            account_state.commit(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            account_state.commit(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(_)) => {
                    panic!()
                },
            }
        }
    }

    pub fn root(&self) -> H256 {
        self.root
    }

    pub fn state<'a>(&'a self) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
        self.database.create_fixed_secure_trie::<Address, Account>(self.root())
    }

    pub fn storage_state<'a>(&'a self, address: Address) -> Option<FixedSecureTrie<<D as Database<'a>>::Guard, H256, M256>> {
        let state = self.state();
        let account = state.get(&address);

        match account {
            Some(account) => {
                let storage_root = account.storage_root;
                Some(self.database.create_fixed_secure_trie::<H256, M256>(storage_root))
            },
            None => None,
        }
    }
}

pub type MemoryStateful = Stateful<HashMap<H256, Vec<u8>>, MemoryDatabase>;
<commit_msg>stateful: remove key from the storage when the value is zero<commit_after>#![deny(unused_import_braces,
        unused_comparisons, unused_must_use,
        unused_variables, non_shorthand_field_patterns,
        unreachable_code)]

extern crate trie;
extern crate sputnikvm;
extern crate sha3;
extern crate block;
extern crate rlp;

use sputnikvm::{H256, U256, M256, Address};
use sputnikvm::vm::{self, ValidTransaction, HeaderParams, Memory, TransactionVM, VM,
                    AccountCommitment, Patch, SeqMemory, AccountState};
use sputnikvm::vm::errors::{PreExecutionError, RequireError};
use sha3::{Keccak256, Digest};
use trie::{Trie, SecureTrie, FixedSecureTrie, DatabaseGuard, MemoryDatabase, MemoryDatabaseGuard, Database, DatabaseOwned};
use block::{Account, Transaction};
use std::collections::HashMap;
use std::cmp::min;

pub struct Stateful<G, D> {
    database: D,
    code_hashes: G,
    root: H256,
}

impl<G, D> Stateful<G, D> {
    pub fn new(database: D, code_hashes: G, root: H256) -> Self {
        Self {
            database,
            code_hashes,
            root
        }
    }
}

impl<G: Default, D: Default> Default for Stateful<G, D> {
    fn default() -> Self {
        Self {
            database: D::default(),
            code_hashes: G::default(),
            root: MemoryDatabase::new().create_empty().root(),
        }
    }
}

impl<G: DatabaseGuard, D: DatabaseOwned> Stateful<G, D> {
    fn is_empty_hash(hash: H256) -> bool {
        hash == H256::from(Keccak256::digest(&[]).as_slice())
    }

    pub fn call<M: Memory + Default>(
        &self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        assert!(U256::from(most_recent_block_hashes.len()) >=
                min(block.number, U256::from(256)));

        let mut vm = TransactionVM::new(transaction, block.clone(), patch);
        let state = self.database.create_fixed_secure_trie(self.root);

        loop {
            match vm.fire() {
                Ok(()) => break,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            vm.commit_account(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(number)) => {
                    let index = (block.number - number).as_usize();
                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
                },
            }
        }

        vm
    }

    pub fn transit(
        &mut self, accounts: &[vm::Account]
    ) {
        let mut state = self.database.create_fixed_secure_trie(self.root);

        for account in accounts {
            match account.clone() {
                vm::Account::Full {
                    nonce, address, balance, changing_storage, code
                } => {
                    let changing_storage: HashMap<U256, M256> = changing_storage.into();

                    let mut account: Account = state.get(&address).unwrap();

                    let mut storage_trie = self.database.create_fixed_secure_trie(account.storage_root);
                    for (key, value) in changing_storage {
                        if value == M256::zero() {
                            storage_trie.remove(&H256::from(key));
                        } else {
                            storage_trie.insert(H256::from(key), value);
                        }
                    }

                    account.balance = balance;
                    account.nonce = nonce;
                    account.storage_root = storage_trie.root();
                    assert!(account.code_hash == H256::from(Keccak256::digest(&code).as_slice()));

                    state.insert(address, account);
                },
                vm::Account::IncreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance + value;

                    state.insert(address, account);
                },
                vm::Account::DecreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance - value;

                    state.insert(address, account);
                },
                vm::Account::Create {
                    nonce, address, balance, storage, code, exists
                } => {
                    if !exists {
                        state.remove(&address);
                    } else {
                        let storage: HashMap<U256, M256> = storage.into();

                        let mut storage_trie = self.database.create_fixed_secure_empty();
                        for (key, value) in storage {
                            if value == M256::zero() {
                                storage_trie.remove(&H256::from(key));
                            } else {
                                storage_trie.insert(H256::from(key), value);
                            }
                        }

                        let code_hash = H256::from(Keccak256::digest(&code).as_slice());
                        self.code_hashes.set(code_hash, code);

                        let account = Account {
                            nonce: nonce,
                            balance: balance,
                            storage_root: storage_trie.root(),
                            code_hash
                        };

                        state.insert(address, account);
                    }
                },
            }
        }

        self.root = state.root();
    }

    pub fn execute<M: Memory + Default>(
        &mut self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        let vm = self.call(transaction, block, patch, most_recent_block_hashes);
        let mut accounts = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        self.transit(&accounts);
        vm
    }

    pub fn to_valid(
        &self, transaction: Transaction, patch: &'static Patch
    ) -> Result<ValidTransaction, PreExecutionError> {
        let state = self.database.create_fixed_secure_trie(self.root);
        let mut account_state = AccountState::default();

        loop {
            match ValidTransaction::from_transaction(&transaction, &account_state, patch) {
                Ok(val) => return val,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            account_state.commit(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            account_state.commit(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            account_state.commit(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            account_state.commit(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(_)) => {
                    panic!()
                },
            }
        }
    }

    pub fn root(&self) -> H256 {
        self.root
    }

    pub fn state<'a>(&'a self) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
        self.database.create_fixed_secure_trie::<Address, Account>(self.root())
    }

    pub fn storage_state<'a>(&'a self, address: Address) -> Option<FixedSecureTrie<<D as Database<'a>>::Guard, H256, M256>> {
        let state = self.state();
        let account = state.get(&address);

        match account {
            Some(account) => {
                let storage_root = account.storage_root;
                Some(self.database.create_fixed_secure_trie::<H256, M256>(storage_root))
            },
            None => None,
        }
    }
}

pub type MemoryStateful = Stateful<HashMap<H256, Vec<u8>>, MemoryDatabase>;
<|endoftext|>


<commit_before>use math::rich_number::RichNumber;

use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_context::{EvalContext, EvalResult, EvalError};

pub fn setup_defaults(context: &mut EvalContext) {
    context.set_constant("PREFIX", Fixity::Prefix.to_string());
    context.set_constant("INFIX", Fixity::Infix.to_string());
    context.set_constant("POSTFIX", Fixity::Postfix.to_string());

    context.define_built_in_method_defaults(
        "operator",
        4,
        BuiltInFunction::new(operator),
    );

    context.define_built_in_method_defaults(
        "defineUnit",
        1,
        BuiltInFunction::new(define_unit),
    );

    context.define_built_in_method_defaults(
        "convert",
        2,
        BuiltInFunction::new(convert),
    );

    context.define_built_in_method_defaults(
        "unitFor",
        1,
        BuiltInFunction::new(unit_for),
    );

    context.define_built_in_method_defaults(
        "valueOf",
        1,
        BuiltInFunction::new(value_of),
    );

    context.define_built_in_method_defaults(
        "conversion",
        3,
        BuiltInFunction::new(conversion),
    );
}

fn operator(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 4));

    try!(expect_param_is(params[0].is_constant(),
        "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
    try!(expect_param_is(params[1].is_number(),
        "Precedence must be a numeric value"));
    try!(expect_param_is(params[2].is_constant(),
        "Name of the operator must be a string literal"));
    try!(expect_param_is(params[3].is_function(),
        "Function definition must be either an existing function or an anonymous function"));

    let fixity = {
        let fx = Fixity::from_str(&params.remove(0).unwrap_constant());
        try!(expect_param_is(fx.is_some(),
            "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
        fx.unwrap()
    };

    let precedence = {
        let p = params.remove(0).unwrap_number();
        try!(expect_param_is(p.is_dimensionless(),
            "Precedence cannot have a unit"));
        p.value as u8
    };

    let name = &params.remove(0).unwrap_constant();
    let function = params.remove(0);

    debug_assert!(params.is_empty(), "Not parameters used");

    match function {
        ContextItem::Definition { function, .. } => {
            context.define(name, fixity, precedence, function);
        },
        ContextItem::BuiltInMethod { function, params, .. } => {
            context.define_built_in_method(name, fixity, precedence, params, function)
        },
        _ => unreachable!(),
    };

    Ok(ContextItem::Nothing)
}

fn define_unit(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_constant(),
        "Name of the unit must be a string literal"));

    let unit_name = &params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not parameters used");

    let unit = context.create_unit(unit_name);

    context.define_built_in_method_defaults(
        unit_name,
        1,
        BuiltInFunction::new(move |context, mut params| {
            try!(expect_params(&params, 1));
            try!(expect_param_is(params[0].is_number(),
                "Value to convert must be numeric"));

            let value = params.remove(0).unwrap_number();
            debug_assert!(params.is_empty(), "Not parameters used");

            context.convert(value, Some(unit))
        }),
    );

    Ok(ContextItem::Nothing)
}

fn convert(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 2));

    unimplemented!();
}

fn unit_for(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    unimplemented!();
}

fn value_of(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    unimplemented!();
}

fn conversion(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 3));

    unimplemented!();
}

fn expect_params(params: &Vec<ContextItem>, nparams: usize) -> Result<(), EvalError> {
    if params.len() != nparams {
        Err(EvalError::ExpectedParams(nparams))
    }
    else {
        Ok(())
    }
}

fn expect_param_is(cond: bool, message: &str) -> Result<(), EvalError> {
    if cond {
        Ok(())
    }
    else {
        Err(EvalError::InvalidParam(message.to_owned()))
    }
}

<commit_msg>Starting to add tests for defaults<commit_after>use math::rich_number::RichNumber;

use eval::fixity::Fixity;
use eval::context_item::ContextItem;
use eval::built_in_function::BuiltInFunction;
use eval::eval_context::{EvalContext, EvalResult, EvalError};

pub fn setup_defaults(context: &mut EvalContext) {
    setup_fixity_constants(context);

    context.define_built_in_method_defaults(
        "operator",
        4,
        BuiltInFunction::new(operator),
    );

    context.define_built_in_method_defaults(
        "defineUnit",
        1,
        BuiltInFunction::new(define_unit),
    );

    context.define_built_in_method_defaults(
        "convert",
        2,
        BuiltInFunction::new(convert),
    );

    context.define_built_in_method_defaults(
        "unitFor",
        1,
        BuiltInFunction::new(unit_for),
    );

    context.define_built_in_method_defaults(
        "valueOf",
        1,
        BuiltInFunction::new(value_of),
    );

    context.define_built_in_method_defaults(
        "conversion",
        3,
        BuiltInFunction::new(conversion),
    );
}

pub fn setup_fixity_constants(context: &mut EvalContext) {
    context.set_constant("PREFIX", Fixity::Prefix.to_string());
    context.set_constant("INFIX", Fixity::Infix.to_string());
    context.set_constant("POSTFIX", Fixity::Postfix.to_string());
}

pub fn operator(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 4));

    try!(expect_param_is(params[0].is_constant(),
        "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
    try!(expect_param_is(params[1].is_number(),
        "Precedence must be a numeric value"));
    try!(expect_param_is(params[2].is_constant(),
        "Name of the operator must be a string literal"));
    try!(expect_param_is(params[3].is_function(),
        "Function definition must be either an existing function or an anonymous function"));

    let fixity = {
        let fx = Fixity::from_str(&params.remove(0).unwrap_constant());
        try!(expect_param_is(fx.is_some(),
            "Fixity must be one of the constants PREFIX, INFIX, or POSTFIX"));
        fx.unwrap()
    };

    let precedence = {
        let p = params.remove(0).unwrap_number();
        try!(expect_param_is(p.is_dimensionless(),
            "Precedence cannot have a unit"));
        p.value as u8
    };

    let name = &params.remove(0).unwrap_constant();
    let function = params.remove(0);

    debug_assert!(params.is_empty(), "Not parameters used");

    match function {
        ContextItem::Definition { function, .. } => {
            context.define(name, fixity, precedence, function);
        },
        ContextItem::BuiltInMethod { function, params, .. } => {
            context.define_built_in_method(name, fixity, precedence, params, function)
        },
        _ => unreachable!(),
    };

    Ok(ContextItem::Nothing)
}

pub fn define_unit(context: &mut EvalContext, mut params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    try!(expect_param_is(params[0].is_constant(),
        "Name of the unit must be a string literal"));

    let unit_name = &params.remove(0).unwrap_constant();
    debug_assert!(params.is_empty(), "Not parameters used");

    let unit = context.create_unit(unit_name);

    context.define_built_in_method_defaults(
        unit_name,
        1,
        BuiltInFunction::new(move |context, mut params| {
            try!(expect_params(&params, 1));
            try!(expect_param_is(params[0].is_number(),
                "Value to convert must be numeric"));

            let value = params.remove(0).unwrap_number();
            debug_assert!(params.is_empty(), "Not parameters used");

            context.convert(value, Some(unit))
        }),
    );

    Ok(ContextItem::Nothing)
}

pub fn convert(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 2));

    unimplemented!();
}

pub fn unit_for(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    unimplemented!();
}

pub fn value_of(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 1));

    unimplemented!();
}

pub fn conversion(context: &mut EvalContext, params: Vec<ContextItem>) -> EvalResult {
    try!(expect_params(&params, 3));

    unimplemented!();
}

fn expect_params(params: &Vec<ContextItem>, nparams: usize) -> Result<(), EvalError> {
    if params.len() != nparams {
        Err(EvalError::ExpectedParams(nparams))
    }
    else {
        Ok(())
    }
}

fn expect_param_is(cond: bool, message: &str) -> Result<(), EvalError> {
    if cond {
        Ok(())
    }
    else {
        Err(EvalError::InvalidParam(message.to_owned()))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use eval::fixity::Fixity;
    use eval::eval_context::EvalContext;

    #[test]
    fn fixity_constants() {
        let mut context = EvalContext::new();
        setup_fixity_constants(&mut context);

        let lookup_fixity = |name| Fixity::from_str(&context.get(name).unwrap().unwrap_constant()).unwrap();

        assert_eq!(lookup_fixity("PREFIX"), Fixity::Prefix);
        assert_eq!(lookup_fixity("INFIX"), Fixity::Infix);
        assert_eq!(lookup_fixity("POSTFIX"), Fixity::Postfix);
    }
}

<|endoftext|>


<commit_before>extern crate hyper;
extern crate juniper;
extern crate juniper_hyper;
extern crate pretty_env_logger;

use hyper::{
    service::{make_service_fn, service_fn},
    Body, Method, Response, Server, StatusCode,
};
use juniper::{
    tests::{model::Database, schema::Query},
    EmptyMutation, RootNode,
};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 3000).into();

    let db = Arc::new(Database::new());
    let root_node = Arc::new(RootNode::new(Query, EmptyMutation::<Database>::new()));

    let new_service = make_service_fn(move |_| {
        let root_node = root_node.clone();
        let ctx = db.clone();

        async move {
            Ok::<_, hyper::Error>(service_fn(move |req| {
                let root_node = root_node.clone();
                let ctx = ctx.clone();
                async move {
                    match (req.method(), req.uri().path()) {
                        (&Method::GET, "/") => juniper_hyper::graphiql("/graphql").await,
                        (&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
                            juniper_hyper::graphql(root_node, ctx, req).await
                        }
                        _ => {
                            let mut response = Response::new(Body::empty());
                            *response.status_mut() = StatusCode::NOT_FOUND;
                            Ok(response)
                        }
                    }
                }
            }))
        }
    });

    let server = Server::bind(&addr).serve(new_service);
    println!("Listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e)
    }
}
<commit_msg>Extern crates are no longer necessary (#536)<commit_after>use hyper::{
    service::{make_service_fn, service_fn},
    Body, Method, Response, Server, StatusCode,
};
use juniper::{
    tests::{model::Database, schema::Query},
    EmptyMutation, RootNode,
};
use std::sync::Arc;

#[tokio::main]
async fn main() {
    pretty_env_logger::init();

    let addr = ([127, 0, 0, 1], 3000).into();

    let db = Arc::new(Database::new());
    let root_node = Arc::new(RootNode::new(Query, EmptyMutation::<Database>::new()));

    let new_service = make_service_fn(move |_| {
        let root_node = root_node.clone();
        let ctx = db.clone();

        async move {
            Ok::<_, hyper::Error>(service_fn(move |req| {
                let root_node = root_node.clone();
                let ctx = ctx.clone();
                async move {
                    match (req.method(), req.uri().path()) {
                        (&Method::GET, "/") => juniper_hyper::graphiql("/graphql").await,
                        (&Method::GET, "/graphql") | (&Method::POST, "/graphql") => {
                            juniper_hyper::graphql(root_node, ctx, req).await
                        }
                        _ => {
                            let mut response = Response::new(Body::empty());
                            *response.status_mut() = StatusCode::NOT_FOUND;
                            Ok(response)
                        }
                    }
                }
            }))
        }
    });

    let server = Server::bind(&addr).serve(new_service);
    println!("Listening on http://{}", addr);

    if let Err(e) = server.await {
        eprintln!("server error: {}", e)
    }
}
<|endoftext|>


<commit_before>//! Handling of DICOM values with the PN (person name) value representation
//! as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/// A DICOM _Person Name_ (PN value representation).
///
/// Values of this type keep
/// family name, given name, middle name, prefix and suffix
/// as borrowed values.
/// All name components are optional.
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a [`PersonName`] from its components.
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert the person name into a DICOM formatted string.
    ///
    /// Name components are interspersed with a `'^'` separator.
    /// Leading null components produce a separator,
    /// while trailing components do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let mut it  = components.iter().rev().peekable();
        // consume trailing None (null) components
        while it.next_if(|component| component.is_none()).is_some(){}

        let mut it = it.rev().peekable();
        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }
    /// Retrieves a PersonName from a Dicom formatted string slice.
    /// The Dicom string representation is split by '^' separator into its respective components.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }
    /// Retrieve a builder for a PersonName
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }

    /// Insert or update the family name component.
    pub fn with_family(&mut self, family_name: &'a str) -> &mut Self {
        self.person_name.family = Some(family_name);
        self
    }

    /// Insert or update the middle name component.
    pub fn with_middle(&mut self, middle_name: &'a str) -> &mut Self {
        self.person_name.middle = Some(middle_name);
        self
    }

    /// Insert or update the given name component.
    pub fn with_given(&mut self, given_name: &'a str) -> &mut Self {
        self.person_name.given = Some(given_name);
        self
    }

    /// Insert or update the prefix component.
    pub fn with_prefix(&mut self, name_prefix: &'a str) -> &mut Self {
        self.person_name.prefix = Some(name_prefix);
        self
    }

    /// Insert or update the suffix component.
    pub fn with_suffix(&mut self, name_suffix: &'a str) -> &mut Self {
        self.person_name.suffix = Some(name_suffix);
        self
    }

    /// Builds the person name with the accumulated components.
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> From<PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

impl<'a> From<&mut PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: &mut PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: None,
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName {
            prefix: Some("Rev."),
            given: None,
            middle: None,
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName {
            prefix: None,
            given: None,
            middle: None,
            family: None,
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: None,
            middle: Some("Robert"),
            family: None,
            suffix: None,
        };
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName {
                prefix: Some("Rev."),
                given: None,
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: None,
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName {
                prefix: None,
                given: Some("John"),
                middle: None,
                family: None,
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: None,
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: None,
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<commit_msg>[core] Extend documentation and testing of person_name<commit_after>//! Handling of DICOM values with the PN (person name) value representation
//! as per PS3.5 sect 6.2.
use std::fmt::{Display, Formatter};

/// A DICOM _Person Name_ (PN value representation).
///
/// Values of this type keep
/// family name, given name, middle name, prefix and suffix
/// as borrowed values.
/// All name components are optional.
///
/// # Example
///
/// A value of type `PersonName` can be obtained
/// either by parsing a DICOM formatted string via [`from_slice`](PersonName::from_slice)
/// or by using the [builder](PersonNameBuilder) API.
///
/// ```
/// # use dicom_core::value::person_name::PersonName;
/// let dr_seuss: PersonName = PersonName::from_slice("Geisel^Theodor^Seuss^Dr.");
/// assert_eq!(&dr_seuss.to_string(), "Dr. Theodor Seuss Geisel");
/// assert_eq!(dr_seuss.prefix(), Some("Dr."));
/// assert_eq!(dr_seuss.given(), Some("Theodor"));
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PersonName<'a> {
    prefix: Option<&'a str>,
    family: Option<&'a str>,
    middle: Option<&'a str>,
    given: Option<&'a str>,
    suffix: Option<&'a str>,
}

/// A builder to construct a [`PersonName`] from its components.
///
/// # Example
///
/// ```
/// # use dicom_core::value::person_name::{PersonName, PersonNameBuilder};
/// let ivan: PersonName = PersonNameBuilder::new()
///     .with_given("Ivan")
///     .with_family("Levanov")
///     .build();
/// assert_eq!(&ivan.to_dicom_string(), "Levanov^Ivan");
/// ```
#[derive(Debug, Copy, Clone)]
pub struct PersonNameBuilder<'a> {
    person_name: PersonName<'a>,
}

impl Display for PersonName<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        let components: &[Option<&str>] = &[
            self.prefix,
            self.given,
            self.middle,
            self.family,
            self.suffix,
        ];

        let mut c_iter = components.iter().flatten().peekable();

        while let Some(component) = c_iter.next() {
            if c_iter.peek().is_some() {
                write!(f, "{} ", component)?
            } else {
                write!(f, "{}", component)?
            }
        }
        Ok(())
    }
}

impl<'a> PersonName<'a> {
    /// Retrieve PersonName prefix
    pub fn prefix(&self) -> Option<&str> {
        self.prefix
    }
    /// Retrieve PersonName suffix
    pub fn suffix(&self) -> Option<&str> {
        self.suffix
    }
    /// Retrieve family name from PersonName
    pub fn family(&self) -> Option<&str> {
        self.family
    }
    /// Retrieve given name from PersonName
    pub fn given(&self) -> Option<&str> {
        self.given
    }
    /// Retrieve middle name from PersonName
    pub fn middle(&self) -> Option<&str> {
        self.middle
    }
    /// Convert the person name into a DICOM formatted string.
    ///
    /// Name components are interspersed with a `'^'` separator.
    /// Leading null components produce a separator,
    /// while trailing components do not.
    pub fn to_dicom_string(&self) -> String {
        let mut name = String::new();

        let components: &[Option<&str>] = &[
            self.family,
            self.given,
            self.middle,
            self.prefix,
            self.suffix,
        ];

        let mut it = components.iter().rev().peekable();
        // consume trailing None (null) components
        while it.next_if(|component| component.is_none()).is_some() {}

        let mut it = it.rev().peekable();
        while let Some(option) = it.next() {
            if let Some(component) = option {
                name.push_str(component);
            }
            if it.peek().is_some() {
                name.push('^');
            }
        }

        name
    }

    /// Obtains a person name by interpreting `slice` as a DICOM formatted string.
    ///
    /// The DICOM string representation is split by the `'^'` separator
    /// into its respective components.
    /// When passing a text value to this function,
    /// ensure that it contains a single DICOM formatted name.
    pub fn from_slice(slice: &'a str) -> PersonName<'a> {
        let mut parts = slice.split('^');

        macro_rules! get_component {
            () => {
                parts
                    .next()
                    .and_then(|s| if s.is_empty() { None } else { Some(s) })
            };
        }

        let family = get_component!();
        let given = get_component!();
        let middle = get_component!();
        let prefix = get_component!();
        let suffix = get_component!();

        PersonName {
            prefix,
            given,
            family,
            middle,
            suffix,
        }
    }

    /// Retrieve a builder for a person name.
    ///
    /// See [`PersonNameBuilder`] for more information.
    pub fn builder() -> PersonNameBuilder<'a> {
        PersonNameBuilder::new()
    }
}

impl<'a> PersonNameBuilder<'a> {
    pub fn new() -> PersonNameBuilder<'a> {
        PersonNameBuilder {
            person_name: PersonName {
                prefix: None,
                family: None,
                middle: None,
                given: None,
                suffix: None,
            },
        }
    }

    /// Insert or update the family name component.
    pub fn with_family(&mut self, family_name: &'a str) -> &mut Self {
        self.person_name.family = Some(family_name);
        self
    }

    /// Insert or update the middle name component.
    pub fn with_middle(&mut self, middle_name: &'a str) -> &mut Self {
        self.person_name.middle = Some(middle_name);
        self
    }

    /// Insert or update the given name component.
    pub fn with_given(&mut self, given_name: &'a str) -> &mut Self {
        self.person_name.given = Some(given_name);
        self
    }

    /// Insert or update the prefix component.
    pub fn with_prefix(&mut self, name_prefix: &'a str) -> &mut Self {
        self.person_name.prefix = Some(name_prefix);
        self
    }

    /// Insert or update the suffix component.
    pub fn with_suffix(&mut self, name_suffix: &'a str) -> &mut Self {
        self.person_name.suffix = Some(name_suffix);
        self
    }

    /// Builds the person name with the accumulated components.
    pub fn build(&self) -> PersonName<'a> {
        self.person_name
    }
}

impl<'a> Default for PersonNameBuilder<'a> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a> From<PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

impl<'a> From<&mut PersonNameBuilder<'a>> for PersonName<'a> {
    fn from(builder: &mut PersonNameBuilder<'a>) -> Self {
        builder.build()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_person_name_to_dicom_string() {
        let p = PersonNameBuilder::new()
            .with_given("John")
            .with_family("Adams")
            .build();
        assert_eq!(p.to_dicom_string(), "Adams^John".to_string());

        let p: PersonName = PersonNameBuilder::new().with_prefix("Rev.").into();
        assert_eq!(p.to_dicom_string(), "^^^Rev.".to_string());

        let p = PersonNameBuilder::new().with_suffix("B.A. M.Div.").build();
        assert_eq!(p.to_dicom_string(), "^^^^B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^Rev.^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_dicom_string(),
            "Adams^John^Robert^^B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert^Rev.".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_dicom_string(), "Adams^John^Robert".to_string());
        let p = PersonName::builder().with_middle("Robert").build();
        assert_eq!(p.to_dicom_string(), "^^Robert".to_string());
    }
    #[test]
    fn test_person_name_to_string() {
        let p = PersonName::builder()
            .with_given("John")
            .with_family("Adams")
            .build();
        assert_eq!(p.to_string(), "John Adams".to_string());

        let p = PersonName::builder().with_prefix("Rev.").build();
        assert_eq!(p.to_string(), "Rev.".to_string());

        let p = PersonName::builder().with_suffix("B.A. M.Div.").build();
        assert_eq!(p.to_string(), "B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(
            p.to_string(),
            "Rev. John Robert Adams B.A. M.Div.".to_string()
        );
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: Some("B.A. M.Div."),
        };
        assert_eq!(p.to_string(), "John Robert Adams B.A. M.Div.".to_string());
        let p = PersonName {
            prefix: Some("Rev."),
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "Rev. John Robert Adams".to_string());
        let p = PersonName {
            prefix: None,
            given: Some("John"),
            middle: Some("Robert"),
            family: Some("Adams"),
            suffix: None,
        };
        assert_eq!(p.to_string(), "John Robert Adams".to_string());
        let p = PersonName::builder().with_middle("Robert").build();
        assert_eq!(p.to_string(), "Robert".to_string());
    }
    #[test]
    fn person_name_from_slice() {
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName::builder().with_middle("Robert").build()
        );
        assert_eq!(
            PersonName::from_slice("^^^Rev."),
            PersonName::builder().with_prefix("Rev.").build()
        );
        assert_eq!(
            PersonName::from_slice("^^^^B.A. M.Div."),
            PersonName::builder().with_suffix("B.A. M.Div.").build()
        );
        assert_eq!(
            PersonName::from_slice("^^Robert"),
            PersonName::builder().with_middle("Robert").build()
        );
        assert_eq!(
            PersonName::from_slice("^John"),
            PersonName::builder().with_given("John").build()
        );
        assert_eq!(
            PersonName::from_slice("Adams"),
            PersonName::builder().with_family("Adams").build()
        );
        assert_eq!(
            PersonName::from_slice("Adams^^^^B.A. M.Div."),
            PersonName::builder()
                .with_family("Adams")
                .with_suffix("B.A. M.Div.")
                .build()
        );
        assert_eq!(
            PersonName::from_slice("Adams^^Robert^^B.A. M.Div."),
            PersonName {
                prefix: None,
                given: None,
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
        assert_eq!(
            PersonName::from_slice("Adams^John^Robert^Rev.^B.A. M.Div."),
            PersonName {
                prefix: Some("Rev."),
                given: Some("John"),
                middle: Some("Robert"),
                family: Some("Adams"),
                suffix: Some("B.A. M.Div."),
            }
        );
    }
}
<|endoftext|>


<commit_before>// TODO Rename structs to snake_case
// TODO serde code_gen for backwards compatibility
#![allow(non_snake_case)]
#[derive(Deserialize, Debug)]
pub struct Error {
    pub code: i64,
    pub message: String,
}
#[derive(Deserialize, Debug)]
pub struct ErrorConsignmentSet {
    pub error: Error
}
#[derive(Deserialize, Debug)]
pub struct Json {
    pub consignmentSet: Vec<ErrorConsignmentSet>,
}
#[derive(Deserialize, Debug)]
pub struct Senderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Eventset {
    pub description: String,
    pub status: String,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitInformationUrl: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: bool,
    pub definitions: Option<Vec<EventsetDefinition>>
}
#[derive(Deserialize, Debug)]
pub struct Packageset {
    pub statusDescription: String,
    pub descriptions: Vec<String>,
    pub packageNumber: String,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: String,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub eventSet: Vec<Eventset>,
}
#[derive(Deserialize, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<Senderaddress>,
    pub recipientHandlingAddress: Option<Senderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
}
#[derive(Deserialize, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<commit_msg>Option all the fields, response varies to such a degree that it's not something you can trust<commit_after>// TODO #[serde(rename(deserialize="name1"))]
#![allow(non_snake_case)]
#[derive(Deserialize, Debug)]
pub struct Error {
    pub code: i64,
    pub message: String,
}
#[derive(Deserialize, Debug)]
pub struct ErrorConsignmentSet {
    pub error: Error
}
#[derive(Deserialize, Debug)]
pub struct Json {
    pub consignmentSet: Vec<ErrorConsignmentSet>,
}
#[derive(Deserialize, Debug)]
pub struct PackagesetSenderaddress {
    pub addressLine1: Option<String>,
    pub addressLine2: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Recipientsignature {
    pub name: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct EventsetDefinition {
    pub term: Option<String>,
    pub explanation: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Eventset {
    pub description: Option<String>,
    pub status: Option<String>,
    pub recipientSignature: Option<Recipientsignature>,
    pub unitId: Option<String>,
    pub unitType: Option<String>,
    pub postalCode: Option<String>,
    pub city: Option<String>,
    pub countryCode: Option<String>,
    pub country: Option<String>,
    pub dateIso: Option<String>,
    pub displayDate: Option<String>,
    pub displayTime: Option<String>,
    pub consignmentEvent: Option<bool>,
    pub definitions: Option<Vec<EventsetDefinition>>,
    pub unitInformationUrl: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct Packageset {
    pub statusDescription: Option<String>,
    pub descriptions: Option<Vec<String>>,
    pub packageNumber: Option<String>,
    pub previousPackageNumber: Option<String>,
    pub productName: Option<String>,
    pub productCode: Option<String>,
    pub brand: Option<String>,
    pub lengthInCm: Option<i64>,
    pub widthInCm: Option<i64>,
    pub heightInCm: Option<i64>,
    pub volumeInDm3: Option<f64>,
    pub weightInKgs: Option<f64>,
    pub pickupCode: Option<String>,
    pub dateOfReturn: Option<String>,
    pub senderName: Option<String>,
    pub senderAddress: Option<PackagesetSenderaddress>,
    pub recipientHandlingAddress: Option<PackagesetSenderaddress>,
    pub eventSet: Vec<Eventset>,
}
#[derive(Deserialize, Debug)]
pub struct Consignmentset {
    pub consignmentId: Option<String>,
    pub previousConsignmentId: Option<String>,
    pub packageSet: Vec<Packageset>,
    pub senderName: Option<String>,
    pub senderAddress: Option<PackagesetSenderaddress>,
    pub recipientHandlingAddress: Option<PackagesetSenderaddress>,
    pub senderReference: Option<String>,
    pub totalWeightInKgs: Option<f64>,
    pub totalVolumeInDm3: Option<f64>,
}
#[derive(Deserialize, Debug)]
pub struct BringResponse {
    pub consignmentSet: Vec<Consignmentset>,
}
<|endoftext|>


<commit_before>//! Contains definitions of the builtin operators supported by Lea.

use std::fmt;

use self::UnOp::*;
use self::BinOp::*;

/// Unary operators
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum UnOp {
    Negate, // -
    LNot,   // !
    LNotLua,// not
    BNot,   // ~
    Len,    // #
}

/// Binary operators
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum BinOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Pow,

    Eq,
    NEq,
    NEqLua,
    LEq,
    GEq,
    Less,
    Greater,

    LAnd,
    LAndLua,
    LOr,
    LOrLua,
    BAnd,
    BOr,
    BXor,
    ShiftL,
    ShiftR,

    Concat,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Assoc {
    Left,
    Right,
}

impl fmt::Display for UnOp {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_str(match *self {
            Negate => "-",
            LNot => "!",
            LNotLua => "not",
            BNot => "~",
            Len => "#",
        })
    }
}

impl fmt::Display for BinOp {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_str(match *self {
            Add => "+",
            Sub => "-",
            Mul => "*",
            Div => "/",
            Mod => "%",
            Pow => "^",

            Concat => "..",

            Eq => "==",
            NEq => "!=",
            NEqLua => "~=",
            LEq => "<=",
            GEq => ">=",
            Less => "<",
            Greater => ">",

            LAnd => "&&",
            LAndLua => "and",
            LOr => "||",
            LOrLua => "or",
            BAnd => "&",
            BOr => "|",
            BXor => "~",    // compat. to Lua 5.3
            ShiftL => "<<",
            ShiftR => ">>",
        })
    }
}

impl BinOp {
    pub fn get_precedence(&self) -> u8 {
        match *self {
            LOr | LOrLua => 0,
            LAnd | LAndLua => 1,
            Eq | NEq | NEqLua | LEq | GEq | Less | Greater => 2,
            Concat => 3,
            BAnd => 4,
            BXor => 5,
            BOr => 6,
            ShiftL => 7,
            ShiftR => 8,
            Add | Sub => 9,
            Mul | Div | Mod => 10,
            Pow => 11,
        }
    }

    pub fn get_assoc(&self) -> Assoc {
        match *self {
            Pow => Assoc::Right,
            _ => Assoc::Left,
        }
    }
}
<commit_msg>Make concat right-associative (like it is in Lua)<commit_after>//! Contains definitions of the builtin operators supported by Lea.

use std::fmt;

use self::UnOp::*;
use self::BinOp::*;

/// Unary operators
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum UnOp {
    Negate, // -
    LNot,   // !
    LNotLua,// not
    BNot,   // ~
    Len,    // #
}

/// Binary operators
#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
pub enum BinOp {
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Pow,

    Eq,
    NEq,
    NEqLua,
    LEq,
    GEq,
    Less,
    Greater,

    LAnd,
    LAndLua,
    LOr,
    LOrLua,
    BAnd,
    BOr,
    BXor,
    ShiftL,
    ShiftR,

    Concat,
}

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Assoc {
    Left,
    Right,
}

impl fmt::Display for UnOp {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_str(match *self {
            Negate => "-",
            LNot => "!",
            LNotLua => "not",
            BNot => "~",
            Len => "#",
        })
    }
}

impl fmt::Display for BinOp {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        fmt.write_str(match *self {
            Add => "+",
            Sub => "-",
            Mul => "*",
            Div => "/",
            Mod => "%",
            Pow => "^",

            Concat => "..",

            Eq => "==",
            NEq => "!=",
            NEqLua => "~=",
            LEq => "<=",
            GEq => ">=",
            Less => "<",
            Greater => ">",

            LAnd => "&&",
            LAndLua => "and",
            LOr => "||",
            LOrLua => "or",
            BAnd => "&",
            BOr => "|",
            BXor => "~",    // compat. to Lua 5.3
            ShiftL => "<<",
            ShiftR => ">>",
        })
    }
}

impl BinOp {
    pub fn get_precedence(&self) -> u8 {
        match *self {
            LOr | LOrLua => 0,
            LAnd | LAndLua => 1,
            Eq | NEq | NEqLua | LEq | GEq | Less | Greater => 2,
            Concat => 3,
            BAnd => 4,
            BXor => 5,
            BOr => 6,
            ShiftL => 7,
            ShiftR => 8,
            Add | Sub => 9,
            Mul | Div | Mod => 10,
            Pow => 11,
        }
    }

    pub fn get_assoc(&self) -> Assoc {
        match *self {
            Pow | Concat => Assoc::Right,
            _ => Assoc::Left,
        }
    }
}
<|endoftext|>