<commit_before>use crate::Error;
use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

#[cfg(backtrace)]
use std::backtrace::Backtrace;

/// Provides the `context` method for `Result`.
///
/// # Example
///
/// ```
/// use anyhow::{Context, Result};
/// use std::fs;
/// use std::path::PathBuf;
///
/// pub struct ImportantThing {
///     path: PathBuf,
/// }
///
/// impl ImportantThing {
///     # const IGNORE: &'static str = stringify! {
///     pub fn detach(&mut self) -> Result<()> {...}
///     # };
///     # fn detach(&mut self) -> Result<()> {
///     #     unimplemented!()
///     # }
/// }
///
/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
///     it.detach().context("failed to detach the important thing")?;
///
///     let path = &it.path;
///     let content = fs::read(path)
///         .with_context(|| format!("failed to read instrs from {}", path.display()))?;
///
///     Ok(content)
/// }
/// ```
///
/// When printed, the outermost context would be printed first and the lower
/// level underlying causes would be enumerated below.
///
/// ```console
/// Error: failed to read instrs from ./path/to/instrs.jsox
///
/// caused by:
///     No such file or directory (os error 2)
/// ```
pub trait Context<T, E> {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context that is evaluated lazily
    /// only once an error does occur.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::new(ContextError { error, context }))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::new(ContextError {
                error,
                context: context(),
            })
        })
    }
}

impl<T> Context<T, Error> for Result<T, Error> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| error.context(context))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| error.context(context()))
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.ok_or_else(|| Error::from_display(context, backtrace!()))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.ok_or_else(|| Error::from_display(context(), backtrace!()))
    }
}

pub(crate) struct ContextError<E, C> {
    pub error: E,
    pub context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}
<commit_msg>Seal the Context trait<commit_after>use crate::Error;
use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

#[cfg(backtrace)]
use std::backtrace::Backtrace;

/// Provides the `context` method for `Result`.
///
/// This trait is sealed and cannot be implemented for types outside of
/// `anyhow`.
///
/// # Example
///
/// ```
/// use anyhow::{Context, Result};
/// use std::fs;
/// use std::path::PathBuf;
///
/// pub struct ImportantThing {
///     path: PathBuf,
/// }
///
/// impl ImportantThing {
///     # const IGNORE: &'static str = stringify! {
///     pub fn detach(&mut self) -> Result<()> {...}
///     # };
///     # fn detach(&mut self) -> Result<()> {
///     #     unimplemented!()
///     # }
/// }
///
/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
///     it.detach().context("failed to detach the important thing")?;
///
///     let path = &it.path;
///     let content = fs::read(path)
///         .with_context(|| format!("failed to read instrs from {}", path.display()))?;
///
///     Ok(content)
/// }
/// ```
///
/// When printed, the outermost context would be printed first and the lower
/// level underlying causes would be enumerated below.
///
/// ```console
/// Error: failed to read instrs from ./path/to/instrs.jsox
///
/// caused by:
///     No such file or directory (os error 2)
/// ```
pub trait Context<T, E>: private::Sealed {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context that is evaluated lazily
    /// only once an error does occur.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::new(ContextError { error, context }))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::new(ContextError {
                error,
                context: context(),
            })
        })
    }
}

impl<T> Context<T, Error> for Result<T, Error> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| error.context(context))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| error.context(context()))
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.ok_or_else(|| Error::from_display(context, backtrace!()))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.ok_or_else(|| Error::from_display(context(), backtrace!()))
    }
}

pub(crate) struct ContextError<E, C> {
    pub error: E,
    pub context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}

mod private {
    use crate::Error;
    use std::error::Error as StdError;

    pub trait Sealed {}

    impl<T, E> Sealed for Result<T, E> where E: StdError + Send + Sync + 'static {}
    impl<T> Sealed for Result<T, Error> {}
    impl<T> Sealed for Option<T> {}
}
<|endoftext|>


<commit_before>//! A very simple, and fast, constant propagation

use analysis::fixed_point;
use error::*;
use executor::eval;
use il;
use std::collections::{HashMap};
use std::cmp::{Ordering, PartialOrd};

/// Compute constants for the given function
pub fn constants<'r>(function: &'r il::Function)
-> Result<HashMap<il::RefProgramLocation<'r>, Constants>> {
    fixed_point::fixed_point_forward(ConstantsAnalysis{}, function)
}

#[derive(Clone, Debug, PartialEq)]
pub struct Constants {
    constants: HashMap<il::Scalar, il::Constant>
}

impl PartialOrd for Constants {
    fn partial_cmp(&self, other: &Constants) -> Option<Ordering> {

        if self.constants.len() < other.constants.len() {
            for (ls, lc) in self.constants.iter() {
                if !other.constants
                    .get(ls)
                    .map(|rc| rc >= lc)
                    .unwrap_or(false) {
                    return None;
                }
            }
            Some(Ordering::Less)
        }
        else if self.constants.len() > other.constants.len() {
            for (ls, lc) in other.constants.iter() {
                if !self.constants
                    .get(ls)
                    .map(|rc| rc >= lc)
                    .unwrap_or(false) {
                    return None;
                }
            }
            Some(Ordering::Less)
        }
        else if self.constants == other.constants {
            Some(Ordering::Equal)
        }
        else {
            None
        }
    }
}

impl Constants {
    pub fn new() -> Constants {
        Constants {
            constants: HashMap::new()
        }
    }

    pub fn scalar(&self, scalar: &il::Scalar) -> Option<&il::Constant> {
        self.constants.get(scalar)
    }

    pub fn set_scalar(&mut self, scalar: il::Scalar, constant: Option<il::Constant>) {
        if constant.is_none() {
            self.constants.remove(&scalar);
        }
        else {
            self.constants.insert(scalar, constant.unwrap());
        }
    }

    pub fn eval(&self, expression: &il::Expression) -> Option<il::Constant> {
        let expression_scalars = expression.scalars();

        let expression =
            expression_scalars
                .into_iter()
                .fold(Some(expression.clone()), |expression, scalar|
                    self.scalar(scalar).map(|constant|
                        expression.map(|expr|
                            expr.replace_scalar(scalar, &constant.clone().into())
                                .unwrap())
                    ).unwrap_or(None)
                )?;

        eval(&expression).ok()
    }

    // TODO: This is an easy target for optiimization
    pub fn join(self, other: &Constants) -> Constants {
        let mut result = self.clone();
        for (scalar, constant) in other.constants.iter() {
            match self.scalar(scalar) {
                Some(c) =>
                if c != constant {
                    result.set_scalar(scalar.clone(), None);
                }
                else {
                    result.set_scalar(scalar.clone(), None);
                }
                None => result.set_scalar(scalar.clone(), Some(constant.clone()))
            }
        }
        result
    }
}

// We require a struct to implement methods for our analysis over.
struct ConstantsAnalysis {}

impl<'r> fixed_point::FixedPointAnalysis<'r, Constants> for ConstantsAnalysis {
    fn trans(&self, location: il::RefProgramLocation<'r>, state: Option<Constants>)
        -> Result<Constants> {

        let mut state = match state {
            Some(state) => state,
            None => Constants::new()
        };

        let state = match location.instruction() {
            Some(instruction) => match *instruction.operation() {
                il::Operation::Assign { ref dst, ref src } => {
                    let constant = state.eval(src);
                    state.set_scalar(dst.clone(), constant);
                    state
                },
                il::Operation::Load { ref dst, .. } => {
                    state.set_scalar(dst.clone(), None);
                    state
                }
                il::Operation::Store { .. } |
                il::Operation::Branch { .. } |
                il::Operation::Raise { .. } => Constants::new()
            },
            None => state
        };

        Ok(state)
    }

    fn join(&self, state0: Constants, state1: &Constants)
        -> Result<Constants> {

        Ok(state0.join(state1))
    }
}
<commit_msg>fix up constants analysis<commit_after>//! A very simple, and fast, constant propagation
//!
//! Each location has the known constant values for all variables before
//! execution of that location.
//!
//! Calling Constants::eval() uses the known constant values to replace scalars,
//! and then attempts to evaluate the expression to an `il::Constant`.

use analysis::fixed_point;
use error::*;
use executor::eval;
use il;
use std::collections::{HashMap};
use std::cmp::{Ordering, PartialOrd};

/// Compute constants for the given function
pub fn constants<'r>(function: &'r il::Function)
-> Result<HashMap<il::RefProgramLocation<'r>, Constants>> {
    let constants = fixed_point::fixed_point_forward(ConstantsAnalysis{}, function)?;

    // we're now going to remap constants, so each position holds the values of
    // constants immediately preceeding it.

    let mut result = HashMap::new();

    for (location, _) in &constants {
        result.insert(location.clone(),
            location.backward()?
                .into_iter()
                .fold(Constants::new(), |c, location|
                    c.join(&constants[&location])));
    }

    Ok(result)
}

#[allow(dead_code)] // Bottom is never used
#[derive(Clone, Debug, PartialEq)]
enum Constant {
    Top,
    Constant(il::Constant),
    Bottom
}

