<commit_before>use std::collections::hash_map;
use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::{M256, U256};

use super::{ExecutionResult, ExecutionError, CommitResult, CommitError, Storage};

#[derive(Debug, Clone)]
pub enum AccountCommitment<S> {
    Full {
        nonce: M256,
        address: Address,
        balance: U256,
        storage: S,
        code: Vec<u8>,
    },
    Code {
        address: Address,
        code: Vec<u8>,
    },
}

impl<S: Storage> AccountCommitment<S> {
    pub fn address(&self) -> Address {
        match self {
            &AccountCommitment::Full {
                address: address,
                ..
            } => address,
            &AccountCommitment::Code {
                address: address,
                ..
            } => address,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Account<S> {
    Full {
        nonce: M256,
        address: Address,
        balance: U256,
        storage: S,
        code: Vec<u8>,
    },
    IncreaseBalance(Address, U256),
    DecreaseBalance(Address, U256),
}

impl<S: Storage> Account<S> {
    pub fn address(&self) -> Address {
        match self {
            &Account::Full {
                address: address,
                ..
            } => address,
            &Account::IncreaseBalance(address, _) => address,
            &Account::DecreaseBalance(address, _) => address,
        }
    }
}

pub struct AccountState<S> {
    accounts: hash_map::HashMap<Address, Account<S>>,
    codes: hash_map::HashMap<Address, Vec<u8>>,
}

impl<S: Storage> Default for AccountState<S> {
    fn default() -> Self {
        Self {
            accounts: hash_map::HashMap::new(),
            codes: hash_map::HashMap::new(),
        }
    }
}

impl<S: Storage + Default> AccountState<S> {
    pub fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        self.accounts.values()
    }

    pub fn commit(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        match commitment {
            AccountCommitment::Full {
                nonce: nonce,
                address: address,
                balance: balance,
                storage: storage,
                code: code
            } => {
                if self.accounts.contains_key(&address) {
                    return Err(CommitError::AlreadyCommitted);
                }

                self.accounts.insert(address, Account::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                });
            },
            AccountCommitment::Code {
                address: address,
                code: code,
            } => {
                if self.accounts.contains_key(&address) || self.codes.contains_key(&address) {
                    return Err(CommitError::AlreadyCommitted);
                }

                self.codes.insert(address, code);
            }
        }
        Ok(())
    }

    pub fn code(&self, address: Address) -> ExecutionResult<&[u8]> {
        if self.codes.contains_key(&address) {
            return Ok(self.codes.get(&address).unwrap().as_slice());
        }

        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    code: ref code,
                    ..
                } => return Ok(code.as_slice()),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccountCode(address));
    }

    pub fn nonce(&self, address: Address) -> ExecutionResult<M256> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    nonce: nonce,
                    ..
                } => return Ok(nonce),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn balance(&self, address: Address) -> ExecutionResult<U256> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    balance: balance,
                    ..
                } => return Ok(balance),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn storage(&self, address: Address) -> ExecutionResult<&S> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    storage: ref storage,
                    ..
                } => return Ok(storage),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn storage_mut(&mut self, address: Address) -> ExecutionResult<&mut S> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get_mut(&address).unwrap() {
                &mut Account::Full {
                    storage: ref mut storage,
                    ..
                } => return Ok(storage),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn increase_balance(&mut self, address: Address, topup: U256) -> ExecutionResult<()> {
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                Some(Account::Full {
                    address: address,
                    balance: balance + topup,
                    storage: storage,
                    code: code,
                    nonce: nonce,
                })
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                Some(Account::IncreaseBalance(address, balance + topup))
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                if balance == topup {
                    None
                } else if balance > topup {
                    Some(Account::DecreaseBalance(address, balance - topup))
                } else {
                    Some(Account::IncreaseBalance(address, topup - balance))
                }
            },
            None => {
                return Err(ExecutionError::RequireAccount(address));
            },
        };
        if account.is_some() {
            self.accounts.insert(address, account.unwrap());
        }
        Ok(())
    }

    pub fn decrease_balance(&mut self, address: Address, withdraw: U256) -> ExecutionResult<()> {
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                if balance < withdraw {
                    return Err(ExecutionError::EmptyBalance);
                }
                Some(Account::Full {
                    address: address,
                    balance: balance - withdraw,
                    storage: storage,
                    code: code,
                    nonce: nonce,
                })
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                Some(Account::DecreaseBalance(address, balance - withdraw))
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                if balance == withdraw {
                    None
                } else if balance > withdraw {
                    Some(Account::IncreaseBalance(address, balance - withdraw))
                } else {
                    Some(Account::DecreaseBalance(address, withdraw - balance))
                }
            },
            None => {
                return Err(ExecutionError::RequireAccount(address));
            },
        };
        if account.is_some() {
            self.accounts.insert(address, account.unwrap());
        }
        Ok(())
    }

    pub fn set_nonce(&mut self, address: Address, new_nonce: M256) -> ExecutionResult<()> {
        match self.accounts.get_mut(&address) {
            Some(&mut Account::Full {
                nonce: ref mut nonce,
                ..
            }) => {
                *nonce = new_nonce;
                Ok(())
            },
            _ => {
                Err(ExecutionError::RequireAccount(address))
            },
        }
    }

    pub fn remove(&mut self, address: Address) -> ExecutionResult<()> {
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                Account::Full {
                    address: address,
                    balance: U256::zero(),
                    storage: S::default(),
                    code: Vec::new(),
                    nonce: M256::zero(),
                }
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                return Err(ExecutionError::RequireAccount(address));
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                return Err(ExecutionError::RequireAccount(address));
            },
            None => {
                return Err(ExecutionError::RequireAccount(address));
            },
        };
        self.accounts.insert(address, account);
        Ok(())
    }
}
<commit_msg>Problem: no merge logic for AccountState Solution: make increase/decrease_balance panic-only and implement merge<commit_after>use std::collections::hash_map;
use utils::gas::Gas;
use utils::address::Address;
use utils::bigint::{M256, U256};

use super::{ExecutionResult, ExecutionError, CommitResult, CommitError, Storage};

#[derive(Debug, Clone)]
pub enum AccountCommitment<S> {
    Full {
        nonce: M256,
        address: Address,
        balance: U256,
        storage: S,
        code: Vec<u8>,
    },
    Code {
        address: Address,
        code: Vec<u8>,
    },
}

impl<S: Storage> AccountCommitment<S> {
    pub fn address(&self) -> Address {
        match self {
            &AccountCommitment::Full {
                address: address,
                ..
            } => address,
            &AccountCommitment::Code {
                address: address,
                ..
            } => address,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Account<S> {
    Full {
        nonce: M256,
        address: Address,
        balance: U256,
        storage: S,
        code: Vec<u8>,
    },
    IncreaseBalance(Address, U256),
    DecreaseBalance(Address, U256),
}

impl<S: Storage> Account<S> {
    pub fn address(&self) -> Address {
        match self {
            &Account::Full {
                address: address,
                ..
            } => address,
            &Account::IncreaseBalance(address, _) => address,
            &Account::DecreaseBalance(address, _) => address,
        }
    }
}

pub struct AccountState<S> {
    accounts: hash_map::HashMap<Address, Account<S>>,
    codes: hash_map::HashMap<Address, Vec<u8>>,
}

impl<S: Storage> Default for AccountState<S> {
    fn default() -> Self {
        Self {
            accounts: hash_map::HashMap::new(),
            codes: hash_map::HashMap::new(),
        }
    }
}

impl<S: Storage + Default> AccountState<S> {
    pub fn accounts(&self) -> hash_map::Values<Address, Account<S>> {
        self.accounts.values()
    }

    pub fn commit(&mut self, commitment: AccountCommitment<S>) -> CommitResult<()> {
        match commitment {
            AccountCommitment::Full {
                nonce: nonce,
                address: address,
                balance: balance,
                storage: storage,
                code: code
            } => {
                if self.accounts.contains_key(&address) {
                    return Err(CommitError::AlreadyCommitted);
                }

                self.accounts.insert(address, Account::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage,
                    code: code,
                });
            },
            AccountCommitment::Code {
                address: address,
                code: code,
            } => {
                if self.accounts.contains_key(&address) || self.codes.contains_key(&address) {
                    return Err(CommitError::AlreadyCommitted);
                }

                self.codes.insert(address, code);
            }
        }
        Ok(())
    }

    pub fn code(&self, address: Address) -> ExecutionResult<&[u8]> {
        if self.codes.contains_key(&address) {
            return Ok(self.codes.get(&address).unwrap().as_slice());
        }

        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    code: ref code,
                    ..
                } => return Ok(code.as_slice()),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccountCode(address));
    }