impl Constant {
    fn get(&self) -> Option<&il::Constant> {
        match *self {
            Constant::Constant(ref constant) => Some(constant),
            Constant::Top |
            Constant::Bottom => None
        }
    }
}

impl PartialOrd for Constant {
    fn partial_cmp(&self, other: &Constant) -> Option<Ordering> {
        match *self {
            Constant::Top => match *other {
                Constant::Top => Some(Ordering::Equal),
                Constant::Constant(_) |
                Constant::Bottom => Some(Ordering::Greater)
            },
            Constant::Constant(ref lc) => match *other {
                Constant::Top => Some(Ordering::Less),
                Constant::Constant(ref rc) =>
                    if lc == rc {
                        Some(Ordering::Equal)
                    }
                    else {
                        None
                    },
                Constant::Bottom => Some(Ordering::Greater),
            },
            Constant::Bottom => match *other {
                Constant::Top |
                Constant::Constant(_) => Some(Ordering::Less),
                Constant::Bottom => Some(Ordering::Equal)
            }
        }
    }
}

#[derive(Clone, Debug, PartialEq)]
pub struct Constants {
    constants: HashMap<il::Scalar, Constant>
}

impl PartialOrd for Constants {
    fn partial_cmp(&self, other: &Constants) -> Option<Ordering> {

        if self.constants.len() < other.constants.len() {
            for (ls, lc) in self.constants.iter() {
                if !other.constants
                    .get(ls)
                    .map(|rc| lc <= rc)
                    .unwrap_or(false) {
                    return None;
                }
            }
            Some(Ordering::Less)
        }
        else if self.constants.len() > other.constants.len() {
            for (ls, lc) in other.constants.iter() {
                if !self.constants
                    .get(ls)
                    .map(|rc| lc <= rc)
                    .unwrap_or(false) {
                    return None;
                }
            }
            Some(Ordering::Greater)
        }
        else {
            let mut order = Ordering::Equal;
            for (ls, lc) in &self.constants {
                match other.constants.get(ls) {
                    Some(rc) =>
                        if lc < rc {
                            if order <= Ordering::Equal {
                                order = Ordering::Less;
                            }
                            else {
                                return None;
                            }
                        }
                        else if lc > rc {
                            if order >= Ordering::Equal {
                                order = Ordering::Greater;
                            }
                            else {
                                return None;
                            }
                        },
                    None => {
                        return None;
                    }
                }
            }
            Some(order)
        }
    }
}

impl Constants {
    pub fn new() -> Constants {
        Constants {
            constants: HashMap::new()
        }
    }

    pub fn scalar(&self, scalar: &il::Scalar) -> Option<&il::Constant> {
        self.constants
            .get(scalar)
            .map(|constant| constant.get())
            .unwrap_or(None)
    }

    fn set_scalar(&mut self, scalar: il::Scalar, constant: Constant) {
        self.constants.insert(scalar, constant);
    }

    fn top(&mut self) {
        self.constants.iter_mut()
            .for_each(|(_, constant)| *constant = Constant::Top);
    }

    pub fn eval(&self, expression: &il::Expression) -> Option<il::Constant> {
        let expression_scalars = expression.scalars();

        let expression =
            expression_scalars
                .into_iter()
                .fold(Some(expression.clone()), |expression, scalar|
                    self.scalar(scalar).map(|constant|
                        expression.map(|expr|
                            expr.replace_scalar(scalar, &constant.clone().into())
                                .unwrap())
                    ).unwrap_or(None)
                )?;

        eval(&expression).ok()
    }

    fn join(self, other: &Constants) -> Constants {
        let mut result = self.clone();
        for (scalar, constant) in other.constants.iter() {
            match self.constants.get(scalar) {
                Some(c) =>
                    if c != constant {
                        result.set_scalar(scalar.clone(), Constant::Top);
                    },
                None => result.set_scalar(scalar.clone(), constant.clone())
            }
        }
        result
    }
}

// We require a struct to implement methods for our analysis over.
struct ConstantsAnalysis {}

impl<'r> fixed_point::FixedPointAnalysis<'r, Constants> for ConstantsAnalysis {
    fn trans(&self, location: il::RefProgramLocation<'r>, state: Option<Constants>)
        -> Result<Constants> {

        let mut state = match state {
            Some(state) => state,
            None => Constants::new()
        };

        let state = match location.instruction() {
            Some(instruction) => match *instruction.operation() {
                il::Operation::Assign { ref dst, ref src } => {
                    let constant =
                        state.eval(src)
                            .map(|constant| Constant::Constant(constant))
                            .unwrap_or(Constant::Top);
                    state.set_scalar(dst.clone(), constant);
                    state
                },
                il::Operation::Load { ref dst, .. } => {
                    state.set_scalar(dst.clone(), Constant::Top);
                    state
                },
                il::Operation::Store { .. } |
                il::Operation::Branch { .. } |
                il::Operation::Raise { .. } => {
                    state.top();
                    state
                }
            },
            None => state
        };

        Ok(state)
    }

    fn join(&self, state0: Constants, state1: &Constants)
        -> Result<Constants> {

        Ok(state0.join(state1))
    }
}<|endoftext|>


<commit_before>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::{File,fs};
use std::io::process::Command;
use std::path::posix::Path;
use std::os::homedir;
use libc::funcs::c95::stdlib::system;
#[cfg(test)] use std::rand::random;
#[cfg(test)] use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
        create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path)
    } else {
        println!("Project already exists.");
    }
}

fn default_editor_set() -> Result<Ok, Err> {
  let output = match Command::new("which").arg("$EDITOR").output() {
      Ok(output) => output,
      Err(e) => fail!("failed to execute process: {}", e),
  };

  println!("{}", output)
}

#[cfg(not(test))] fn open_project_file(path: &Path) {
    let method = format!("$EDITOR {}", path.display()).to_c_str();
    unsafe { system(method.unwrap()); };
}

#[cfg(test)] fn open_project_file(_path: &Path) { }

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    let method = format!("$EDITOR {}", path.display()).to_c_str();
    unsafe { system(method.unwrap()); };
}

/// Create the muxed directory and return the path if creation is successful.
fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    path.clone()
}

/// Return a boolean if the ~/.muxed/ dir exists.
fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

/// Return the users current homedir as a string.
fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

/// Test helper to standardize how random files and directories are generated.
#[cfg(test)]
fn random_name() -> String {
    format!("test_{}", random::<f64>())
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<commit_msg>Return a boolean if the return value of the command is not blank.<commit_after>//! The initializer module parses arguments and verfies commands are valid
//! The creator module handles creating the muxed directory and project files.
#![allow(experimental)]

use std::io::{File,fs};
use std::io::process::Command;
use std::path::posix::Path;
use std::os::homedir;
use libc::funcs::c95::stdlib::system;
#[cfg(test)] use std::rand::random;
#[cfg(test)] use std::finally::Finally;

static TEMPLATE: &'static str = include_str!("creator/template.yml");
static DEFAULT_MUXED_DIR: &'static str = "muxed";

pub fn new(name: &str) {
    let muxed_dir = if muxed_dir_exists(&DEFAULT_MUXED_DIR.to_string()) {
        Path::new(format!("{}/.{}/", homedir_string(), &DEFAULT_MUXED_DIR.to_string()))
    } else {
        create_muxed_dir(&DEFAULT_MUXED_DIR.to_string())
    };

    let path = &Path::new(format!("{}/{}", muxed_dir.display(), name));
    if !path.exists() {
        create_project_file(path)
    } else {
        println!("Project already exists.");
    }
}

fn default_editor_set() -> bool {
  let output = match Command::new("which").arg("$EDITOR").output() {
      Ok(output) => output.output.to_string(),
      Err(e) => fail!("failed to execute process: {}", e),
  };

  !output.is_empty()
}

#[cfg(not(test))] fn open_project_file(path: &Path) {
    let method = format!("$EDITOR {}", path.display()).to_c_str();
    unsafe { system(method.unwrap()); };
}

#[cfg(test)] fn open_project_file(_path: &Path) { }

/// Copy and create the new project file from a template. Attempt to open the
/// users default editor to make changes.
fn create_project_file(path: &Path) {
    match File::create(path).write(TEMPLATE.as_bytes()) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    let method = format!("$EDITOR {}", path.display()).to_c_str();
    unsafe { system(method.unwrap()); };
}

/// Create the muxed directory and return the path if creation is successful.
fn create_muxed_dir(name: &String) -> Path {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    match fs::mkdir(path, ::std::io::UserRWX) {
        Ok(()) => (),
        Err(_e) => println!("Failed to create project {}", path.filename()),
    }

    path.clone()
}

/// Return a boolean if the ~/.muxed/ dir exists.
fn muxed_dir_exists(name: &String) -> bool {
    let path = &Path::new(format!("{}/.{}", homedir_string(), name));
    path.exists()
}

/// Return the users current homedir as a string.
fn homedir_string() -> String {
    let home_unwrap = homedir().unwrap();
    format!("{}", home_unwrap.display())
}

/// Test helper to standardize how random files and directories are generated.
#[cfg(test)]
fn random_name() -> String {
    format!("test_{}", random::<f64>())
}

#[test]
fn muxed_dir_exists_returns_false() {
    assert!(!muxed_dir_exists(&random_name()));
}

#[test]
fn muxed_dir_exists_returns_true() {
    let dir = random_name();
    create_muxed_dir(&dir);
    assert!(muxed_dir_exists(&dir));

    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn creates_muxed_dir() {
    let dir = random_name();
    let muxed_path  = &Path::new(format!("{}/.{}/", homedir_string(), dir));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    match fs::rmdir_recursive(muxed_path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to remove the path {} with error {}", muxed_path.display(), e),
    }
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    assert!(path.exists());
    match fs::unlink(path) {
        Ok(()) => (), // succeeded
        Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
    }
}

#[test]
// TODO: Fix this test so it verifies something better.
fn new_doesnt_overwrite_existing_file() {
    let name = random_name();
    let path = &Path::new(format!("{}/.muxed/{}", homedir_string(), name));
    new(name.as_slice());
    (|| {
        new(name.as_slice());
    }).finally(|| {
        match fs::unlink(path) {
            Ok(()) => (), // succeeded
            Err(e) => println!("Failed to unlink the path {} with error {}", path.display(), e),
        }
    })
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::bundle::{self, Bundle, Exchange, Response, Uri};
use crate::prelude::*;
use cbor_event::Len;
use std::io::Write;

use cbor_event::se::Serializer;

struct CountWrite<W> {
    count: usize,
    inner: W,
}

impl<W> CountWrite<W> {
    fn new(inner: W) -> Self {
        CountWrite { count: 0, inner }
    }
}

impl<W: Write> Write for CountWrite<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.count += buf.len();
        self.inner.write(buf)
    }
    fn flush(&mut self) -> std::io::Result<()> {
        self.inner.flush()
    }
}

pub(crate) fn encode<W: Write + Sized>(bundle: &Bundle, write: W) -> Result<()> {
    Encoder::new(CountWrite::new(write)).encode(bundle)?;
    Ok(())
}

pub(crate) fn encode_to_vec(bundle: &Bundle) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    encode(bundle, &mut write)?;
    Ok(write)
}

struct Encoder<W: Write> {
    se: Serializer<W>,
}

trait Count {
    fn count(&self) -> usize;
}

impl<W: Write> Count for Serializer<CountWrite<W>> {
    fn count(&self) -> usize {
        // Use unsafe because Serializer.0 is private.
        // TODO: Avoid to use unsafe.
        let se_ptr: *const Serializer<CountWrite<W>> = self;
        let count_write_ptr = se_ptr.cast::<CountWrite<W>>();
        unsafe { (*count_write_ptr).count }
    }
}

impl<W: Write> Encoder<W> {
    fn new(write: W) -> Self {
        Encoder {
            // se: Serializer::new(CountWrite::new(write)),
            se: Serializer::new(write),
        }
    }

    fn write_magic(&mut self) -> Result<()> {
        self.se.write_bytes(bundle::HEADER_MAGIC_BYTES)?;
        Ok(())
    }

    fn write_version(&mut self, version: &bundle::Version) -> Result<()> {
        self.se.write_bytes(version.bytes())?;
        Ok(())
    }

    fn write_primary_url(&mut self, primary_url: &Uri) -> Result<()> {
        self.se.write_text(&primary_url.to_string())?;
        Ok(())
    }
}

impl<W: Write + Sized> Encoder<CountWrite<W>> {
    fn encode(&mut self, bundle: &Bundle) -> Result<()> {
        self.se
            .write_array(Len::Len(bundle::TOP_ARRAY_LEN as u64))?;
        self.write_magic()?;
        self.write_version(&bundle.version)?;
        self.write_primary_url(&bundle.primary_url)?;

        let sections = encode_sections(bundle)?;

        let section_length_cbor = encode_section_lengths(&sections)?;
        self.se.write_bytes(section_length_cbor)?;

        self.se.write_array(Len::Len(sections.len() as u64))?;
        for section in sections {
            self.se.write_raw_bytes(&section.bytes)?;
        }

        // Write the length of bytes
        self.se.write_unsigned_integer(self.se.count() as u64 + 8)?; // 8 is the length of u64.
        Ok(())
    }
}

struct Section {
    name: &'static str,
    bytes: Vec<u8>,
}

fn encode_sections(bundle: &Bundle) -> Result<Vec<Section>> {
    let mut sections = Vec::new();

    // manifest
    if let Some(uri) = &bundle.manifest {
        let bytes = encode_manifest_section(uri)?;
        sections.push(Section {
            name: "manifest",
            bytes,
        });
    };

    // responses
    let (response_section_bytes, response_locations) = encode_response_section(&bundle.exchanges)?;

    let response_section = Section {
        name: "responses",
        bytes: response_section_bytes,
    };

    // index from responses
    let index_section = Section {
        name: "index",
        bytes: encode_index_section(&response_locations)?,
    };

    sections.push(index_section);
    sections.push(response_section);
    Ok(sections)
}

fn encode_manifest_section(url: &Uri) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    let mut se = Serializer::new(&mut write);
    se.write_text(url.to_string())?;
    Ok(write)
}

struct ResponseLocation {
    uri: Uri,
    offset: usize,
    length: usize,
}

fn encode_response_section(exchanges: &[Exchange]) -> Result<(Vec<u8>, Vec<ResponseLocation>)> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(CountWrite::new(&mut bytes));

    se.write_array(Len::Len(exchanges.len() as u64))?;

    let mut response_locations = Vec::new();

    for exchange in exchanges {
        let offset = se.count();

        se.write_array(Len::Len(2))?;
        se.write_bytes(&encode_headers(&exchange.response)?)?;
        se.write_bytes(&exchange.response.body())?;

        response_locations.push(ResponseLocation {
            uri: exchange.request.uri().clone(),
            offset,
            length: se.count() - offset,
        });
    }

    Ok((bytes, response_locations))
}