    pub fn nonce(&self, address: Address) -> ExecutionResult<M256> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    nonce: nonce,
                    ..
                } => return Ok(nonce),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn balance(&self, address: Address) -> ExecutionResult<U256> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    balance: balance,
                    ..
                } => return Ok(balance),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn storage(&self, address: Address) -> ExecutionResult<&S> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get(&address).unwrap() {
                &Account::Full {
                    storage: ref storage,
                    ..
                } => return Ok(storage),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn storage_mut(&mut self, address: Address) -> ExecutionResult<&mut S> {
        if self.accounts.contains_key(&address) {
            match self.accounts.get_mut(&address).unwrap() {
                &mut Account::Full {
                    storage: ref mut storage,
                    ..
                } => return Ok(storage),
                _ => (),
            }
        }

        return Err(ExecutionError::RequireAccount(address));
    }

    pub fn increase_balance(&mut self, address: Address, topup: U256) {
        assert!(topup != U256::zero());
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                Some(Account::Full {
                    address: address,
                    balance: balance + topup,
                    storage: storage,
                    code: code,
                    nonce: nonce,
                })
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                Some(Account::IncreaseBalance(address, balance + topup))
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                if balance == topup {
                    None
                } else if balance > topup {
                    Some(Account::DecreaseBalance(address, balance - topup))
                } else {
                    Some(Account::IncreaseBalance(address, topup - balance))
                }
            },
            None => {
                Some(Account::IncreaseBalance(address, topup))
            },
        };
        if account.is_some() {
            self.accounts.insert(address, account.unwrap());
        }
    }

    pub fn decrease_balance(&mut self, address: Address, withdraw: U256) {
        assert!(withdraw != U256::zero());
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                Some(Account::Full {
                    address: address,
                    balance: balance - withdraw,
                    storage: storage,
                    code: code,
                    nonce: nonce,
                })
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                Some(Account::DecreaseBalance(address, balance - withdraw))
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                if balance == withdraw {
                    None
                } else if balance > withdraw {
                    Some(Account::IncreaseBalance(address, balance - withdraw))
                } else {
                    Some(Account::DecreaseBalance(address, withdraw - balance))
                }
            },
            None => {
                Some(Account::DecreaseBalance(address, withdraw))
            },
        };
        if account.is_some() {
            self.accounts.insert(address, account.unwrap());
        }
    }

    pub fn set_nonce(&mut self, address: Address, new_nonce: M256) -> ExecutionResult<()> {
        match self.accounts.get_mut(&address) {
            Some(&mut Account::Full {
                nonce: ref mut nonce,
                ..
            }) => {
                *nonce = new_nonce;
                Ok(())
            },
            _ => {
                Err(ExecutionError::RequireAccount(address))
            },
        }
    }

    pub fn remove(&mut self, address: Address) -> ExecutionResult<()> {
        let account = match self.accounts.remove(&address) {
            Some(Account::Full {
                address: address,
                balance: balance,
                storage: storage,
                code: code,
                nonce: nonce,
            }) => {
                Account::Full {
                    address: address,
                    balance: U256::zero(),
                    storage: S::default(),
                    code: Vec::new(),
                    nonce: M256::zero(),
                }
            },
            Some(Account::DecreaseBalance(address, balance)) => {
                return Err(ExecutionError::RequireAccount(address));
            },
            Some(Account::IncreaseBalance(address, balance)) => {
                return Err(ExecutionError::RequireAccount(address));
            },
            None => {
                return Err(ExecutionError::RequireAccount(address));
            },
        };
        self.accounts.insert(address, account);
        Ok(())
    }

    pub fn merge(&mut self, other: &Account<S>) {
        match other {
            &Account::Full {
                nonce: nonce,
                address: address,
                balance: balance,
                storage: ref storage,
                code: ref code
            } => {
                self.accounts.insert(address, Account::Full {
                    nonce: nonce,
                    address: address,
                    balance: balance,
                    storage: storage.derive(),
                    code: code.clone(),
                });
            },
            &Account::IncreaseBalance(address, inc) => {
                self.increase_balance(address, inc);
            },
            &Account::DecreaseBalance(address, dec) => {
                self.decrease_balance(address, dec);
            },
        }
    }
}
<|endoftext|>


<commit_before>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct SendContact<'c, 'p, 'f, 'l> {
    chat_id: ChatId<'c>,
    phone_number: Cow<'p, str>,
    first_name: Cow<'f, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    last_name: Option<Cow<'l, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_notification: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_to_message_id: Option<Integer>,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}

impl<'c, 'p, 'f, 'l> Request for SendContact<'c, 'p, 'f, 'l> {
    type Response = Message;
    type RawResponse = Message;

    fn map(raw: Self::RawResponse) -> Self::Response {
        raw
    }

    fn name() -> &'static str {
        "sendContact"
    }
}

impl<'c, 'p, 'f, 'l> SendContact<'c, 'p, 'f, 'l> {
    pub fn new<C, P, F>(chat: C, phone_number: P, first_name: F) -> Self
        where C: Into<ChatId<'c>>,
              P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>
    {
        SendContact {
            chat_id: chat.into(),
            phone_number: phone_number.into(),
            first_name: first_name.into(),
            last_name: None,
            disable_notification: false,
            reply_to_message_id: None,
            reply_markup: None,
        }
    }

    pub fn last_name<F>(mut self, last_name: F) -> Self where F: Into<Cow<'l, str>> {
        self.last_name = Some(last_name.into());
        self
    }

    pub fn disable_notification(mut self) -> Self {
        self.disable_notification = true;
        self
    }

    pub fn reply_to<R>(mut self, to: R) -> Self where R: Into<MessageId> {
        self.reply_to_message_id = Some(to.into().0);
        self
    }

    pub fn reply_markup<R>(mut self, reply_markup: R) -> Self where R: Into<ReplyMarkup> {
        self.reply_markup = Some(reply_markup.into());
        self
    }
}<commit_msg>Added "Can..." functions<commit_after>use std::ops::Not;
use std::borrow::Cow;

use types::*;
use requests::*;

#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize)]
pub struct SendContact<'c, 'p, 'f, 'l> {
    chat_id: ChatId<'c>,
    phone_number: Cow<'p, str>,
    first_name: Cow<'f, str>,
    #[serde(skip_serializing_if = "Option::is_none")]
    last_name: Option<Cow<'l, str>>,
    #[serde(skip_serializing_if = "Not::not")]
    disable_notification: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_to_message_id: Option<Integer>,
    #[serde(skip_serializing_if = "Option::is_none")]
    reply_markup: Option<ReplyMarkup>,
}

impl<'c, 'p, 'f, 'l> Request for SendContact<'c, 'p, 'f, 'l> {
    type Response = Message;
    type RawResponse = Message;

    fn map(raw: Self::RawResponse) -> Self::Response {
        raw
    }

    fn name() -> &'static str {
        "sendContact"
    }
}

impl<'c, 'p, 'f, 'l> SendContact<'c, 'p, 'f, 'l> {
    pub fn new<C, P, F>(chat: C, phone_number: P, first_name: F) -> Self
        where C: Into<ChatId<'c>>,
              P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>
    {
        SendContact {
            chat_id: chat.into(),
            phone_number: phone_number.into(),
            first_name: first_name.into(),
            last_name: None,
            disable_notification: false,
            reply_to_message_id: None,
            reply_markup: None,
        }
    }

    pub fn last_name<F>(mut self, last_name: F) -> Self
        where F: Into<Cow<'l, str>>
    {
        self.last_name = Some(last_name.into());
        self
    }

    pub fn disable_notification(mut self) -> Self {
        self.disable_notification = true;
        self
    }