fn encode_index_section(response_locations: &[ResponseLocation]) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    for response_location in response_locations {
        let mut key = Serializer::new(Vec::new());
        key.write_text(response_location.uri.to_string())?;

        let mut value = Serializer::new(Vec::new());
        value.write_array(Len::Len(3))?;
        // TODO: Support variants.
        value.write_bytes(b"")?;
        value.write_unsigned_integer(response_location.offset as u64)?;
        value.write_unsigned_integer(response_location.length as u64)?;

        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new(Vec::new());
    se.write_map(Len::Len(response_locations.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}

fn encode_section_lengths(sections: &[Section]) -> Result<Vec<u8>> {
    let mut bytes = Vec::new();
    let mut se = Serializer::new(&mut bytes);

    se.write_array(Len::Len((sections.len() * 2) as u64))?;
    for section in sections {
        se.write_text(section.name)?;
        se.write_unsigned_integer(section.bytes.len() as u64)?;
    }
    Ok(bytes)
}

fn encode_headers(response: &Response) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    // Write status
    let mut key = Serializer::new(Vec::new());
    key.write_bytes(b":status")?;
    let mut value = Serializer::new(Vec::new());
    value.write_bytes(response.status().as_u16().to_string().as_bytes())?;
    map.insert(key.finalize(), value.finalize());

    // Write headers
    for (header_name, header_value) in response.headers() {
        let mut key = Serializer::new(Vec::new());
        key.write_bytes(header_name.as_str().as_bytes())?;
        let mut value = Serializer::new(Vec::new());
        value.write_bytes(header_value.to_str()?.as_bytes())?;
        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new(Vec::new());
    se.write_map(Len::Len(map.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}
<commit_msg>cleanup, no functional change<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::bundle::{self, Bundle, Exchange, Response, Uri};
use crate::prelude::*;
use cbor_event::Len;
use std::io::Write;

use cbor_event::se::Serializer;

struct CountWrite<W> {
    count: usize,
    inner: W,
}

impl<W> CountWrite<W> {
    fn new(inner: W) -> Self {
        CountWrite { count: 0, inner }
    }
}

impl<W: Write> Write for CountWrite<W> {
    fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
        self.count += buf.len();
        self.inner.write(buf)
    }
    fn flush(&mut self) -> std::io::Result<()> {
        self.inner.flush()
    }
}

pub(crate) fn encode<W: Write + Sized>(bundle: &Bundle, write: W) -> Result<()> {
    Encoder::new(CountWrite::new(write)).encode(bundle)?;
    Ok(())
}

pub(crate) fn encode_to_vec(bundle: &Bundle) -> Result<Vec<u8>> {
    let mut write = Vec::new();
    encode(bundle, &mut write)?;
    Ok(write)
}

struct Encoder<W: Write> {
    se: Serializer<W>,
}

trait Count {
    fn count(&self) -> usize;
}

impl<W: Write> Count for Serializer<CountWrite<W>> {
    fn count(&self) -> usize {
        // Use unsafe because Serializer.0 is private.
        // TODO: Avoid to use unsafe.
        let se_ptr: *const Serializer<CountWrite<W>> = self;
        let count_write_ptr = se_ptr.cast::<CountWrite<W>>();
        unsafe { (*count_write_ptr).count }
    }
}

impl<W: Write> Encoder<W> {
    fn new(write: W) -> Self {
        Encoder {
            se: Serializer::new(write),
        }
    }

    fn write_magic(&mut self) -> Result<()> {
        self.se.write_bytes(bundle::HEADER_MAGIC_BYTES)?;
        Ok(())
    }

    fn write_version(&mut self, version: &bundle::Version) -> Result<()> {
        self.se.write_bytes(version.bytes())?;
        Ok(())
    }

    fn write_primary_url(&mut self, primary_url: &Uri) -> Result<()> {
        self.se.write_text(&primary_url.to_string())?;
        Ok(())
    }
}

impl<W: Write + Sized> Encoder<CountWrite<W>> {
    fn encode(&mut self, bundle: &Bundle) -> Result<()> {
        self.se
            .write_array(Len::Len(bundle::TOP_ARRAY_LEN as u64))?;
        self.write_magic()?;
        self.write_version(&bundle.version)?;
        self.write_primary_url(&bundle.primary_url)?;

        let sections = encode_sections(bundle)?;

        let section_length_cbor = encode_section_lengths(&sections)?;
        self.se.write_bytes(section_length_cbor)?;

        self.se.write_array(Len::Len(sections.len() as u64))?;
        for section in sections {
            self.se.write_raw_bytes(&section.bytes)?;
        }

        // Write the length of bytes
        self.se.write_unsigned_integer(self.se.count() as u64 + 8)?; // 8 is the length of u64.
        Ok(())
    }
}

struct Section {
    name: &'static str,
    bytes: Vec<u8>,
}

fn encode_sections(bundle: &Bundle) -> Result<Vec<Section>> {
    let mut sections = Vec::new();

    // manifest
    if let Some(uri) = &bundle.manifest {
        let bytes = encode_manifest_section(uri)?;
        sections.push(Section {
            name: "manifest",
            bytes,
        });
    };

    // responses
    let (response_section_bytes, response_locations) = encode_response_section(&bundle.exchanges)?;

    let response_section = Section {
        name: "responses",
        bytes: response_section_bytes,
    };

    // index from responses
    let index_section = Section {
        name: "index",
        bytes: encode_index_section(&response_locations)?,
    };

    sections.push(index_section);
    sections.push(response_section);
    Ok(sections)
}

fn encode_manifest_section(url: &Uri) -> Result<Vec<u8>> {
    let mut se = Serializer::new_vec();
    se.write_text(url.to_string())?;
    Ok(se.finalize())
}

struct ResponseLocation {
    uri: Uri,
    offset: usize,
    length: usize,
}

fn encode_response_section(exchanges: &[Exchange]) -> Result<(Vec<u8>, Vec<ResponseLocation>)> {
    let mut se = Serializer::new(CountWrite::new(Vec::new()));

    se.write_array(Len::Len(exchanges.len() as u64))?;

    let mut response_locations = Vec::new();

    for exchange in exchanges {
        let offset = se.count();

        se.write_array(Len::Len(2))?;
        se.write_bytes(&encode_headers(&exchange.response)?)?;
        se.write_bytes(&exchange.response.body())?;

        response_locations.push(ResponseLocation {
            uri: exchange.request.uri().clone(),
            offset,
            length: se.count() - offset,
        });
    }

    Ok((se.finalize().inner, response_locations))
}

fn encode_index_section(response_locations: &[ResponseLocation]) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    for response_location in response_locations {
        let mut key = Serializer::new_vec();
        key.write_text(response_location.uri.to_string())?;

        let mut value = Serializer::new_vec();
        value.write_array(Len::Len(3))?;
        // TODO: Support variants.
        value.write_bytes(b"")?;
        value.write_unsigned_integer(response_location.offset as u64)?;
        value.write_unsigned_integer(response_location.length as u64)?;

        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new_vec();
    se.write_map(Len::Len(response_locations.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}

fn encode_section_lengths(sections: &[Section]) -> Result<Vec<u8>> {
    let mut se = Serializer::new_vec();

    se.write_array(Len::Len((sections.len() * 2) as u64))?;
    for section in sections {
        se.write_text(section.name)?;
        se.write_unsigned_integer(section.bytes.len() as u64)?;
    }
    Ok(se.finalize())
}

fn encode_headers(response: &Response) -> Result<Vec<u8>> {
    // Map keys must be sorted.
    // See [3.9. Canonical CBOR](https://tools.ietf.org/html/rfc7049#section-3.9)
    let mut map = std::collections::BTreeMap::<Vec<u8>, Vec<u8>>::new();

    // Write status
    let mut key = Serializer::new_vec();
    key.write_bytes(b":status")?;
    let mut value = Serializer::new_vec();
    value.write_bytes(response.status().as_u16().to_string().as_bytes())?;
    map.insert(key.finalize(), value.finalize());

    // Write headers
    for (header_name, header_value) in response.headers() {
        let mut key = Serializer::new_vec();
        key.write_bytes(header_name.as_str().as_bytes())?;
        let mut value = Serializer::new_vec();
        value.write_bytes(header_value.to_str()?.as_bytes())?;
        map.insert(key.finalize(), value.finalize());
    }

    let mut se = Serializer::new_vec();
    se.write_map(Len::Len(map.len() as u64))?;
    for (key, value) in map {
        se.write_raw_bytes(&key)?;
        se.write_raw_bytes(&value)?;
    }
    Ok(se.finalize())
}
<|endoftext|>


<commit_before>use std::fmt;
use enum_set::CLike;
use bit_field::BitField;
use std::mem;

pub enum StackPointer {
    MSP(u32),
    PSP(u32),
}

pub struct PSR {
    pub value: u32,
}

pub trait Apsr {
    fn get_n(&self) -> bool;
    fn set_n(&mut self, result: u32);

    fn get_z(&self) -> bool;
    fn set_z(&mut self, result: u32);

    fn get_c(&self) -> bool;
    fn set_c(&mut self, c: bool);

    fn get_v(&self) -> bool;
    fn set_v(&mut self, v: bool);

    fn get_q(&self) -> bool;
    fn set_q(&mut self, q: bool);
}

pub trait Ipsr {
    fn get_exception_number(&self) -> u8;
}

// Execution Program Status register
//
// A view to PSR register containing the data.
pub trait Epsr {
    fn set_t(&mut self, t: bool);
    fn get_t(&self) -> bool;
}

impl Apsr for PSR {
    fn get_n(&self) -> bool {
        (*self).value.get_bit(31)
    }

    fn set_n(&mut self, result: u32) {
        (*self).value &= 0x7fff_ffff;
        (*self).value |= result & 0x8000_0000;
    }

    fn get_z(&self) -> bool {
        (*self).value.get_bit(30)
    }
    fn set_z(&mut self, result: u32) {
        if result == 0 {
            (*self).value |= 0x4000_0000;
        } else {
            (*self).value &= 0x4000_0000 ^ 0xffff_ffff;
        }
    }

    fn get_c(&self) -> bool {
        (*self).value.get_bit(29)
    }
    fn set_c(&mut self, c: bool) {
        if c {
            (*self).value |= 0x2000_0000;
        } else {
            (*self).value &= 0x2000_0000 ^ 0xffff_ffff;
        }
    }
    fn get_v(&self) -> bool {
        (*self).value.get_bit(28)
    }
    fn set_v(&mut self, v: bool) {
        if v {
            (*self).value |= 0x1000_0000;
        } else {
            (*self).value &= 0x1000_0000 ^ 0xffff_ffff;
        }
    }

    fn get_q(&self) -> bool {
        (*self).value.get_bit(27)
    }
    fn set_q(&mut self, q: bool) {
        (*self).value.set_bit(27, q);
    }
}

impl Epsr for PSR {
    fn get_t(&self) -> bool {
        (*self).value.get_bit(24)
    }
    fn set_t(&mut self, n: bool) {
        (*self).value.set_bit(24, n);
    }
}

impl Ipsr for PSR {
    fn get_exception_number(&self) -> u8 {
        (*self).value.get_bits(0..6) as u8
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u32)]
pub enum Reg {
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    R8,
    R9,
    R10,
    R11,
    R12,
    SP,
    LR,
    PC,
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u32)]
pub enum SpecialReg {
    APSR,
    IAPSR,
    EAPSR,
    XPSR,
    IPSR,
    EPSR,
    IEPSR,
    MSP,
    PSP,
    PRIMASK,
    CONTROL,
}

impl CLike for Reg {
    fn to_u32(&self) -> u32 {
        *self as u32
    }

    unsafe fn from_u32(v: u32) -> Reg {
        mem::transmute(v)
    }
}

impl Reg {
    pub fn value(&self) -> usize {
        match *self {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }

    pub fn from_u16(n: u16) -> Option<Reg> {
        match n {
            0 => Some(Reg::R0),
            1 => Some(Reg::R1),
            2 => Some(Reg::R2),
            3 => Some(Reg::R3),
            4 => Some(Reg::R4),
            5 => Some(Reg::R5),
            6 => Some(Reg::R6),
            7 => Some(Reg::R7),
            8 => Some(Reg::R8),
            9 => Some(Reg::R9),
            10 => Some(Reg::R10),
            11 => Some(Reg::R11),
            12 => Some(Reg::R12),
            13 => Some(Reg::SP),
            14 => Some(Reg::LR),
            15 => Some(Reg::PC),
            _ => None,
        }
    }
}

impl From<u8> for Reg {
    fn from(value: u8) -> Self {
        match value & 0xf {
            0 => Reg::R0,
            1 => Reg::R1,
            2 => Reg::R2,
            3 => Reg::R3,
            4 => Reg::R4,
            5 => Reg::R5,
            6 => Reg::R6,
            7 => Reg::R7,
            8 => Reg::R8,
            9 => Reg::R9,
            10 => Reg::R10,
            11 => Reg::R11,
            12 => Reg::R12,
            13 => Reg::SP,
            14 => Reg::LR,
            15 => Reg::PC,
            _ => Reg::R0,
        }
    }
}

impl From<Reg> for u8 {
    fn from(value: Reg) -> Self {
        match value {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }
}

impl From<Reg> for usize {
    fn from(value: Reg) -> Self {
        match value {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }
}

impl SpecialReg {
    pub fn from_u16(n: u16) -> Option<SpecialReg> {
        match n {
            0 => Some(SpecialReg::APSR),
            1 => Some(SpecialReg::IAPSR),
            2 => Some(SpecialReg::EAPSR),
            3 => Some(SpecialReg::XPSR),
            5 => Some(SpecialReg::IPSR),
            6 => Some(SpecialReg::EPSR),
            7 => Some(SpecialReg::IEPSR),
            8 => Some(SpecialReg::MSP),
            9 => Some(SpecialReg::PSP),
            16 => Some(SpecialReg::PRIMASK),
            20 => Some(SpecialReg::CONTROL),
            _ => None,
        }
    }
}

impl From<u8> for SpecialReg {
    fn from(value: u8) -> Self {
        match value & 0x1f {
            0 => SpecialReg::APSR,
            1 => SpecialReg::IAPSR,
            2 => SpecialReg::EAPSR,
            3 => SpecialReg::XPSR,
            5 => SpecialReg::IPSR,
            6 => SpecialReg::EPSR,
            7 => SpecialReg::IEPSR,
            8 => SpecialReg::MSP,
            9 => SpecialReg::PSP,
            16 => SpecialReg::PRIMASK,
            20 => SpecialReg::CONTROL,
            _ => SpecialReg::APSR,
        }
    }
}

impl fmt::Display for Reg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Reg::R0 => write!(f, "R0"),
            Reg::R1 => write!(f, "R1"),
            Reg::R2 => write!(f, "R2"),
            Reg::R3 => write!(f, "R3"),
            Reg::R4 => write!(f, "R4"),
            Reg::R5 => write!(f, "R5"),
            Reg::R6 => write!(f, "R6"),
            Reg::R7 => write!(f, "R7"),
            Reg::R8 => write!(f, "R8"),
            Reg::R9 => write!(f, "R9"),
            Reg::R10 => write!(f, "R10"),
            Reg::R11 => write!(f, "R11"),
            Reg::R12 => write!(f, "R12"),
            Reg::SP => write!(f, "SP"),
            Reg::LR => write!(f, "LR"),
            Reg::PC => write!(f, "PC"),
        }
    }
}

impl fmt::Display for SpecialReg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SpecialReg::APSR => write!(f, "APSR"),
            SpecialReg::IAPSR => write!(f, "IAPSR"),
            SpecialReg::EAPSR => write!(f, "EAPSR"),
            SpecialReg::XPSR => write!(f, "XPSR"),
            SpecialReg::IPSR => write!(f, "IPSR"),
            SpecialReg::EPSR => write!(f, "EPSR"),
            SpecialReg::IEPSR => write!(f, "IEPSR"),
            SpecialReg::MSP => write!(f, "MSP"),
            SpecialReg::PSP => write!(f, "PSP"),
            SpecialReg::PRIMASK => write!(f, "PRIMASK"),
            SpecialReg::CONTROL => write!(f, "CONTROL"),
        }
    }
}

pub struct Control {
    pub n_priv: bool,
    pub sp_sel: bool,
}

impl From<Control> for u8 {
    fn from(control: Control) -> Self {
        control.n_priv as u8 + ((control.sp_sel as u8) << 1)
    }
}
<commit_msg>use small letters for constant style on traces<commit_after>use std::fmt;
use enum_set::CLike;
use bit_field::BitField;
use std::mem;

pub enum StackPointer {
    MSP(u32),
    PSP(u32),
}

pub struct PSR {
    pub value: u32,
}

pub trait Apsr {
    fn get_n(&self) -> bool;
    fn set_n(&mut self, result: u32);

    fn get_z(&self) -> bool;
    fn set_z(&mut self, result: u32);

    fn get_c(&self) -> bool;
    fn set_c(&mut self, c: bool);

    fn get_v(&self) -> bool;
    fn set_v(&mut self, v: bool);

    fn get_q(&self) -> bool;
    fn set_q(&mut self, q: bool);
}

pub trait Ipsr {
    fn get_exception_number(&self) -> u8;
}

// Execution Program Status register
//
// A view to PSR register containing the data.
pub trait Epsr {
    fn set_t(&mut self, t: bool);
    fn get_t(&self) -> bool;
}

impl Apsr for PSR {
    fn get_n(&self) -> bool {
        (*self).value.get_bit(31)
    }

    fn set_n(&mut self, result: u32) {
        (*self).value &= 0x7fff_ffff;
        (*self).value |= result & 0x8000_0000;
    }

    fn get_z(&self) -> bool {
        (*self).value.get_bit(30)
    }
    fn set_z(&mut self, result: u32) {
        if result == 0 {
            (*self).value |= 0x4000_0000;
        } else {
            (*self).value &= 0x4000_0000 ^ 0xffff_ffff;
        }
    }

    fn get_c(&self) -> bool {
        (*self).value.get_bit(29)
    }
    fn set_c(&mut self, c: bool) {
        if c {
            (*self).value |= 0x2000_0000;
        } else {
            (*self).value &= 0x2000_0000 ^ 0xffff_ffff;
        }
    }
    fn get_v(&self) -> bool {
        (*self).value.get_bit(28)
    }
    fn set_v(&mut self, v: bool) {
        if v {
            (*self).value |= 0x1000_0000;
        } else {
            (*self).value &= 0x1000_0000 ^ 0xffff_ffff;
        }
    }

    fn get_q(&self) -> bool {
        (*self).value.get_bit(27)
    }
    fn set_q(&mut self, q: bool) {
        (*self).value.set_bit(27, q);
    }
}

impl Epsr for PSR {
    fn get_t(&self) -> bool {
        (*self).value.get_bit(24)
    }
    fn set_t(&mut self, n: bool) {
        (*self).value.set_bit(24, n);
    }
}

impl Ipsr for PSR {
    fn get_exception_number(&self) -> u8 {
        (*self).value.get_bits(0..6) as u8
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u32)]
pub enum Reg {
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    R8,
    R9,
    R10,
    R11,
    R12,
    SP,
    LR,
    PC,
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[repr(u32)]
pub enum SpecialReg {
    APSR,
    IAPSR,
    EAPSR,
    XPSR,
    IPSR,
    EPSR,
    IEPSR,
    MSP,
    PSP,
    PRIMASK,
    CONTROL,
}

impl CLike for Reg {
    fn to_u32(&self) -> u32 {
        *self as u32
    }

    unsafe fn from_u32(v: u32) -> Reg {
        mem::transmute(v)
    }
}

impl Reg {
    pub fn value(&self) -> usize {
        match *self {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }

    pub fn from_u16(n: u16) -> Option<Reg> {
        match n {
            0 => Some(Reg::R0),
            1 => Some(Reg::R1),
            2 => Some(Reg::R2),
            3 => Some(Reg::R3),
            4 => Some(Reg::R4),
            5 => Some(Reg::R5),
            6 => Some(Reg::R6),
            7 => Some(Reg::R7),
            8 => Some(Reg::R8),
            9 => Some(Reg::R9),
            10 => Some(Reg::R10),
            11 => Some(Reg::R11),
            12 => Some(Reg::R12),
            13 => Some(Reg::SP),
            14 => Some(Reg::LR),
            15 => Some(Reg::PC),
            _ => None,
        }
    }
}

impl From<u8> for Reg {
    fn from(value: u8) -> Self {
        match value & 0xf {
            0 => Reg::R0,
            1 => Reg::R1,
            2 => Reg::R2,
            3 => Reg::R3,
            4 => Reg::R4,
            5 => Reg::R5,
            6 => Reg::R6,
            7 => Reg::R7,
            8 => Reg::R8,
            9 => Reg::R9,
            10 => Reg::R10,
            11 => Reg::R11,
            12 => Reg::R12,
            13 => Reg::SP,
            14 => Reg::LR,
            15 => Reg::PC,
            _ => Reg::R0,
        }
    }
}

impl From<Reg> for u8 {
    fn from(value: Reg) -> Self {
        match value {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }
}

impl From<Reg> for usize {
    fn from(value: Reg) -> Self {
        match value {
            Reg::R0 => 0,
            Reg::R1 => 1,
            Reg::R2 => 2,
            Reg::R3 => 3,
            Reg::R4 => 4,
            Reg::R5 => 5,
            Reg::R6 => 6,
            Reg::R7 => 7,
            Reg::R8 => 8,
            Reg::R9 => 9,
            Reg::R10 => 10,
            Reg::R11 => 11,
            Reg::R12 => 12,
            Reg::SP => 13,
            Reg::LR => 14,
            Reg::PC => 15,
        }
    }
}

impl SpecialReg {
    pub fn from_u16(n: u16) -> Option<SpecialReg> {
        match n {
            0 => Some(SpecialReg::APSR),
            1 => Some(SpecialReg::IAPSR),
            2 => Some(SpecialReg::EAPSR),
            3 => Some(SpecialReg::XPSR),
            5 => Some(SpecialReg::IPSR),
            6 => Some(SpecialReg::EPSR),
            7 => Some(SpecialReg::IEPSR),
            8 => Some(SpecialReg::MSP),
            9 => Some(SpecialReg::PSP),
            16 => Some(SpecialReg::PRIMASK),
            20 => Some(SpecialReg::CONTROL),
            _ => None,
        }
    }
}

impl From<u8> for SpecialReg {
    fn from(value: u8) -> Self {
        match value & 0x1f {
            0 => SpecialReg::APSR,
            1 => SpecialReg::IAPSR,
            2 => SpecialReg::EAPSR,
            3 => SpecialReg::XPSR,
            5 => SpecialReg::IPSR,
            6 => SpecialReg::EPSR,
            7 => SpecialReg::IEPSR,
            8 => SpecialReg::MSP,
            9 => SpecialReg::PSP,
            16 => SpecialReg::PRIMASK,
            20 => SpecialReg::CONTROL,
            _ => SpecialReg::APSR,
        }
    }
}

impl fmt::Display for Reg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Reg::R0 => write!(f, "r0"),
            Reg::R1 => write!(f, "r1"),
            Reg::R2 => write!(f, "r2"),
            Reg::R3 => write!(f, "r3"),
            Reg::R4 => write!(f, "r4"),
            Reg::R5 => write!(f, "r5"),
            Reg::R6 => write!(f, "r6"),
            Reg::R7 => write!(f, "r7"),
            Reg::R8 => write!(f, "r8"),
            Reg::R9 => write!(f, "r9"),
            Reg::R10 => write!(f, "r10"),
            Reg::R11 => write!(f, "r11"),
            Reg::R12 => write!(f, "r12"),
            Reg::SP => write!(f, "sp"),
            Reg::LR => write!(f, "lr"),
            Reg::PC => write!(f, "pc"),
        }
    }
}

impl fmt::Display for SpecialReg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            SpecialReg::APSR => write!(f, "APSR"),
            SpecialReg::IAPSR => write!(f, "IAPSR"),
            SpecialReg::EAPSR => write!(f, "EAPSR"),
            SpecialReg::XPSR => write!(f, "XPSR"),
            SpecialReg::IPSR => write!(f, "IPSR"),
            SpecialReg::EPSR => write!(f, "EPSR"),
            SpecialReg::IEPSR => write!(f, "IEPSR"),
            SpecialReg::MSP => write!(f, "MSP"),
            SpecialReg::PSP => write!(f, "PSP"),
            SpecialReg::PRIMASK => write!(f, "PRIMASK"),
            SpecialReg::CONTROL => write!(f, "CONTROL"),
        }
    }
}