    pub fn reply_to<R>(mut self, to: R) -> Self
        where R: Into<MessageId>
    {
        self.reply_to_message_id = Some(to.into().0);
        self
    }

    pub fn reply_markup<R>(mut self, reply_markup: R) -> Self
        where R: Into<ReplyMarkup>
    {
        self.reply_markup = Some(reply_markup.into());
        self
    }
}

pub trait CanSendContact<'bc, 'c, 'p, 'f, 'l> {
    fn contact<P, F>(&'bc self, phone_number: P, first_name: F) -> SendContact<'c, 'p, 'f, 'l>
        where P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>;
}

impl<'bc, 'c, 'p, 'f, 'l, C: 'bc> CanSendContact<'bc, 'c, 'p, 'f, 'l> for C
    where &'bc C: Into<ChatId<'c>>
{
    fn contact<P, F>(&'bc self, phone_number: P, first_name: F) -> SendContact<'c, 'p, 'f, 'l>
        where P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>
    {
        SendContact::new(self, phone_number, first_name)
    }
}

pub trait CanReplySendContact {
    fn contact_reply<'c, 'p, 'f, 'l, P: 'p, F: 'f>(&self,
                                                   phone_number: P,
                                                   first_name: F)
                                                   -> SendContact<'c, 'p, 'f, 'l>
        where P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>;
}

impl CanReplySendContact for Message {
    fn contact_reply<'c, 'p, 'f, 'l, P: 'p, F: 'f>(&self,
                                                   phone_number: P,
                                                   first_name: F)
                                                   -> SendContact<'c, 'p, 'f, 'l>
        where P: Into<Cow<'p, str>>,
              F: Into<Cow<'f, str>>
    {
        self.chat
            .contact(phone_number, first_name)
            .reply_to(self)
    }
}
<|endoftext|>


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

use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CStr;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux",
              target_os = "android",
              target_os = "emscripten"))]
    pub fn set_name(name: &CStr) {
        const PR_SET_NAME: libc::c_int = 15;
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_setname_np(name.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &CStr) {
        use ffi::CString;
        let cname = CString::new(&b"%s"[..]).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     name.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris"))]
    pub fn set_name(_name: &CStr) {
        // Newlib and Illumos has no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut ts = libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long,
        };

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while libc::nanosleep(&ts, &mut ts) == -1 {
                assert_eq!(os::errno(), libc::EINTR);
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
          not(target_os = "freebsd"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
          target_os = "freebsd",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use prelude::v1::*;

    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(any(target_os = "linux", target_os = "freebsd")) {
            2
        } else {
            1
        };

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
        //if libc::pthread_getattr_np(libc::pthread_self(), &mut attr) == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "freebsd") {
                Some(stackaddr as usize - guardsize as usize)
            } else if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);

    match __pthread_get_minstack.get() {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<commit_msg>Remove accidental comment<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use prelude::v1::*;

use alloc::boxed::FnBox;
use cmp;
#[cfg(not(any(target_env = "newlib", target_os = "solaris")))]
use ffi::CStr;
use io;
use libc;
use mem;
use ptr;
use sys::os;
use time::Duration;

use sys_common::thread::*;

pub struct Thread {
    id: libc::pthread_t,
}

// Some platforms may have pthread_t as a pointer in which case we still want
// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}

impl Thread {
    pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
                          -> io::Result<Thread> {
        let p = box p;
        let mut native: libc::pthread_t = mem::zeroed();
        let mut attr: libc::pthread_attr_t = mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);

        let stack_size = cmp::max(stack, min_stack_size(&attr));
        match libc::pthread_attr_setstacksize(&mut attr,
                                              stack_size as libc::size_t) {
            0 => {}
            n => {
                assert_eq!(n, libc::EINVAL);
                // EINVAL means |stack_size| is either too small or not a
                // multiple of the system page size.  Because it's definitely
                // >= PTHREAD_STACK_MIN, it must be an alignment issue.
                // Round up to the nearest page and try again.
                let page_size = os::page_size();
                let stack_size = (stack_size + page_size - 1) &
                                 (-(page_size as isize - 1) as usize - 1);
                let stack_size = stack_size as libc::size_t;
                assert_eq!(libc::pthread_attr_setstacksize(&mut attr,
                                                           stack_size), 0);
            }
        };

        let ret = libc::pthread_create(&mut native, &attr, thread_start,
                                       &*p as *const _ as *mut _);
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);

        return if ret != 0 {
            Err(io::Error::from_raw_os_error(ret))
        } else {
            mem::forget(p); // ownership passed to pthread_create
            Ok(Thread { id: native })
        };

        extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
            unsafe { start_thread(main); }
            ptr::null_mut()
        }
    }

    pub fn yield_now() {
        let ret = unsafe { libc::sched_yield() };
        debug_assert_eq!(ret, 0);
    }

    #[cfg(any(target_os = "linux",
              target_os = "android",
              target_os = "emscripten"))]
    pub fn set_name(name: &CStr) {
        const PR_SET_NAME: libc::c_int = 15;
        // pthread wrapper only appeared in glibc 2.12, so we use syscall
        // directly.
        unsafe {
            libc::prctl(PR_SET_NAME, name.as_ptr() as libc::c_ulong, 0, 0, 0);
        }
    }

    #[cfg(any(target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr());
        }
    }

    #[cfg(any(target_os = "macos", target_os = "ios"))]
    pub fn set_name(name: &CStr) {
        unsafe {
            libc::pthread_setname_np(name.as_ptr());
        }
    }

    #[cfg(target_os = "netbsd")]
    pub fn set_name(name: &CStr) {
        use ffi::CString;
        let cname = CString::new(&b"%s"[..]).unwrap();
        unsafe {
            libc::pthread_setname_np(libc::pthread_self(), cname.as_ptr(),
                                     name.as_ptr() as *mut libc::c_void);
        }
    }
    #[cfg(any(target_env = "newlib", target_os = "solaris"))]
    pub fn set_name(_name: &CStr) {
        // Newlib and Illumos has no way to set a thread name.
    }

    pub fn sleep(dur: Duration) {
        let mut ts = libc::timespec {
            tv_sec: dur.as_secs() as libc::time_t,
            tv_nsec: dur.subsec_nanos() as libc::c_long,
        };

        // If we're awoken with a signal then the return value will be -1 and
        // nanosleep will fill in `ts` with the remaining time.
        unsafe {
            while libc::nanosleep(&ts, &mut ts) == -1 {
                assert_eq!(os::errno(), libc::EINTR);
            }
        }
    }

    pub fn join(self) {
        unsafe {
            let ret = libc::pthread_join(self.id, ptr::null_mut());
            mem::forget(self);
            debug_assert_eq!(ret, 0);
        }
    }

    pub fn id(&self) -> libc::pthread_t { self.id }

    pub fn into_id(self) -> libc::pthread_t {
        let id = self.id;
        mem::forget(self);
        id
    }
}

impl Drop for Thread {
    fn drop(&mut self) {
        let ret = unsafe { libc::pthread_detach(self.id) };
        debug_assert_eq!(ret, 0);
    }
}

#[cfg(all(not(all(target_os = "linux", not(target_env = "musl"))),
          not(target_os = "freebsd"),
          not(target_os = "macos"),
          not(target_os = "bitrig"),
          not(all(target_os = "netbsd", not(target_vendor = "rumprun"))),
          not(target_os = "openbsd"),
          not(target_os = "solaris")))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    pub unsafe fn current() -> Option<usize> { None }
    pub unsafe fn init() -> Option<usize> { None }
}