pub struct Control {
    pub n_priv: bool,
    pub sp_sel: bool,
}

impl From<Control> for u8 {
    fn from(control: Control) -> Self {
        control.n_priv as u8 + ((control.sp_sel as u8) << 1)
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use futures::{future::FutureExt, select_biased};
use tbot::{connectors::Https, types::parameters};
use tokio::{
    self,
    stream::StreamExt,
    sync::Notify,
    time::{self, delay_queue::DelayQueue, Duration, Instant},
};

use crate::client::pull_feed;
use crate::data::{Database, Feed, FeedUpdate};
use crate::messages::{format_large_msg, Escape};

pub fn start(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    min_interval: u32,
    max_interval: u32,
) {
    let mut queue = FetchQueue::new();
    // TODO: Don't use interval, it can accumulate ticks
    // replace it with delay_until
    let mut interval = time::interval_at(Instant::now(), Duration::from_secs(min_interval as u64));
    tokio::spawn(async move {
        loop {
            select_biased! {
                feed = queue.next().fuse() => {
                    let feed = feed.expect("unreachable");
                    let bot = bot.clone();
                    let db = db.clone();
                    tokio::spawn(async move {
                        if let Err(e) = fetch_and_push_updates(bot, db, feed).await {
                            dbg!(e);
                        }
                    });
                }
                _ = interval.tick().fuse() => {
                    let feeds = db.lock().unwrap().all_feeds();
                    for feed in feeds {
                        let feed_interval = cmp::min(
                            feed.ttl.map(|ttl| ttl * 60).unwrap_or(min_interval),
                            max_interval,
                        ) as u64 - 1; // after -1, we can stagger with `interval`
                        queue.enqueue(feed, Duration::from_secs(feed_interval));
                    }
                }
            }
        }

        queue.enqueue(feed, Duration::from_secs(feed_interval));
    });
}

async fn fetch_and_push_updates(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    feed: Feed,
) -> Result<(), tbot::errors::MethodCall> {
    let new_feed = match pull_feed(&feed.link).await {
        Ok(feed) => feed,
        Err(e) => {
            let down_time = db.lock().unwrap().get_or_update_down_time(&feed.link);
            // 5 days
            if down_time.as_secs() > 5 * 24 * 60 * 60 {
                let msg = format!(
                    "《{}》\
                     已经连续 5 天拉取出错 ({}),\
                     可能已经关闭, 请取消订阅",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&e.to_string())
                );
                push_updates(&bot, &db, feed.subscribers, parameters::Text::html(&msg)).await?;
            }
            return Ok(());
        }
    };

    let updates = db.lock().unwrap().update(&feed.link, new_feed);
    for update in updates {
        match update {
            FeedUpdate::Items(items) => {
                let msgs =
                    format_large_msg(format!("{}", Escape(&feed.title)), &items, |item| {
                        let title = item
                            .title
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.title);
                        let link = item
                            .link
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.link);
                        format!("{}", Escape(link), Escape(title))
                    });
                for msg in msgs {
                    push_updates(
                        &bot,
                        &db,
                        feed.subscribers.iter().copied(),
                        parameters::Text::html(&msg),
                    )
                    .await?;
                }
            }
            FeedUpdate::Title(new_title) => {
                let msg = format!(
                    "{} 已更名为 {}",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&new_title)
                );
                push_updates(
                    &bot,
                    &db,
                    feed.subscribers.iter().copied(),
                    parameters::Text::html(&msg),
                )
                .await?;
            }
        }
    }
    Ok(())
}

async fn push_updates<I: IntoIterator<Item = i64>>(
    bot: &tbot::Bot<Https>,
    db: &Arc<Mutex<Database>>,
    subscribers: I,
    msg: parameters::Text<'_>,
) -> Result<(), tbot::errors::MethodCall> {
    use tbot::errors::MethodCall;
    for mut subscriber in subscribers {
        'retry: for _ in 0..3 {
            match bot
                .send_message(tbot::types::chat::Id(subscriber), msg)
                .call()
                .await
            {
                Err(MethodCall::RequestError { description, .. })
                    if chat_is_unavailable(&description) =>
                {
                    db.lock().unwrap().delete_subscriber(subscriber);
                }
                Err(MethodCall::RequestError {
                    migrate_to_chat_id: Some(new_chat_id),
                    ..
                }) => {
                    db.lock()
                        .unwrap()
                        .update_subscriber(subscriber, new_chat_id.0);
                    subscriber = new_chat_id.0;
                    continue 'retry;
                }
                Err(MethodCall::RequestError {
                    retry_after: Some(delay),
                    ..
                }) => {
                    time::delay_for(Duration::from_secs(delay)).await;
                    continue 'retry;
                }
                other => {
                    other?;
                }
            }
            break 'retry;
        }
    }
    Ok(())
}

pub fn chat_is_unavailable(s: &str) -> bool {
    s.contains("Forbidden") || s.contains("chat not found")
}

#[derive(Default)]
struct FetchQueue {
    feeds: HashMap<String, Feed>,
    notifies: DelayQueue<String>,
    wakeup: Notify,
}

impl FetchQueue {
    fn new() -> Self {
        Self::default()
    }

    fn enqueue(&mut self, feed: Feed, delay: Duration) -> bool {
        let exists = self.feeds.contains_key(&feed.link);
        if !exists {
            self.notifies.insert(feed.link.clone(), delay);
            self.feeds.insert(feed.link.clone(), feed);
            self.wakeup.notify();
        }
        !exists
    }

    async fn next(&mut self) -> Result<Feed, time::Error> {
        loop {
            if let Some(feed_id) = self.notifies.next().await {
                let feed = self.feeds.remove(feed_id?.get_ref()).unwrap();
                break Ok(feed);
            } else {
                self.wakeup.notified().await;
            }
        }
    }
}
<commit_msg>Fix a copy/paste error<commit_after>use std::cmp;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