#[cfg(any(all(target_os = "linux", not(target_env = "musl")),
          target_os = "freebsd",
          target_os = "macos",
          target_os = "bitrig",
          all(target_os = "netbsd", not(target_vendor = "rumprun")),
          target_os = "openbsd",
          target_os = "solaris"))]
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
    use prelude::v1::*;

    use libc;
    use libc::mmap;
    use libc::{PROT_NONE, MAP_PRIVATE, MAP_ANON, MAP_FAILED, MAP_FIXED};
    use sys::os;

    #[cfg(any(target_os = "macos",
              target_os = "bitrig",
              target_os = "openbsd",
              target_os = "solaris"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        current().map(|s| s as *mut libc::c_void)
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    unsafe fn get_stack_start() -> Option<*mut libc::c_void> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut stackaddr = ::ptr::null_mut();
            let mut stacksize = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut stacksize), 0);
            ret = Some(stackaddr);
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }

    pub unsafe fn init() -> Option<usize> {
        let psize = os::page_size();
        let mut stackaddr = match get_stack_start() {
            Some(addr) => addr,
            None => return None,
        };

        // Ensure stackaddr is page aligned! A parent process might
        // have reset RLIMIT_STACK to be non-page aligned. The
        // pthread_attr_getstack() reports the usable stack area
        // stackaddr < stackaddr + stacksize, so if stackaddr is not
        // page-aligned, calculate the fix such that stackaddr <
        // new_page_aligned_stackaddr < stackaddr + stacksize
        let remainder = (stackaddr as usize) % psize;
        if remainder != 0 {
            stackaddr = ((stackaddr as usize) + psize - remainder)
                as *mut libc::c_void;
        }

        // Rellocate the last page of the stack.
        // This ensures SIGBUS will be raised on
        // stack overflow.
        let result = mmap(stackaddr,
                          psize as libc::size_t,
                          PROT_NONE,
                          MAP_PRIVATE | MAP_ANON | MAP_FIXED,
                          -1,
                          0);

        if result != stackaddr || result == MAP_FAILED {
            panic!("failed to allocate a guard page");
        }

        let offset = if cfg!(any(target_os = "linux", target_os = "freebsd")) {
            2
        } else {
            1
        };

        Some(stackaddr as usize + offset * psize)
    }

    #[cfg(target_os = "solaris")]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::stack_getbounds(&mut current_stack), 0);
        Some(current_stack.ss_sp as usize)
    }

    #[cfg(target_os = "macos")]
    pub unsafe fn current() -> Option<usize> {
        Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t -
              libc::pthread_get_stacksize_np(libc::pthread_self())) as usize)
    }

    #[cfg(any(target_os = "openbsd", target_os = "bitrig"))]
    pub unsafe fn current() -> Option<usize> {
        let mut current_stack: libc::stack_t = ::mem::zeroed();
        assert_eq!(libc::pthread_stackseg_np(libc::pthread_self(),
                                             &mut current_stack), 0);

        let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size();
        Some(if libc::pthread_main_np() == 1 {
            // main thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize + extra
        } else {
            // new thread
            current_stack.ss_sp as usize - current_stack.ss_size as usize
        })
    }

    #[cfg(any(target_os = "android", target_os = "freebsd",
              target_os = "linux", target_os = "netbsd"))]
    pub unsafe fn current() -> Option<usize> {
        let mut ret = None;
        let mut attr: libc::pthread_attr_t = ::mem::zeroed();
        assert_eq!(libc::pthread_attr_init(&mut attr), 0);
        #[cfg(target_os = "freebsd")]
            let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr);
        #[cfg(not(target_os = "freebsd"))]
            let e = libc::pthread_getattr_np(libc::pthread_self(), &mut attr);
        if e == 0 {
            let mut guardsize = 0;
            assert_eq!(libc::pthread_attr_getguardsize(&attr, &mut guardsize), 0);
            if guardsize == 0 {
                panic!("there is no guard page");
            }
            let mut stackaddr = ::ptr::null_mut();
            let mut size = 0;
            assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr,
                                                   &mut size), 0);

            ret = if cfg!(target_os = "freebsd") {
                Some(stackaddr as usize - guardsize as usize)
            } else if cfg!(target_os = "netbsd") {
                Some(stackaddr as usize)
            } else {
                Some(stackaddr as usize + guardsize as usize)
            };
        }
        assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
        ret
    }
}

// glibc >= 2.15 has a __pthread_get_minstack() function that returns
// PTHREAD_STACK_MIN plus however many bytes are needed for thread-local
// storage.  We need that information to avoid blowing up when a small stack
// is created in an application with big thread-local storage requirements.
// See #6233 for rationale and details.
#[cfg(target_os = "linux")]
#[allow(deprecated)]
fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize {
    weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t);

    match __pthread_get_minstack.get() {
        None => libc::PTHREAD_STACK_MIN as usize,
        Some(f) => unsafe { f(attr) as usize },
    }
}

// No point in looking up __pthread_get_minstack() on non-glibc
// platforms.
#[cfg(all(not(target_os = "linux"),
          not(target_os = "netbsd")))]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    libc::PTHREAD_STACK_MIN as usize
}

#[cfg(target_os = "netbsd")]
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
    2048 // just a guess
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate uuid;

#[macro_use] extern crate libimagerror;
#[macro_use] extern crate libimagstore;
extern crate libimaglink;
extern crate libimagutil;

pub static MODULE_ENTRY_PATH_NAME: &'static str = "annotation";

module_entry_path_mod!(MODULE_ENTRY_PATH_NAME);

pub mod annotation;
pub mod error;
pub mod result;

<commit_msg>Fix dependency name<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

extern crate uuid;

#[macro_use] extern crate libimagerror;
#[macro_use] extern crate libimagstore;
extern crate libimagentrylink;
extern crate libimagutil;

pub static MODULE_ENTRY_PATH_NAME: &'static str = "annotation";

module_entry_path_mod!(MODULE_ENTRY_PATH_NAME);

pub mod annotation;
pub mod error;
pub mod result;

<|endoftext|>


<commit_before>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::arch::global_asm;
use core::panic::PanicInfo;

use log::*;

global_asm!(include_str!("../src/boot.asm"));

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}

#[no_mangle]
pub extern "C" fn main() -> ! {
    com_logger::init();
    error!("Hello World!");
    panic!();
}
<commit_msg>examples/baremetal: exit instead of hanging<commit_after>// Copyright 2022 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#![no_std] // don't link the Rust standard library
#![no_main] // disable all Rust-level entry points

use core::arch::{asm, global_asm};
use core::panic::PanicInfo;

use log::*;

global_asm!(include_str!("../src/boot.asm"));

/// This function is called on panic.
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    // Execute a debug breakpoint instruction to cause a VMEXIT.
    // SAFETY: This instruction will exit the hosting VM, so no further Rust code will execute.
    unsafe {
        asm!("int3");
    }
    // Just in case we are still running somehow, spin forever.
    loop {}
}

#[no_mangle]
pub extern "C" fn main() -> ! {
    com_logger::init();
    error!("Hello World!");
    panic!();
}
<|endoftext|>


<commit_before>extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 || value > 100 {
            panic!("Guess value must be between 1 and 100, got {}.", value);
        }

        Guess { value }
    }

    pub fn value(&self) -> u32 {
        self.value
    }
}

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess = match guess.trim().parse() {
            Ok(num) => Guess::new(num),
            Err(_) => continue,
        };

        println!("You guessed: {}", guess.value());

        match guess.value().cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}
<commit_msg>Add should_panic exercise<commit_after>extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        if value < 1 {
            panic!("Guess value must be greater than or equal to 1, got {}.",
                   value);
        } else if value > 100 {
            panic!("Guess value must be less than or equal to 100, got {}.",
                   value);
        }

        Guess { value }
    }

    pub fn value(&self) -> u32 {
        self.value
    }
}

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1, 101);

    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");

        let guess = match guess.trim().parse() {
            Ok(num) => Guess::new(num),
            Err(_) => continue,
        };

        println!("You guessed: {}", guess.value());

        match guess.value().cmp(&secret_number) {
            Ordering::Less => println!("Too small!"),
            Ordering::Greater => println!("Too big!"),
            Ordering::Equal => {
                println!("You win!");
                break;
            }
        }
    }
}

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

    #[test]
    #[should_panic(expected = "Guess value must be less than or equal to 100")]
    fn greater_than_100() {
        Guess::new(200);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use super::Task;

use core::fmt;
use core::cell::UnsafeCell;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::{Acquire, Release};

/// A synchronization primitive for task notification.
///
/// `AtomicTask` will coordinate concurrent notifications with the consumer
/// potentially "updating" the underlying task to notify. This is useful in
/// scenarios where a computation completes in another thread and wants to
/// notify the consumer, but the consumer is in the process of being migrated to
/// a new logical task.
///
/// Roughly, consumers should call `park` before checking the result of a
/// computation and producers should call `notify` after producing the
/// computation. It is also permitted for `notify` to be called **before**
/// `park`. This results in a no-op.
///
/// A single `AtomicTask` may be reused for any number of calls to `park` or
/// `noitfy`.
///
/// `AtomicTask` does not provide any guaranteed memory ordering, as such the
/// user should use caution and use other synchronization primitives to guard
/// the result of the underlying computation.
pub struct AtomicTask {
    state: AtomicUsize,
    task: UnsafeCell<Option<Task>>,
}

/// Initial state, the `AtomicTask` is currently not being used.
///
/// The value `2` is picked specifically because it between the write lock &
/// read lock values. Since the read lock is represented by an incrementing
/// counter, this enables an atomic fetch_sub operation to be used for releasing
/// a lock.
const WAITING: usize = 2;

/// The `park` function has determined that the task is no longer current. This
/// implies that `AtomicTask::park` is being called from a different task than
/// is represented by the currently stored task. The write lock is obtained to
/// update the task cell.
const LOCKED_WRITE: usize = 0;

/// At least one call to `notify` happened concurrently to `park` updating the
/// task cell. This state is detected when `park` exits the mutation code and
/// signals to `park` that it is responsible for notifying its own task.
const LOCKED_WRITE_NOTIFIED: usize = 1;

/// The `notify` function has locked access to the task cell for notification.
///
/// The constant is left here mostly for documentation reasons.
#[allow(dead_code)]
const LOCKED_READ: usize = 3;

impl AtomicTask {
    /// Create an `AtomicTask` initialized with the given `Task`
    pub fn new() -> AtomicTask {
        // Make sure that task is Sync
        trait AssertSync: Sync {}
        impl AssertSync for Task {}

        AtomicTask {
            state: AtomicUsize::new(WAITING),
            task: UnsafeCell::new(None),
        }
    }

    /// Sets the current task to be notified on calls to `notify`.
    ///
    /// The new task will take place of any previous tasks that were registered
    /// by previous calls to `park`.
    pub fn park(&self) {
        // Get a new task handle
        let task = super::current();

        match self.state.compare_and_swap(WAITING, LOCKED_WRITE, Acquire) {
            WAITING => {
                unsafe {
                    // Locked acquired, update the task cell
                    *self.task.get() = Some(task);

                    // Release the lock. If the state transitioned to
                    // `LOCKED_NOTIFIED`, this means that an notify has been
                    // signaled, so notify the task.
                    if LOCKED_WRITE_NOTIFIED == self.state.swap(WAITING, Release) {
                        (*self.task.get()).as_ref().unwrap().notify();
                    }
                }
            }
            LOCKED_WRITE | LOCKED_WRITE_NOTIFIED => {
                // A thread is concurrently calling `park`. This shouldn't
                // happen as it doesn't really make much sense, but it isn't
                // unsafe per se. Since two threads are concurrently trying to
                // update the task, it's undefined which one "wins" (no ordering
                // guarantees), so we can just do nothing.
            }
            state => {
                debug_assert!(state != LOCKED_WRITE, "unexpected state LOCKED_WRITE");
                debug_assert!(state != LOCKED_WRITE_NOTIFIED, "unexpected state LOCKED_WRITE_NOTIFIED");

                // Currently in a read locked state, this implies that `notify`
                // is currently being called on the old task handle. So, we call
                // notify on the new task handle
                task.notify();
            }
        }
    }

    /// Notifies the task that last called `park`.
    ///
    /// If `park` has not been called yet, then this does nothing.
    pub fn notify(&self) {
        let mut curr = WAITING;

        loop {
            if curr == LOCKED_WRITE {
                // Transition the state to LOCKED_NOTIFIED
                let actual = self.state.compare_and_swap(LOCKED_WRITE, LOCKED_WRITE_NOTIFIED, Release);

                if curr == actual {
                    // Success, return
                    return;
                }

                // update current state variable and try again
                curr = actual;

            } else if curr == LOCKED_WRITE_NOTIFIED {
                // Currently in `LOCKED_WRITE_NOTIFIED` state, nothing else to do.
                return;

            } else {
                // Currently in a LOCKED_READ state, so attempt to increment the
                // lock count.
                let actual = self.state.compare_and_swap(curr, curr + 1, Acquire);

                // Locked acquired
                if actual == curr {
                    // Notify the task
                    unsafe {
                        if let Some(ref task) = *self.task.get() {
                            task.notify();
                        }
                    }

                    // Release the lock
                    self.state.fetch_sub(1, Release);

                    // Done
                    return;
                }

                // update current state variable and try again
                curr = actual;

            }
        }
    }
}

impl fmt::Debug for AtomicTask {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "AtomicTask")
    }
}

unsafe impl Send for AtomicTask {}
unsafe impl Sync for AtomicTask {}
<commit_msg>Additional AtomicTask::park docs<commit_after>#![allow(dead_code)]

use super::Task;

use core::fmt;
use core::cell::UnsafeCell;
use core::sync::atomic::AtomicUsize;
use core::sync::atomic::Ordering::{Acquire, Release};

/// A synchronization primitive for task notification.
///
/// `AtomicTask` will coordinate concurrent notifications with the consumer
/// potentially "updating" the underlying task to notify. This is useful in
/// scenarios where a computation completes in another thread and wants to
/// notify the consumer, but the consumer is in the process of being migrated to
/// a new logical task.
///
/// Roughly, consumers should call `park` before checking the result of a
/// computation and producers should call `notify` after producing the
/// computation. It is also permitted for `notify` to be called **before**
/// `park`. This results in a no-op.
///
/// A single `AtomicTask` may be reused for any number of calls to `park` or
/// `noitfy`.
///
/// `AtomicTask` does not provide any guaranteed memory ordering, as such the
/// user should use caution and use other synchronization primitives to guard
/// the result of the underlying computation.
pub struct AtomicTask {
    state: AtomicUsize,
    task: UnsafeCell<Option<Task>>,
}

/// Initial state, the `AtomicTask` is currently not being used.
///
/// The value `2` is picked specifically because it between the write lock &
/// read lock values. Since the read lock is represented by an incrementing
/// counter, this enables an atomic fetch_sub operation to be used for releasing
/// a lock.
const WAITING: usize = 2;

/// The `park` function has determined that the task is no longer current. This
/// implies that `AtomicTask::park` is being called from a different task than
/// is represented by the currently stored task. The write lock is obtained to
/// update the task cell.
const LOCKED_WRITE: usize = 0;

/// At least one call to `notify` happened concurrently to `park` updating the
/// task cell. This state is detected when `park` exits the mutation code and
/// signals to `park` that it is responsible for notifying its own task.
const LOCKED_WRITE_NOTIFIED: usize = 1;

/// The `notify` function has locked access to the task cell for notification.
///
/// The constant is left here mostly for documentation reasons.
#[allow(dead_code)]
const LOCKED_READ: usize = 3;

impl AtomicTask {
    /// Create an `AtomicTask` initialized with the given `Task`
    pub fn new() -> AtomicTask {
        // Make sure that task is Sync
        trait AssertSync: Sync {}
        impl AssertSync for Task {}

        AtomicTask {
            state: AtomicUsize::new(WAITING),
            task: UnsafeCell::new(None),
        }
    }