use futures::{future::FutureExt, select_biased};
use tbot::{connectors::Https, types::parameters};
use tokio::{
    self,
    stream::StreamExt,
    sync::Notify,
    time::{self, delay_queue::DelayQueue, Duration, Instant},
};

use crate::client::pull_feed;
use crate::data::{Database, Feed, FeedUpdate};
use crate::messages::{format_large_msg, Escape};

pub fn start(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    min_interval: u32,
    max_interval: u32,
) {
    let mut queue = FetchQueue::new();
    // TODO: Don't use interval, it can accumulate ticks
    // replace it with delay_until
    let mut interval = time::interval_at(Instant::now(), Duration::from_secs(min_interval as u64));
    tokio::spawn(async move {
        loop {
            select_biased! {
                feed = queue.next().fuse() => {
                    let feed = feed.expect("unreachable");
                    let bot = bot.clone();
                    let db = db.clone();
                    tokio::spawn(async move {
                        if let Err(e) = fetch_and_push_updates(bot, db, feed).await {
                            dbg!(e);
                        }
                    });
                }
                _ = interval.tick().fuse() => {
                    let feeds = db.lock().unwrap().all_feeds();
                    for feed in feeds {
                        let feed_interval = cmp::min(
                            feed.ttl.map(|ttl| ttl * 60).unwrap_or(min_interval),
                            max_interval,
                        ) as u64 - 1; // after -1, we can stagger with `interval`
                        queue.enqueue(feed, Duration::from_secs(feed_interval));
                    }
                }
            }
        }
    });
}

async fn fetch_and_push_updates(
    bot: tbot::Bot<tbot::connectors::Https>,
    db: Arc<Mutex<Database>>,
    feed: Feed,
) -> Result<(), tbot::errors::MethodCall> {
    let new_feed = match pull_feed(&feed.link).await {
        Ok(feed) => feed,
        Err(e) => {
            let down_time = db.lock().unwrap().get_or_update_down_time(&feed.link);
            // 5 days
            if down_time.as_secs() > 5 * 24 * 60 * 60 {
                let msg = format!(
                    "《{}》\
                     已经连续 5 天拉取出错 ({}),\
                     可能已经关闭, 请取消订阅",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&e.to_string())
                );
                push_updates(&bot, &db, feed.subscribers, parameters::Text::html(&msg)).await?;
            }
            return Ok(());
        }
    };

    let updates = db.lock().unwrap().update(&feed.link, new_feed);
    for update in updates {
        match update {
            FeedUpdate::Items(items) => {
                let msgs =
                    format_large_msg(format!("{}", Escape(&feed.title)), &items, |item| {
                        let title = item
                            .title
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.title);
                        let link = item
                            .link
                            .as_ref()
                            .map(|s| s.as_str())
                            .unwrap_or_else(|| &feed.link);
                        format!("{}", Escape(link), Escape(title))
                    });
                for msg in msgs {
                    push_updates(
                        &bot,
                        &db,
                        feed.subscribers.iter().copied(),
                        parameters::Text::html(&msg),
                    )
                    .await?;
                }
            }
            FeedUpdate::Title(new_title) => {
                let msg = format!(
                    "{} 已更名为 {}",
                    Escape(&feed.link),
                    Escape(&feed.title),
                    Escape(&new_title)
                );
                push_updates(
                    &bot,
                    &db,
                    feed.subscribers.iter().copied(),
                    parameters::Text::html(&msg),
                )
                .await?;
            }
        }
    }
    Ok(())
}

async fn push_updates<I: IntoIterator<Item = i64>>(
    bot: &tbot::Bot<Https>,
    db: &Arc<Mutex<Database>>,
    subscribers: I,
    msg: parameters::Text<'_>,
) -> Result<(), tbot::errors::MethodCall> {
    use tbot::errors::MethodCall;
    for mut subscriber in subscribers {
        'retry: for _ in 0..3 {
            match bot
                .send_message(tbot::types::chat::Id(subscriber), msg)
                .call()
                .await
            {
                Err(MethodCall::RequestError { description, .. })
                    if chat_is_unavailable(&description) =>
                {
                    db.lock().unwrap().delete_subscriber(subscriber);
                }
                Err(MethodCall::RequestError {
                    migrate_to_chat_id: Some(new_chat_id),
                    ..
                }) => {
                    db.lock()
                        .unwrap()
                        .update_subscriber(subscriber, new_chat_id.0);
                    subscriber = new_chat_id.0;
                    continue 'retry;
                }
                Err(MethodCall::RequestError {
                    retry_after: Some(delay),
                    ..
                }) => {
                    time::delay_for(Duration::from_secs(delay)).await;
                    continue 'retry;
                }
                other => {
                    other?;
                }
            }
            break 'retry;
        }
    }
    Ok(())
}

pub fn chat_is_unavailable(s: &str) -> bool {
    s.contains("Forbidden") || s.contains("chat not found")
}

#[derive(Default)]
struct FetchQueue {
    feeds: HashMap<String, Feed>,
    notifies: DelayQueue<String>,
    wakeup: Notify,
}

impl FetchQueue {
    fn new() -> Self {
        Self::default()
    }

    fn enqueue(&mut self, feed: Feed, delay: Duration) -> bool {
        let exists = self.feeds.contains_key(&feed.link);
        if !exists {
            self.notifies.insert(feed.link.clone(), delay);
            self.feeds.insert(feed.link.clone(), feed);
            self.wakeup.notify();
        }
        !exists
    }

    async fn next(&mut self) -> Result<Feed, time::Error> {
        loop {
            if let Some(feed_id) = self.notifies.next().await {
                let feed = self.feeds.remove(feed_id?.get_ref()).unwrap();
                break Ok(feed);
            } else {
                self.wakeup.notified().await;
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! ~~~rust
//! extern crate gfx;
//!
//! #[start]
//! fn start(argc: int, argv: **u8) -> int {
//!     native::start(argc, argv, main)
//! }
//!
//! fn main() {
//!     // spawn render task
//!     let (renderer, mut device) = gfx::start(()).unwrap();
//!
//!     // spawn game task
//!     spawn(proc {
//!         let _ = renderer; // do stuff with renderer
//!         loop {}
//!     })
//!
//!     loop {
//!         device.update(); // update device
//!     }
//! }
//! ~~~
//!
//! ~~~
//!     Render Task        |           Main Platform Thread             |         User Task
//!                        |                                            |
//! +----------------+     |                      +----------------+    |
//! |                |<----- device::Reply -------|                |    |
//! | device::Client |     |                      | device::Server |    |
//! |                |------ device::Request ---->|                |    |
//! +----------------+     |                      +----------------+    |
//!                        |                                            |
//!                        |                                            |     +----------------+
//!                        |<------------- render::Request -------------------|                |
//!                        |                                            |     | render::Client |
//!                        |-------------- render::Reply -------------------->|                |
//!                        |                                            |     +----------------+
//!                        |                                            |
//! ~~~

#![crate_id = "github.com/bjz/gfx-rs#gfx:0.1"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate libc;

pub use Renderer = render::Client;
pub use MeshSlice = render::mesh::Slice;
pub use VertexSlice = render::mesh::VertexSlice;
pub use Device = device::Server;
pub use device::InitError;
pub use platform::GraphicsContext;
pub use render::target::ClearData;

pub type Options<'a> = &'a platform::GlProvider;

mod device;
mod render;
pub mod platform;

pub fn start<Api, P: GraphicsContext<Api>>(graphics_context: P, options: Options)
        -> Result<(Renderer, Device<P>), InitError> {
    device::init(graphics_context, options).map(|(server, client)| {
        ((render::start(options, server), client))
    })
}
<commit_msg>expose IndexSlice<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! ~~~rust
//! extern crate gfx;
//!
//! #[start]
//! fn start(argc: int, argv: **u8) -> int {
//!     native::start(argc, argv, main)
//! }
//!
//! fn main() {
//!     // spawn render task
//!     let (renderer, mut device) = gfx::start(()).unwrap();
//!
//!     // spawn game task
//!     spawn(proc {
//!         let _ = renderer; // do stuff with renderer
//!         loop {}
//!     })
//!
//!     loop {
//!         device.update(); // update device
//!     }
//! }
//! ~~~
//!
//! ~~~
//!     Render Task        |           Main Platform Thread             |         User Task
//!                        |                                            |
//! +----------------+     |                      +----------------+    |
//! |                |<----- device::Reply -------|                |    |
//! | device::Client |     |                      | device::Server |    |
//! |                |------ device::Request ---->|                |    |
//! +----------------+     |                      +----------------+    |
//!                        |                                            |
//!                        |                                            |     +----------------+
//!                        |<------------- render::Request -------------------|                |
//!                        |                                            |     | render::Client |
//!                        |-------------- render::Reply -------------------->|                |
//!                        |                                            |     +----------------+
//!                        |                                            |
//! ~~~

#![crate_id = "github.com/bjz/gfx-rs#gfx:0.1"]
#![comment = "A lightweight graphics device manager for Rust"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]
#[phase(plugin, link)] extern crate log;
extern crate libc;

pub use Renderer = render::Client;
pub use MeshSlice = render::mesh::Slice;
pub use VertexSlice = render::mesh::VertexSlice;
pub use IndexSlice = render::mesh::IndexSlice;
pub use Device = device::Server;
pub use device::InitError;
pub use platform::GraphicsContext;
pub use render::target::ClearData;

pub type Options<'a> = &'a platform::GlProvider;

mod device;
mod render;
pub mod platform;

pub fn start<Api, P: GraphicsContext<Api>>(graphics_context: P, options: Options)
        -> Result<(Renderer, Device<P>), InitError> {
    device::init(graphics_context, options).map(|(server, client)| {
        ((render::start(options, server), client))
    })
}
<|endoftext|>


<commit_before>extern crate gj;
extern crate gjio;
extern crate crexp_client_proto;
extern crate spki_sexp as sexp;
extern crate serde;
#[macro_use]
extern crate quick_error;

use gj::{EventLoop, Promise};
use gjio::{AsyncRead, AsyncWrite, BufferPrefix, SocketStream, EventPort};
use std::net::SocketAddr;
use std::io;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::fmt;

use serde::{ser,de};

use crexp_client_proto::messages::{ClientReq,ClientResp};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            from()
            description(err.description())
            cause(err)
        }
        Sexp(err: sexp::Error) {
            from()
            description(err.description())
            cause(err)
        }
    }
}

struct SexpChannel<S, R> {
    stream: Rc<RefCell<SocketStream>>,
    packets: Rc<RefCell<sexp::Packetiser>>,
    _send: PhantomData<S>,
    _recv: PhantomData<R>,
}

impl<S: ser::Serialize + 'static + fmt::Debug, R: de::Deserialize + 'static + fmt::Debug> SexpChannel<S, R> {
    fn new(stream: SocketStream) -> SexpChannel<S, R> {
        SexpChannel {
            stream: Rc::new(RefCell::new(stream)),
            packets: Rc::new(RefCell::new(sexp::Packetiser::new())),
            _send: PhantomData, _recv: PhantomData,
        }
    }