    /// Sets the current task to be notified on calls to `notify`.
    ///
    /// The new task will take place of any previous tasks that were registered
    /// by previous calls to `park`. Any calls to `notify` that happen after
    /// a call to `park` (as defined by the memory ordering rules), will notify
    /// the `park` caller's task.
    ///
    /// It is safe to call `park` with multiple other threads concurrently
    /// calling `notify`. This will result in the `park` caller's current task
    /// being notified once.
    ///
    /// This function is safe to call concurrently, but this is generally a bad
    /// idea. Concurrent calls to `park` will attempt to register different
    /// tasks to be notified. One of the callers will win and have its task set,
    /// but there is no guarantee as to which caller will succeed.
    pub fn park(&self) {
        // Get a new task handle
        let task = super::current();

        match self.state.compare_and_swap(WAITING, LOCKED_WRITE, Acquire) {
            WAITING => {
                unsafe {
                    // Locked acquired, update the task cell
                    *self.task.get() = Some(task);

                    // Release the lock. If the state transitioned to
                    // `LOCKED_NOTIFIED`, this means that an notify has been
                    // signaled, so notify the task.
                    if LOCKED_WRITE_NOTIFIED == self.state.swap(WAITING, Release) {
                        (*self.task.get()).as_ref().unwrap().notify();
                    }
                }
            }
            LOCKED_WRITE | LOCKED_WRITE_NOTIFIED => {
                // A thread is concurrently calling `park`. This shouldn't
                // happen as it doesn't really make much sense, but it isn't
                // unsafe per se. Since two threads are concurrently trying to
                // update the task, it's undefined which one "wins" (no ordering
                // guarantees), so we can just do nothing.
            }
            state => {
                debug_assert!(state != LOCKED_WRITE, "unexpected state LOCKED_WRITE");
                debug_assert!(state != LOCKED_WRITE_NOTIFIED, "unexpected state LOCKED_WRITE_NOTIFIED");

                // Currently in a read locked state, this implies that `notify`
                // is currently being called on the old task handle. So, we call
                // notify on the new task handle
                task.notify();
            }
        }
    }

    /// Notifies the task that last called `park`.
    ///
    /// If `park` has not been called yet, then this does nothing.
    pub fn notify(&self) {
        let mut curr = WAITING;

        loop {
            if curr == LOCKED_WRITE {
                // Transition the state to LOCKED_NOTIFIED
                let actual = self.state.compare_and_swap(LOCKED_WRITE, LOCKED_WRITE_NOTIFIED, Release);

                if curr == actual {
                    // Success, return
                    return;
                }

                // update current state variable and try again
                curr = actual;

            } else if curr == LOCKED_WRITE_NOTIFIED {
                // Currently in `LOCKED_WRITE_NOTIFIED` state, nothing else to do.
                return;

            } else {
                // Currently in a LOCKED_READ state, so attempt to increment the
                // lock count.
                let actual = self.state.compare_and_swap(curr, curr + 1, Acquire);

                // Locked acquired
                if actual == curr {
                    // Notify the task
                    unsafe {
                        if let Some(ref task) = *self.task.get() {
                            task.notify();
                        }
                    }

                    // Release the lock
                    self.state.fetch_sub(1, Release);

                    // Done
                    return;
                }

                // update current state variable and try again
                curr = actual;

            }
        }
    }
}

impl fmt::Debug for AtomicTask {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "AtomicTask")
    }
}

unsafe impl Send for AtomicTask {}
unsafe impl Sync for AtomicTask {}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use bytecode_verifier::{
    verifier::{verify_module_dependencies, VerifiedProgram},
    VerifiedModule,
};
use compiler::{util, Compiler};
use ir_to_bytecode::parser::{parse_module, parse_script};
use serde_json;
use std::{convert::TryFrom, fs, io::Write, path::PathBuf};
use stdlib::stdlib_modules;
use structopt::StructOpt;
use types::{access_path::AccessPath, account_address::AccountAddress, transaction::Program};
use vm::{errors::VerificationError, file_format::CompiledModule};

#[derive(Debug, StructOpt)]
#[structopt(
    name = "IR Compiler",
    author = "Libra",
    about = "Move IR to bytecode compiler."
)]
struct Args {
    /// Serialize and write the compiled output to this file
    #[structopt(short = "o", long = "output")]
    pub output_path: Option<String>,
    /// Treat input file as a module (default is to treat file as a program)
    #[structopt(short = "m", long = "module")]
    pub module_input: bool,
    /// Account address used for publishing
    #[structopt(short = "a", long = "address")]
    pub address: Option<String>,
    /// Do not automatically compile stdlib dependencies
    #[structopt(long = "no-stdlib")]
    pub no_stdlib: bool,
    /// Do not automatically run the bytecode verifier
    #[structopt(long = "no-verify")]
    pub no_verify: bool,
    /// Path to the Move IR source to compile
    #[structopt(parse(from_os_str))]
    pub source_path: PathBuf,
    /// Instead of compiling the source, emit a dependency list of the compiled source
    #[structopt(short = "-l", long = "list_dependencies")]
    pub list_dependencies: bool,
}

fn print_errors_and_exit(verification_errors: &[VerificationError]) -> ! {
    println!("Verification failed. Errors below:");
    for e in verification_errors {
        println!("{:?}", e);
    }
    std::process::exit(1);
}

fn do_verify_module(module: CompiledModule, dependencies: &[VerifiedModule]) -> VerifiedModule {
    let verified_module = match VerifiedModule::new(module) {
        Ok(module) => module,
        Err((_, errors)) => print_errors_and_exit(&errors),
    };
    let (verified_module, errors) = verify_module_dependencies(verified_module, dependencies);
    if !errors.is_empty() {
        print_errors_and_exit(&errors);
    }
    verified_module
}

fn write_output(path: &str, buf: &[u8]) {
    let mut f = fs::File::create(path)
        .unwrap_or_else(|err| panic!("Unable to open output file {}: {}", path, err));
    f.write_all(&buf)
        .unwrap_or_else(|err| panic!("Unable to write to output file {}: {}", path, err));
}

fn main() {
    let args = Args::from_args();

    let address = args
        .address
        .map(|a| AccountAddress::try_from(a).unwrap())
        .unwrap_or_else(AccountAddress::default);

    if args.list_dependencies {
        let source = fs::read_to_string(args.source_path).expect("Unable to read file");
        let dependency_list: Vec<AccessPath> = if args.module_input {
            let module = parse_module(&source).expect("Unable to parse module");
            module.get_external_deps()
        } else {
            let script = parse_script(&source).expect("Unable to parse module");
            script.get_external_deps()
        }
        .into_iter()
        .map(|m| AccessPath::code_access_path(&m))
        .collect();
        match args.output_path {
            Some(path) => {
                let deps_bytes =
                    serde_json::to_vec(&dependency_list).expect("Unable to serialize dependencies");
                write_output(&path, &deps_bytes);
            }
            None => println!(
                "{}",
                serde_json::to_string(&dependency_list).expect("Unable to serialize dependencies")
            ),
        }
        return;
    }

    if !args.module_input {
        let source = fs::read_to_string(args.source_path).expect("Unable to read file");
        let compiler = Compiler {
            address,
            code: &source,
            skip_stdlib_deps: args.no_stdlib,
            ..Compiler::default()
        };
        let (compiled_program, dependencies) = compiler
            .into_compiled_program_and_deps()
            .expect("Failed to compile program");

        let compiled_program = if !args.no_verify {
            let verified_program = VerifiedProgram::new(compiled_program, &dependencies)
                .expect("Failed to verify program");
            verified_program.into_inner()
        } else {
            compiled_program
        };

        match args.output_path {
            Some(path) => {
                let mut script = vec![];
                compiled_program
                    .script
                    .serialize(&mut script)
                    .expect("Unable to serialize script");
                let mut modules = vec![];
                for m in compiled_program.modules.iter() {
                    let mut buf = vec![];
                    m.serialize(&mut buf).expect("Unable to serialize module");
                    modules.push(buf);
                }
                let program = Program::new(script, modules, vec![]);
                let program_bytes =
                    serde_json::to_vec(&program).expect("Unable to serialize program");
                write_output(&path, &program_bytes);
            }
            None => {
                println!("{}", compiled_program);
            }
        }
    } else {
        let dependencies = if args.no_stdlib {
            vec![]
        } else {
            stdlib_modules().to_vec()
        };
        let compiled_module = util::do_compile_module(&args.source_path, &address, &dependencies);
        let compiled_module = if !args.no_verify {
            let verified_module = do_verify_module(compiled_module, &dependencies);
            verified_module.into_inner()
        } else {
            compiled_module
        };
        match args.output_path {
            Some(path) => {
                let mut out = vec![];
                compiled_module
                    .serialize(&mut out)
                    .expect("Unable to serialize module");
                write_output(&path, &out);
            }
            None => {
                println!("{}", compiled_module);
            }
        }
    }
}
<commit_msg>[compiler] Add a flag to pass in on chain module dependencies<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use bytecode_verifier::{
    verifier::{verify_module_dependencies, VerifiedProgram},
    VerifiedModule,
};
use compiler::{util, Compiler};
use ir_to_bytecode::parser::{parse_module, parse_script};
use serde_json;
use std::{convert::TryFrom, fs, io::Write, path::PathBuf};
use stdlib::stdlib_modules;
use structopt::StructOpt;
use types::{access_path::AccessPath, account_address::AccountAddress, transaction::Program};
use vm::{errors::VerificationError, file_format::CompiledModule};

#[derive(Debug, StructOpt)]
#[structopt(
    name = "IR Compiler",
    author = "Libra",
    about = "Move IR to bytecode compiler."
)]
struct Args {
    /// Serialize and write the compiled output to this file
    #[structopt(short = "o", long = "output")]
    pub output_path: Option<String>,
    /// Treat input file as a module (default is to treat file as a program)
    #[structopt(short = "m", long = "module")]
    pub module_input: bool,
    /// Account address used for publishing
    #[structopt(short = "a", long = "address")]
    pub address: Option<String>,
    /// Do not automatically compile stdlib dependencies
    #[structopt(long = "no-stdlib")]
    pub no_stdlib: bool,
    /// Do not automatically run the bytecode verifier
    #[structopt(long = "no-verify")]
    pub no_verify: bool,
    /// Path to the Move IR source to compile
    #[structopt(parse(from_os_str))]
    pub source_path: PathBuf,
    /// Instead of compiling the source, emit a dependency list of the compiled source
    #[structopt(short = "-l", long = "list_dependencies")]
    pub list_dependencies: bool,
    /// Path to the list of modules that we want to link with
    #[structopt(long = "deps")]
    pub deps_path: Option<String>,
}

fn print_errors_and_exit(verification_errors: &[VerificationError]) -> ! {
    println!("Verification failed. Errors below:");
    for e in verification_errors {
        println!("{:?}", e);
    }
    std::process::exit(1);
}

fn do_verify_module(module: CompiledModule, dependencies: &[VerifiedModule]) -> VerifiedModule {
    let verified_module = match VerifiedModule::new(module) {
        Ok(module) => module,
        Err((_, errors)) => print_errors_and_exit(&errors),
    };
    let (verified_module, errors) = verify_module_dependencies(verified_module, dependencies);
    if !errors.is_empty() {
        print_errors_and_exit(&errors);
    }
    verified_module
}

fn write_output(path: &str, buf: &[u8]) {
    let mut f = fs::File::create(path)
        .unwrap_or_else(|err| panic!("Unable to open output file {}: {}", path, err));
    f.write_all(&buf)
        .unwrap_or_else(|err| panic!("Unable to write to output file {}: {}", path, err));
}

fn main() {
    let args = Args::from_args();

    let address = args
        .address
        .map(|a| AccountAddress::try_from(a).unwrap())
        .unwrap_or_else(AccountAddress::default);

    if args.list_dependencies {
        let source = fs::read_to_string(args.source_path).expect("Unable to read file");
        let dependency_list: Vec<AccessPath> = if args.module_input {
            let module = parse_module(&source).expect("Unable to parse module");
            module.get_external_deps()
        } else {
            let script = parse_script(&source).expect("Unable to parse module");
            script.get_external_deps()
        }
        .into_iter()
        .map(|m| AccessPath::code_access_path(&m))
        .collect();
        match args.output_path {
            Some(path) => {
                let deps_bytes =
                    serde_json::to_vec(&dependency_list).expect("Unable to serialize dependencies");
                write_output(&path, &deps_bytes);
            }
            None => println!(
                "{}",
                serde_json::to_string(&dependency_list).expect("Unable to serialize dependencies")
            ),
        }
        return;
    }

    let deps = {
        if let Some(path) = args.deps_path {
            let deps = fs::read_to_string(path).expect("Unable to read dependency file");
            let deps_list: Vec<Vec<u8>> =
                serde_json::from_str(deps.as_str()).expect("Unable to parse dependency file");
            deps_list
                .into_iter()
                .map(|module_bytes| {
                    VerifiedModule::new(
                        CompiledModule::deserialize(module_bytes.as_slice())
                            .expect("Downloaded module blob can't be deserialized"),
                    )
                    .expect("Downloaded module blob failed verifier")
                })
                .collect()
        } else if args.no_stdlib {
            vec![]
        } else {
            stdlib_modules().to_vec()
        }
    };

    if !args.module_input {
        let source = fs::read_to_string(args.source_path).expect("Unable to read file");
        let compiler = Compiler {
            address,
            code: &source,
            skip_stdlib_deps: args.no_stdlib,
            extra_deps: deps,
            ..Compiler::default()
        };
        let (compiled_program, dependencies) = compiler
            .into_compiled_program_and_deps()
            .expect("Failed to compile program");

        let compiled_program = if !args.no_verify {
            let verified_program = VerifiedProgram::new(compiled_program, &dependencies)
                .expect("Failed to verify program");
            verified_program.into_inner()
        } else {
            compiled_program
        };

        match args.output_path {
            Some(path) => {
                let mut script = vec![];
                compiled_program
                    .script
                    .serialize(&mut script)
                    .expect("Unable to serialize script");
                let mut modules = vec![];
                for m in compiled_program.modules.iter() {
                    let mut buf = vec![];
                    m.serialize(&mut buf).expect("Unable to serialize module");
                    modules.push(buf);
                }
                let program = Program::new(script, modules, vec![]);
                let program_bytes =
                    serde_json::to_vec(&program).expect("Unable to serialize program");
                write_output(&path, &program_bytes);
            }
            None => {
                println!("{}", compiled_program);
            }
        }
    } else {
        let compiled_module = util::do_compile_module(&args.source_path, &address, &deps);
        let compiled_module = if !args.no_verify {
            let verified_module = do_verify_module(compiled_module, &deps);
            verified_module.into_inner()
        } else {
            compiled_module
        };
        match args.output_path {
            Some(path) => {
                let mut out = vec![];
                compiled_module
                    .serialize(&mut out)
                    .expect("Unable to serialize module");
                write_output(&path, &out);
            }
            None => {
                println!("{}", compiled_module);
            }
        }
    }
}
<|endoftext|>


<commit_before>//! A trait to represent a stream

use crate::smtp::client::mock::MockStream;
use native_tls::{Protocol, TlsConnector, TlsStream};
use std::io::{self, ErrorKind, Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, TcpStream};
use std::time::Duration;

/// Parameters to use for secure clients
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct ClientTlsParameters {
    /// A connector from `native-tls`
    pub connector: TlsConnector,
    /// The domain to send during the TLS handshake
    pub domain: String,
}

impl ClientTlsParameters {
    /// Creates a `ClientTlsParameters`
    pub fn new(domain: String, connector: TlsConnector) -> ClientTlsParameters {
        ClientTlsParameters { connector, domain }
    }
}

/// Accepted protocols by default.
/// This removes TLS 1.0 and 1.1 compared to tls-native defaults.
pub const DEFAULT_TLS_MIN_PROTOCOL: Protocol = Protocol::Tlsv12;

#[derive(Debug)]
/// Represents the different types of underlying network streams
pub enum NetworkStream {
    /// Plain TCP stream
    Tcp(TcpStream),
    /// Encrypted TCP stream
    Tls(TlsStream<TcpStream>),
    /// Mock stream
    Mock(MockStream),
}

impl NetworkStream {
    /// Returns peer's address
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            NetworkStream::Tcp(ref s) => s.peer_addr(),
            NetworkStream::Tls(ref s) => s.get_ref().peer_addr(),
            NetworkStream::Mock(_) => Ok(SocketAddr::V4(SocketAddrV4::new(
                Ipv4Addr::new(127, 0, 0, 1),
                80,
            ))),
        }
    }

    /// Shutdowns the connection
    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref s) => s.shutdown(how),
            NetworkStream::Tls(ref s) => s.get_ref().shutdown(how),
            NetworkStream::Mock(_) => Ok(()),
        }
    }
}

impl Read for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.read(buf),
            NetworkStream::Tls(ref mut s) => s.read(buf),
            NetworkStream::Mock(ref mut s) => s.read(buf),
        }
    }
}

impl Write for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.write(buf),
            NetworkStream::Tls(ref mut s) => s.write(buf),
            NetworkStream::Mock(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.flush(),
            NetworkStream::Tls(ref mut s) => s.flush(),
            NetworkStream::Mock(ref mut s) => s.flush(),
        }
    }
}