    fn send(&self, data: S) -> Promise<(), Error> {
        let stream = self.stream.clone();
        Promise::ok(data)
            .map(move |req| Ok(try!(sexp::as_bytes(&req))))
            .then(move |bytes| {
                let mut borr = stream.borrow_mut();
                borr.write(bytes).map(|_| Ok(())).map_err(From::from)
            })
    }
    fn read_a_packet(stream: Rc<RefCell<SocketStream>>, packets: Rc<RefCell<sexp::Packetiser>>) -> Promise<R, Error> {
        println!("Read a packet: {:?}", packets);
        let buf = vec![0; 11];
        let read = {
            let mut borrowed = stream.borrow_mut();
            borrowed.try_read(buf, 1)
        };
        read.map_err(From::from)
            .then(move |(buf, nbytes)| {
                println!("Read bytes: {:?}", &buf[..nbytes]);
                if nbytes == 0 {
                    return Promise::err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF").into())
                }
                let read = {
                    let mut borrowed = packets.borrow_mut();
                    borrowed.feed(&buf[..nbytes]);
                    borrowed.take()
                };
                println!("Take a packet: {:?}", read);
                match read {
                    Ok(Some(p)) => Promise::ok(p),
                    Ok(None) => Self::read_a_packet(stream, packets),
                    Err(e) => Promise::err(e.into()),
                }
            })
    }
    fn recv(&self) -> Promise<R, Error> {
        let stream = self.stream.clone();
        let packets = self.packets.clone();
        Promise::ok(())
            .then(move |()| {
                Self::read_a_packet(stream, packets)
            })
    }
}

pub struct Producer {
    chan: Rc<RefCell<SexpChannel<ClientReq, ClientResp>>>,
}

impl Producer {
    pub fn new(host: SocketAddr, event_port: &mut EventPort) -> Promise<Producer, Error> {
        let network = event_port.get_network();
        let mut address = network.get_tcp_address(host);
        address.connect().map(move |mut stream|
            Ok(Producer {
                chan: Rc::new(RefCell::new(SexpChannel::new(stream))),
            })
        ).map_err(From::from)
    }

    pub fn publish(&mut self, data: &str) -> Promise<(), Error> {
        let chan = self.chan.clone();
        Promise::ok(ClientReq::Publish(data.as_bytes().to_vec().into()))
            .then(move |req| {
                    let p = {
                        let mut borr = chan.borrow_mut();
                        borr.send(req).map_err(From::from)
                    };
                    p.map(|()| Ok(chan))
                })
            .then(move |chan| {
                let mut borr = chan.borrow_mut();
                borr.recv()
            }).then(move |val| {
                println!("Write returned {:?}", val);
                Promise::ok(())
            })
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn it_works() {
    }
}
<commit_msg>Yield seqno on produce.<commit_after>extern crate gj;
extern crate gjio;
extern crate crexp_client_proto;
extern crate spki_sexp as sexp;
extern crate serde;
#[macro_use]
extern crate quick_error;

use gj::{EventLoop, Promise};
use gjio::{AsyncRead, AsyncWrite, BufferPrefix, SocketStream, EventPort};
use std::net::SocketAddr;
use std::io;
use std::io::Write;
use std::rc::Rc;
use std::cell::RefCell;
use std::marker::PhantomData;
use std::fmt;

use serde::{ser,de};

use crexp_client_proto::messages::{ClientReq,ClientResp, Seqno};

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: io::Error) {
            from()
            description(err.description())
            cause(err)
        }
        Sexp(err: sexp::Error) {
            from()
            description(err.description())
            cause(err)
        }
        Server(seq: Seqno, desc: String) {
            description("server error")
        }

    }
}

struct SexpChannel<S, R> {
    stream: Rc<RefCell<SocketStream>>,
    packets: Rc<RefCell<sexp::Packetiser>>,
    _send: PhantomData<S>,
    _recv: PhantomData<R>,
}

impl<S: ser::Serialize + 'static + fmt::Debug, R: de::Deserialize + 'static + fmt::Debug> SexpChannel<S, R> {
    fn new(stream: SocketStream) -> SexpChannel<S, R> {
        SexpChannel {
            stream: Rc::new(RefCell::new(stream)),
            packets: Rc::new(RefCell::new(sexp::Packetiser::new())),
            _send: PhantomData, _recv: PhantomData,
        }
    }

    fn send(&self, data: S) -> Promise<(), Error> {
        let stream = self.stream.clone();
        Promise::ok(data)
            .map(move |req| Ok(try!(sexp::as_bytes(&req))))
            .then(move |bytes| {
                let mut borr = stream.borrow_mut();
                borr.write(bytes).map(|_| Ok(())).map_err(From::from)
            })
    }
    fn read_a_packet(stream: Rc<RefCell<SocketStream>>, packets: Rc<RefCell<sexp::Packetiser>>) -> Promise<R, Error> {
        println!("Read a packet: {:?}", packets);
        let buf = vec![0; 11];
        let read = {
            let mut borrowed = stream.borrow_mut();
            borrowed.try_read(buf, 1)
        };
        read.map_err(From::from)
            .then(move |(buf, nbytes)| {
                println!("Read bytes: {:?}", &buf[..nbytes]);
                if nbytes == 0 {
                    return Promise::err(io::Error::new(io::ErrorKind::UnexpectedEof, "EOF").into())
                }
                let read = {
                    let mut borrowed = packets.borrow_mut();
                    borrowed.feed(&buf[..nbytes]);
                    borrowed.take()
                };
                println!("Take a packet: {:?}", read);
                match read {
                    Ok(Some(p)) => Promise::ok(p),
                    Ok(None) => Self::read_a_packet(stream, packets),
                    Err(e) => Promise::err(e.into()),
                }
            })
    }
    fn recv(&self) -> Promise<R, Error> {
        let stream = self.stream.clone();
        let packets = self.packets.clone();
        Promise::ok(())
            .then(move |()| {
                Self::read_a_packet(stream, packets)
            })
    }
}

pub struct Producer {
    chan: Rc<RefCell<SexpChannel<ClientReq, ClientResp>>>,
}

impl Producer {
    pub fn new(host: SocketAddr, event_port: &mut EventPort) -> Promise<Producer, Error> {
        let network = event_port.get_network();
        let mut address = network.get_tcp_address(host);
        address.connect().map(move |mut stream|
            Ok(Producer {
                chan: Rc::new(RefCell::new(SexpChannel::new(stream))),
            })
        ).map_err(From::from)
    }

    pub fn publish(&mut self, data: &str) -> Promise<Seqno, Error> {
        let chan = self.chan.clone();
        Promise::ok(ClientReq::Publish(data.as_bytes().to_vec().into()))
            .then(move |req| {
                    let p = {
                        let mut borr = chan.borrow_mut();
                        borr.send(req).map_err(From::from)
                    };
                    p.map(|()| Ok(chan))
                })
            .then(move |chan| {
                let mut borr = chan.borrow_mut();
                borr.recv()
            }).map(move |val| {
                match val {
                    ClientResp::Ok(seq, _) => Ok(seq),
                    ClientResp::Err(seq, msg) => Err(Error::Server(seq, msg)),
                }
            })
    }
}

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