/// A trait for the concept of opening a stream
pub trait Connector: Sized {
    /// Opens a connection to the given IP socket
    fn connect(
        addr: &SocketAddr,
        timeout: Option<Duration>,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> io::Result<Self>;
    /// Upgrades to TLS connection
    fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()>;
    /// Is the NetworkStream encrypted
    fn is_encrypted(&self) -> bool;
}

impl Connector for NetworkStream {
    fn connect(
        addr: &SocketAddr,
        timeout: Option<Duration>,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> io::Result<NetworkStream> {
        let tcp_stream = match timeout {
            Some(duration) => TcpStream::connect_timeout(addr, duration)?,
            None => TcpStream::connect(addr)?,
        };

        match tls_parameters {
            Some(context) => context
                .connector
                .connect(context.domain.as_ref(), tcp_stream)
                .map(NetworkStream::Tls)
                .map_err(|e| io::Error::new(ErrorKind::Other, e)),
            None => Ok(NetworkStream::Tcp(tcp_stream)),
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::match_same_arms))]
    fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> {
        *self = match *self {
            NetworkStream::Tcp(ref mut stream) => match tls_parameters
                .connector
                .connect(tls_parameters.domain.as_ref(), stream.try_clone().unwrap())
            {
                Ok(tls_stream) => NetworkStream::Tls(tls_stream),
                Err(err) => return Err(io::Error::new(ErrorKind::Other, err)),
            },
            NetworkStream::Tls(_) => return Ok(()),
            NetworkStream::Mock(_) => return Ok(()),
        };

        Ok(())
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::match_same_arms))]
    fn is_encrypted(&self) -> bool {
        match *self {
            NetworkStream::Tcp(_) => false,
            NetworkStream::Tls(_) => true,
            NetworkStream::Mock(_) => false,
        }
    }
}

/// A trait for read and write timeout support
pub trait Timeout: Sized {
    /// Set read timeout for IO calls
    fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
    /// Set write timeout for IO calls
    fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
}

impl Timeout for NetworkStream {
    fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut stream) => stream.set_read_timeout(duration),
            NetworkStream::Tls(ref mut stream) => stream.get_ref().set_read_timeout(duration),
            NetworkStream::Mock(_) => Ok(()),
        }
    }

    /// Set write timeout for IO calls
    fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut stream) => stream.set_write_timeout(duration),
            NetworkStream::Tls(ref mut stream) => stream.get_ref().set_write_timeout(duration),
            NetworkStream::Mock(_) => Ok(()),
        }
    }
}
<commit_msg>docs(transport-smtp): fix docs for `domain` field<commit_after>//! A trait to represent a stream

use crate::smtp::client::mock::MockStream;
use native_tls::{Protocol, TlsConnector, TlsStream};
use std::io::{self, ErrorKind, Read, Write};
use std::net::{Ipv4Addr, Shutdown, SocketAddr, SocketAddrV4, TcpStream};
use std::time::Duration;

/// Parameters to use for secure clients
#[derive(Clone)]
#[allow(missing_debug_implementations)]
pub struct ClientTlsParameters {
    /// A connector from `native-tls`
    pub connector: TlsConnector,
    /// The domain name which is expected in the TLS certificate from the server
    pub domain: String,
}

impl ClientTlsParameters {
    /// Creates a `ClientTlsParameters`
    pub fn new(domain: String, connector: TlsConnector) -> ClientTlsParameters {
        ClientTlsParameters { connector, domain }
    }
}

/// Accepted protocols by default.
/// This removes TLS 1.0 and 1.1 compared to tls-native defaults.
pub const DEFAULT_TLS_MIN_PROTOCOL: Protocol = Protocol::Tlsv12;

#[derive(Debug)]
/// Represents the different types of underlying network streams
pub enum NetworkStream {
    /// Plain TCP stream
    Tcp(TcpStream),
    /// Encrypted TCP stream
    Tls(TlsStream<TcpStream>),
    /// Mock stream
    Mock(MockStream),
}

impl NetworkStream {
    /// Returns peer's address
    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
        match *self {
            NetworkStream::Tcp(ref s) => s.peer_addr(),
            NetworkStream::Tls(ref s) => s.get_ref().peer_addr(),
            NetworkStream::Mock(_) => Ok(SocketAddr::V4(SocketAddrV4::new(
                Ipv4Addr::new(127, 0, 0, 1),
                80,
            ))),
        }
    }

    /// Shutdowns the connection
    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref s) => s.shutdown(how),
            NetworkStream::Tls(ref s) => s.get_ref().shutdown(how),
            NetworkStream::Mock(_) => Ok(()),
        }
    }
}

impl Read for NetworkStream {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.read(buf),
            NetworkStream::Tls(ref mut s) => s.read(buf),
            NetworkStream::Mock(ref mut s) => s.read(buf),
        }
    }
}

impl Write for NetworkStream {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.write(buf),
            NetworkStream::Tls(ref mut s) => s.write(buf),
            NetworkStream::Mock(ref mut s) => s.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut s) => s.flush(),
            NetworkStream::Tls(ref mut s) => s.flush(),
            NetworkStream::Mock(ref mut s) => s.flush(),
        }
    }
}

/// A trait for the concept of opening a stream
pub trait Connector: Sized {
    /// Opens a connection to the given IP socket
    fn connect(
        addr: &SocketAddr,
        timeout: Option<Duration>,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> io::Result<Self>;
    /// Upgrades to TLS connection
    fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()>;
    /// Is the NetworkStream encrypted
    fn is_encrypted(&self) -> bool;
}

impl Connector for NetworkStream {
    fn connect(
        addr: &SocketAddr,
        timeout: Option<Duration>,
        tls_parameters: Option<&ClientTlsParameters>,
    ) -> io::Result<NetworkStream> {
        let tcp_stream = match timeout {
            Some(duration) => TcpStream::connect_timeout(addr, duration)?,
            None => TcpStream::connect(addr)?,
        };

        match tls_parameters {
            Some(context) => context
                .connector
                .connect(context.domain.as_ref(), tcp_stream)
                .map(NetworkStream::Tls)
                .map_err(|e| io::Error::new(ErrorKind::Other, e)),
            None => Ok(NetworkStream::Tcp(tcp_stream)),
        }
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::match_same_arms))]
    fn upgrade_tls(&mut self, tls_parameters: &ClientTlsParameters) -> io::Result<()> {
        *self = match *self {
            NetworkStream::Tcp(ref mut stream) => match tls_parameters
                .connector
                .connect(tls_parameters.domain.as_ref(), stream.try_clone().unwrap())
            {
                Ok(tls_stream) => NetworkStream::Tls(tls_stream),
                Err(err) => return Err(io::Error::new(ErrorKind::Other, err)),
            },
            NetworkStream::Tls(_) => return Ok(()),
            NetworkStream::Mock(_) => return Ok(()),
        };

        Ok(())
    }

    #[cfg_attr(feature = "cargo-clippy", allow(clippy::match_same_arms))]
    fn is_encrypted(&self) -> bool {
        match *self {
            NetworkStream::Tcp(_) => false,
            NetworkStream::Tls(_) => true,
            NetworkStream::Mock(_) => false,
        }
    }
}

/// A trait for read and write timeout support
pub trait Timeout: Sized {
    /// Set read timeout for IO calls
    fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
    /// Set write timeout for IO calls
    fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()>;
}

impl Timeout for NetworkStream {
    fn set_read_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut stream) => stream.set_read_timeout(duration),
            NetworkStream::Tls(ref mut stream) => stream.get_ref().set_read_timeout(duration),
            NetworkStream::Mock(_) => Ok(()),
        }
    }

    /// Set write timeout for IO calls
    fn set_write_timeout(&mut self, duration: Option<Duration>) -> io::Result<()> {
        match *self {
            NetworkStream::Tcp(ref mut stream) => stream.set_write_timeout(duration),
            NetworkStream::Tls(ref mut stream) => stream.get_ref().set_write_timeout(duration),
            NetworkStream::Mock(_) => Ok(()),
        }
    }
}
<|endoftext|>