<commit_before>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    fn parse_parenthetical<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::RightParen => {
                    return Ok(Expression::List(list))
                },
                Token::LeftParen => {
                    list.push(
                        try!(Expression::parse_parenthetical(tokenizer))
                    );
                },
                Token::Number(_, _) => {
                    list.push(
                        Expression::Number(NumberValue::from_scalar(lexeme))
                    );
                },
                Token::Plus | Token::Minus | Token::Star |
                              Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                Token::Comment(_) => {},
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected right paren while parsing a value expression; reached EOF instead."
            ),
        })
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::LeftParen => {
                    list.push(
                        try!(Expression::parse_parenthetical(tokenizer))
                    );
                },
                Token::Number(_, _) => {
                    list.push(
                        Expression::Number(NumberValue::from_scalar(lexeme))
                    );
                },
                Token::Plus | Token::Minus | Token::Star |
                              Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                Token::Comment(_) => {},
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(self, context: &Context, force_slash: bool) -> Expression {
        if let Expression::List(exprs) = self {
            let mut last_was_an_operator = true;
            // TODO: I'd love to have more types here, to ensure only values are
            // on the value stack and only operators are on the operator stack...
            let mut value_stack: Vec<Expression> = Vec::new();
            let mut op_stack: Vec<Expression> = Vec::new();

            // Split into value stacks and operator stacks

            let mut exprs = exprs.into_iter();
            while let Some(part) = exprs.next() {
                debug!("Processing list item {:#?}", part);
                match part {
                    Expression::Number(nv) => {
                        if last_was_an_operator {
                            debug!("Push on value stack {:#?}", nv);
                            value_stack.push(Expression::Number(nv));
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                Expression::Number(nv),
                            );
                            debug!("Push on list on value stack {:#?}", list);
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::Operator(ref op) if op.token == Token::Slash && !force_slash => {
                        let list = create_list(
                            value_stack.pop(),
                            Expression::Operator(op.clone()),
                        );
                        debug!("Push on list on value stack {:#?}", list);
                        value_stack.push(list);

                    },
                    Expression::Operator(op) => {
                        debug!("Push on op stack {:#?}", op);
                        op_stack.push(Expression::Operator(op));
                        last_was_an_operator = true;
                    },
                    Expression::String(lex) => {
                        let var_eval = context.get_variable(&lex)
                                        .unwrap_or(Expression::String(lex));

                        if last_was_an_operator {
                            value_stack.push(var_eval);
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                var_eval,
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::List(list) => {
                        debug!("Push list on value stack {:#?}", list);
                        value_stack.push(Expression::List(list));
                        last_was_an_operator = false;
                    },
                }
            }

            // Process the stacks
            while !op_stack.is_empty() {
                let op = op_stack.pop().unwrap();
                let second = value_stack.pop().expect("Expected a second argument on the value stack");
                let first = value_stack.pop().expect("Expected a first argument on the value stack");

                let math_result = first.apply_math(op, second, context, force_slash);
                debug!("Math result: {:#?}", math_result);

                value_stack.push(math_result);
            }

            value_stack.pop().unwrap()
        } else {
            self
        }
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                Expression::List(exprs).evaluate_list(context, false)
            },
        }
    }

    fn apply_math(self, operator: Expression, second: Expression, context: &Context, force_slash: bool) -> Expression {
        debug!("Applying math to:\nfirst: {:#?}\nop: {:#?}\nsecond: {:#?}", self, operator, second);
        match (self.clone(), second.clone()) {
            (Expression::Number(f), Expression::Number(s)) => {
                match operator {
                    Expression::Operator(ref o) if o.token == Token::Slash => {
                        if force_slash || (f.computed || s.computed) {
                            let result = f.apply_math(&o, &s);
                            Expression::Number(result)
                        } else {
                            Expression::List(vec![self, operator.clone(), second.clone()])
                        }
                    },
                    Expression::Operator(o) => {
                        let result = f.apply_math(&o, &s);
                        Expression::Number(result)
                    },
                    _ => unreachable!(),
                }
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                let eval_second = Expression::List(s).evaluate_list(context, true);
                eval_first.apply_math(operator, eval_second, context, true)
            },
            (Expression::List(f), Expression::Number(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                eval_first.apply_math(operator, Expression::Number(s), context, true)
            },
            (Expression::Number(f), Expression::List(s)) => {
                let eval_second = Expression::List(s).evaluate_list(context, true);
                Expression::Number(f).apply_math(operator, eval_second, context, true)
            },
            _ => unimplemented!(),
        }
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
            Expression::Operator(plus()),
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<commit_msg>Yuck yuck yuck. More jacked up list math works tho<commit_after>use sass::output_style::SassOutputStyle;
use token::{Lexeme, Token};
use ast::number_value::NumberValue;
use context::Context;
use error::{Result, SassError, ErrorKind};

#[derive(Debug, Clone, PartialEq)]
pub enum Expression {
    List(Vec<Expression>),
    Number(NumberValue),
    Operator(Lexeme),
    String(Lexeme),
}

impl Expression {
    #[allow(unused_variables)]
    pub fn to_string(&self, style: SassOutputStyle) -> String {
        match *self {
            Expression::List(ref elements) => {
                elements.iter().map(|e|
                    e.to_string(style)
                ).collect::<Vec<_>>().join(" ")
            },
            Expression::Number(ref nv) => nv.to_string(),
            Expression::Operator(ref lex) => lex.token.to_string(),
            Expression::String(ref lex) => lex.token.to_string(),
        }
    }

    fn parse_parenthetical<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::RightParen => {
                    return Ok(Expression::List(list))
                },
                Token::LeftParen => {
                    list.push(
                        try!(Expression::parse_parenthetical(tokenizer))
                    );
                },
                Token::Number(_, _) => {
                    list.push(
                        Expression::Number(NumberValue::from_scalar(lexeme))
                    );
                },
                Token::Plus | Token::Minus | Token::Star |
                              Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                Token::Comment(_) => {},
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected right paren while parsing a value expression; reached EOF instead."
            ),
        })
    }

    pub fn parse<T: Iterator<Item = Result<Lexeme>>>(tokenizer: &mut T) -> Result<Expression> {
        let mut list = vec![];
        while let Some(Ok(lexeme)) = tokenizer.next() {
            match lexeme.token {
                Token::Semicolon => {
                    if list.len() == 1 {
                        return Ok(list.pop().unwrap())
                    } else {
                        return Ok(Expression::List(list))
                    }
                },
                Token::LeftParen => {
                    list.push(
                        try!(Expression::parse_parenthetical(tokenizer))
                    );
                },
                Token::Number(_, _) => {
                    list.push(
                        Expression::Number(NumberValue::from_scalar(lexeme))
                    );
                },
                Token::Plus | Token::Minus | Token::Star |
                              Token::Slash | Token::Percent => {
                    list.push(Expression::Operator(lexeme));
                },
                Token::Comment(_) => {},
                _ => {
                    list.push(Expression::String(lexeme));
                }
            }
        }

        let error_offset = match list.pop() {
            Some(Expression::String(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Operator(lexeme)) => lexeme.offset.unwrap_or(0),
            Some(Expression::Number(nv)) => nv.offset().unwrap_or(0),
            Some(Expression::List(_)) => unreachable!(), // for now until nested lists
            None => 0,
        };
        Err(SassError {
            offset: error_offset,
            kind: ErrorKind::UnexpectedEof,
            message: String::from(
                "Expected semicolon while parsing a value expression; reached EOF instead."
            ),
        })
    }

    fn evaluate_list(self, context: &Context, force_slash: bool) -> Expression {
        if let Expression::List(exprs) = self {
            let mut last_was_an_operator = true;
            // TODO: I'd love to have more types here, to ensure only values are
            // on the value stack and only operators are on the operator stack...
            let mut value_stack: Vec<Expression> = Vec::new();
            let mut op_stack: Vec<Expression> = Vec::new();

            // Split into value stacks and operator stacks

            let mut exprs = exprs.into_iter();
            while let Some(part) = exprs.next() {
                debug!("Processing list item {:#?}", part);
                match part {
                    Expression::Number(nv) => {
                        if last_was_an_operator {
                            debug!("Push on value stack {:#?}", nv);
                            value_stack.push(Expression::Number(nv));
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                Expression::Number(nv),
                            );
                            debug!("Push on list on value stack {:#?}", list);
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::Operator(ref op) if op.token == Token::Slash && !force_slash => {
                        let list = create_list(
                            value_stack.pop(),
                            Expression::Operator(op.clone()),
                        );
                        debug!("Push on list on value stack {:#?}", list);
                        value_stack.push(list);

                    },
                    Expression::Operator(op) => {
                        debug!("Push on op stack {:#?}", op);
                        op_stack.push(Expression::Operator(op));
                        last_was_an_operator = true;
                    },
                    Expression::String(lex) => {
                        let var_eval = context.get_variable(&lex)
                                        .unwrap_or(Expression::String(lex));

                        if last_was_an_operator {
                            value_stack.push(var_eval);
                        } else {
                            let list = create_list(
                                value_stack.pop(),
                                var_eval,
                            );
                            value_stack.push(list);
                        }
                        last_was_an_operator = false;
                    },
                    Expression::List(list) => {
                        debug!("Push list on value stack {:#?}", list);
                        value_stack.push(Expression::List(list));
                        last_was_an_operator = false;
                    },
                }
            }

            // Process the stacks
            while !op_stack.is_empty() {
                let op = op_stack.pop().unwrap();
                let second = value_stack.pop().expect("Expected a second argument on the value stack");
                let first = value_stack.pop().expect("Expected a first argument on the value stack");

                let math_result = first.apply_math(op, second, context, force_slash);
                debug!("Math result: {:#?}", math_result);

                value_stack.push(math_result);
            }

            value_stack.pop().unwrap()
        } else {
            self
        }
    }

    pub fn evaluate(self, context: &Context) -> Expression {
        match self {
            Expression::Number(nv) => Expression::Number(nv),
            Expression::Operator(op) => Expression::Operator(op),
            Expression::String(lex) => {
                context.get_variable(&lex).unwrap_or(Expression::String(lex))
            },
            Expression::List(exprs) => {
                Expression::List(exprs).evaluate_list(context, false)
            },
        }
    }

    fn is_slash(&self) -> bool {
        match self {
            &Expression::Operator(ref o) if o.token == Token::Slash => true,
            _ => false,
        }
    }

    fn is_plus(&self) -> bool {
        match self {
            &Expression::Operator(ref o) if o.token == Token::Plus => true,
            _ => false,
        }
    }

    fn apply_math(self, operator: Expression, second: Expression, context: &Context, force_slash: bool) -> Expression {
        debug!("Applying math to:\nfirst: {:#?}\nop: {:#?}\nsecond: {:#?}", self, operator, second);
        match (self.clone(), second.clone()) {
            (Expression::Number(f), Expression::Number(s)) => {
                match operator {
                    Expression::Operator(ref o) if o.token == Token::Slash => {
                        if force_slash || (f.computed || s.computed) {
                            let result = f.apply_math(&o, &s);
                            Expression::Number(result)
                        } else {
                            Expression::List(vec![self, operator.clone(), second.clone()])
                        }
                    },
                    Expression::Operator(o) => {
                        let result = f.apply_math(&o, &s);
                        Expression::Number(result)
                    },
                    _ => unreachable!(),
                }
            },
            (Expression::List(f), Expression::List(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                let eval_second = Expression::List(s).evaluate_list(context, true);
                eval_first.apply_math(operator, eval_second, context, true)
            },
            (Expression::List(f), Expression::Number(s)) => {
                let eval_first = Expression::List(f).evaluate_list(context, true);
                eval_first.apply_math(operator, Expression::Number(s), context, true)
            },
            (Expression::Number(f), Expression::List(s)) => {
                if s.iter().any(|e| e.is_slash()) {
                    let evaled_list = Expression::List(s).evaluate_list(context, true);
                    Expression::Number(f).apply_math(
                        operator,
                        evaled_list,
                        context,
                        true
                    )
                } else {
                    if let Some((ref first_in_list, rest_of_list)) =
                            s.split_first() {
                        let new_first = if operator.is_plus() {
                            Expression::String(
                                Lexeme {
                                    token: Token::String(
                                        format!("{}{}", f, first_in_list.to_string(SassOutputStyle::Expanded))
                                    ),
                                    offset: f.offset(),
                                }
                            )
                        } else {
                            Expression::Number(f).apply_math(
                                operator,
                                (*first_in_list).clone(),
                                context,
                                true
                            )
                        };

                        let mut new_list = vec![new_first];
                        new_list.extend_from_slice(rest_of_list);
                        Expression::List(new_list)
                    } else {
                        panic!("Trying to perform an operation on a number and a list; expected to get a list with something in it");
                    }
                }
            },
            _ => unimplemented!(),
        }
    }
}

fn create_list(head: Option<Expression>, tail: Expression) -> Expression {
    let mut list = match head {
        Some(Expression::List(v)) => v,
        Some(e) => vec![e],
        None => vec![],
    };
    list.push(tail);
    Expression::List(list)
}

#[cfg(test)]
mod tests {
    use super::*;
    use token::{Lexeme, Token};
    use ast::number_value::NumberValue;
    use context::Context;

    fn semicolon() -> Lexeme {
        Lexeme { token: Token::Semicolon, offset: None }
    }

    fn blue() -> Lexeme {
        Lexeme { token: Token::String("blue".into()), offset: None }
    }

    fn plus() -> Lexeme {
        Lexeme { token: Token::Plus, offset: None }
    }

    fn slash() -> Lexeme {
        Lexeme { token: Token::Slash, offset: None }
    }

    fn one() -> Lexeme {
        Lexeme { token: Token::Number(1.0, None), offset: None }
    }

    fn two() -> Lexeme {
        Lexeme { token: Token::Number(2.0, None), offset: None }
    }

    fn one_px() -> Lexeme {
        Lexeme { token: Token::Number(1.0, Some("px".into())), offset: None }
    }

    #[test]
    fn it_parses_a_single_string() {
        let mut fake_tokenizer = vec![Ok(blue()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::String(blue()))
        );
    }

    #[test]
    fn it_parses_a_list() {
        let mut fake_tokenizer = vec![
            Ok(one()),
            Ok(plus()),
            Ok(one()),
            Ok(semicolon())
        ].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::List(vec![
                Expression::Number(NumberValue::from_scalar(one())),
                Expression::Operator(plus()),
                Expression::Number(NumberValue::from_scalar(one())),
            ]))
        );
    }

    #[test]
    fn it_parses_a_number_without_units() {
        let mut fake_tokenizer = vec![Ok(one()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one())))
        );
    }

    #[test]
    fn it_parses_a_number_with_units() {
        let mut fake_tokenizer = vec![Ok(one_px()), Ok(semicolon())].into_iter();
        assert_eq!(
            Expression::parse(&mut fake_tokenizer),
            Ok(Expression::Number(NumberValue::from_scalar(one_px())))
        );
    }

    #[test]
    fn it_evaluates_a_list() {
        let ex = Expression::List(vec![
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
            Expression::Operator(plus()),
            Expression::Number(NumberValue::from_scalar(one())),
            Expression::Operator(slash()),
            Expression::Number(NumberValue::from_scalar(two())),
        ]);
        let fake_context = Context::new();
        assert_eq!(
            ex.evaluate(&fake_context),
            Expression::Number(NumberValue { scalar: one(), computed: true })
        );
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::collections::VecDeque;
use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::time::Duration;

use futures::Stream;

use telegram_bot_raw::{AllowedUpdate, GetUpdates, Integer, Update};

use crate::api::Api;
use crate::errors::Error;

const TELEGRAM_LONG_POLL_TIMEOUT_SECONDS: u64 = 5;
const TELEGRAM_LONG_POLL_LIMIT_MESSAGES: Integer = 100;
const TELEGRAM_LONG_POLL_ERROR_DELAY_MILLISECONDS: u64 = 500;

/// This type represents stream of Telegram API updates and uses
/// long polling method under the hood.
#[must_use = "streams do nothing unless polled"]
pub struct UpdatesStream {
    api: Api,
    last_update: Integer,
    buffer: VecDeque<Update>,
    current_request: Option<Pin<Box<dyn Future<Output = Result<Option<Vec<Update>>, Error>>>>>,
    timeout: Duration,
    allowed_updates: Vec<AllowedUpdate>,
    limit: Integer,
    error_delay: Duration,
    next_poll_id: usize,
}

impl Stream for UpdatesStream {
    type Item = Result<Update, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        let ref_mut = self.get_mut();
        let poll_id = ref_mut.next_poll_id;
        ref_mut.next_poll_id += 1;
        let span = tracing::trace_span!("stream", poll_id = poll_id);
        let _enter = span.enter();

        tracing::trace!("start stream polling");

        if let Some(value) = ref_mut.buffer.pop_front() {
            tracing::trace!(update = ?value, "returning buffered update");
            return Poll::Ready(Some(Ok(value)));
        }
        tracing::trace!("processing request");

        let result = match ref_mut.current_request {
            None => {
                tracing::trace!("there is no current request");
                Ok(false)
            }
            Some(ref mut current_request) => {
                let cc = current_request.as_mut();
                let polled_update = cc.poll(cx);
                match polled_update {
                    Poll::Pending => {
                        tracing::trace!("request is pending");
                        return Poll::Pending;
                    }
                    Poll::Ready(Ok(None)) => {
                        tracing::trace!("request timed out");
                        Ok(false)
                    }
                    Poll::Ready(Ok(Some(ref updates))) if updates.is_empty() => {
                        tracing::trace!("request resolved to empty update list");
                        Ok(false)
                    }
                    Poll::Ready(Ok(Some(updates))) => {
                        for update in updates {
                            tracing::trace!(update = ?update, "processing update");
                            ref_mut.last_update = max(update.id, ref_mut.last_update);
                            tracing::trace!(last_update = ref_mut.last_update);
                            ref_mut.buffer.push_back(update)
                        }

                        Ok(true)
                    }
                    Poll::Ready(Err(err)) => {
                        tracing::error!(error = %err, "request error");
                        Err(err)
                    }
                }
            }
        };

        match result {
            Err(err) => {
                let timeout = ref_mut.timeout + Duration::from_secs(1);
                let mut get_updates = GetUpdates::new();
                get_updates
                    .offset(ref_mut.last_update + 1)
                    .timeout(ref_mut.error_delay.as_secs() as Integer)
                    .limit(ref_mut.limit)
                    .allowed_updates(&ref_mut.allowed_updates);
                tracing::trace!(request = ?get_updates, timeout=?timeout, "preparing new request");

                let request = ref_mut.api.send_timeout(get_updates, timeout);
                ref_mut.current_request = Some(Box::pin(request));
                return Poll::Ready(Some(Err(err)));
            }
            Ok(false) => {
                let timeout = ref_mut.timeout + Duration::from_secs(1);
                let mut get_updates = GetUpdates::new();
                get_updates
                    .offset(ref_mut.last_update + 1)
                    .timeout(ref_mut.error_delay.as_secs() as Integer)
                    .limit(ref_mut.limit)
                    .allowed_updates(&ref_mut.allowed_updates);
                tracing::trace!(request = ?get_updates, timeout=?timeout, "preparing new request");

                let request = ref_mut.api.send_timeout(get_updates, timeout);
                ref_mut.current_request = Some(Box::pin(request));

                tracing::trace!("executing recursive call");
                Pin::new(ref_mut).poll_next(cx)
            }
            Ok(true) => {
                tracing::trace!("dropping request");
                ref_mut.current_request = None;
                tracing::trace!("executing recursive call");
                Pin::new(ref_mut).poll_next(cx)
            }
        }
    }
}

impl UpdatesStream {
    ///  create a new `UpdatesStream` instance.
    pub fn new(api: &Api) -> Self {
        UpdatesStream {
            api: api.clone(),
            last_update: 0,
            buffer: VecDeque::new(),
            current_request: None,
            timeout: Duration::from_secs(TELEGRAM_LONG_POLL_TIMEOUT_SECONDS),
            allowed_updates: Vec::new(),
            limit: TELEGRAM_LONG_POLL_LIMIT_MESSAGES,
            error_delay: Duration::from_millis(TELEGRAM_LONG_POLL_ERROR_DELAY_MILLISECONDS),
            next_poll_id: 0,
        }
    }

    /// Set timeout for long polling requests, this corresponds with `timeout` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method,
    /// also this stream sets an additional request timeout for `timeout + 1 second`
    /// in case of invalid Telegram API server behaviour.
    ///
    /// Default timeout is 5 seconds.
    pub fn timeout(&mut self, timeout: Duration) -> &mut Self {
        self.timeout = timeout;
        self
    }

    /// Set allowed updates to receive, this corresponds with `allowed_updates` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method.
    /// List the types of updates you want your bot to receive. For example,
    /// specify [“message”, “edited_channel_post”, “callback_query”] to only receive updates of these types.
    /// See Update for a complete list of available update types. Specify an empty list to receive all
    /// updates regardless of type (default). If not specified, the previous setting will be used.
    ///
    /// Please note that this parameter doesn't affect updates created before the call to the getUpdates,
    /// so unwanted updates may be received for a short period of time.
    pub fn allowed_updates(&mut self, allowed_updates: &[AllowedUpdate]) -> &mut Self {
        self.allowed_updates = allowed_updates.to_vec();
        self
    }

    /// Set limits the number of updates to be retrieved, this corresponds with `limit` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method.
    /// Values between 1—100 are accepted.
    ///
    /// Defaults to 100.
    pub fn limit(&mut self, limit: Integer) -> &mut Self {
        self.limit = limit;
        self
    }

    /// Set a delay between erroneous request and next request.
    /// This delay prevents busy looping in some cases.
    ///
    /// Default delay is 500 ms.
    pub fn error_delay(&mut self, delay: Duration) -> &mut Self {
        self.error_delay = delay;
        self
    }
}
<commit_msg>Make UpdatesStream Send<commit_after>use std::cmp::max;
use std::collections::VecDeque;
use std::future::Future;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use std::time::Duration;

use futures::Stream;

use telegram_bot_raw::{AllowedUpdate, GetUpdates, Integer, Update};

use crate::api::Api;
use crate::errors::Error;

const TELEGRAM_LONG_POLL_TIMEOUT_SECONDS: u64 = 5;
const TELEGRAM_LONG_POLL_LIMIT_MESSAGES: Integer = 100;
const TELEGRAM_LONG_POLL_ERROR_DELAY_MILLISECONDS: u64 = 500;

/// This type represents stream of Telegram API updates and uses
/// long polling method under the hood.
#[must_use = "streams do nothing unless polled"]
pub struct UpdatesStream {
    api: Api,
    last_update: Integer,
    buffer: VecDeque<Update>,
    current_request:
        Option<Pin<Box<dyn Future<Output = Result<Option<Vec<Update>>, Error>> + Send>>>,
    timeout: Duration,
    allowed_updates: Vec<AllowedUpdate>,
    limit: Integer,
    error_delay: Duration,
    next_poll_id: usize,
}

impl Stream for UpdatesStream {
    type Item = Result<Update, Error>;

    fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        let ref_mut = self.get_mut();
        let poll_id = ref_mut.next_poll_id;
        ref_mut.next_poll_id += 1;
        let span = tracing::trace_span!("stream", poll_id = poll_id);
        let _enter = span.enter();

        tracing::trace!("start stream polling");

        if let Some(value) = ref_mut.buffer.pop_front() {
            tracing::trace!(update = ?value, "returning buffered update");
            return Poll::Ready(Some(Ok(value)));
        }
        tracing::trace!("processing request");

        let result = match ref_mut.current_request {
            None => {
                tracing::trace!("there is no current request");
                Ok(false)
            }
            Some(ref mut current_request) => {
                let cc = current_request.as_mut();
                let polled_update = cc.poll(cx);
                match polled_update {
                    Poll::Pending => {
                        tracing::trace!("request is pending");
                        return Poll::Pending;
                    }
                    Poll::Ready(Ok(None)) => {
                        tracing::trace!("request timed out");
                        Ok(false)
                    }
                    Poll::Ready(Ok(Some(ref updates))) if updates.is_empty() => {
                        tracing::trace!("request resolved to empty update list");
                        Ok(false)
                    }
                    Poll::Ready(Ok(Some(updates))) => {
                        for update in updates {
                            tracing::trace!(update = ?update, "processing update");
                            ref_mut.last_update = max(update.id, ref_mut.last_update);
                            tracing::trace!(last_update = ref_mut.last_update);
                            ref_mut.buffer.push_back(update)
                        }

                        Ok(true)
                    }
                    Poll::Ready(Err(err)) => {
                        tracing::error!(error = %err, "request error");
                        Err(err)
                    }
                }
            }
        };

        match result {
            Err(err) => {
                let timeout = ref_mut.timeout + Duration::from_secs(1);
                let mut get_updates = GetUpdates::new();
                get_updates
                    .offset(ref_mut.last_update + 1)
                    .timeout(ref_mut.error_delay.as_secs() as Integer)
                    .limit(ref_mut.limit)
                    .allowed_updates(&ref_mut.allowed_updates);
                tracing::trace!(request = ?get_updates, timeout=?timeout, "preparing new request");

                let request = ref_mut.api.send_timeout(get_updates, timeout);
                ref_mut.current_request = Some(Box::pin(request));
                return Poll::Ready(Some(Err(err)));
            }
            Ok(false) => {
                let timeout = ref_mut.timeout + Duration::from_secs(1);
                let mut get_updates = GetUpdates::new();
                get_updates
                    .offset(ref_mut.last_update + 1)
                    .timeout(ref_mut.error_delay.as_secs() as Integer)
                    .limit(ref_mut.limit)
                    .allowed_updates(&ref_mut.allowed_updates);
                tracing::trace!(request = ?get_updates, timeout=?timeout, "preparing new request");

                let request = ref_mut.api.send_timeout(get_updates, timeout);
                ref_mut.current_request = Some(Box::pin(request));

                tracing::trace!("executing recursive call");
                Pin::new(ref_mut).poll_next(cx)
            }
            Ok(true) => {
                tracing::trace!("dropping request");
                ref_mut.current_request = None;
                tracing::trace!("executing recursive call");
                Pin::new(ref_mut).poll_next(cx)
            }
        }
    }
}

impl UpdatesStream {
    ///  create a new `UpdatesStream` instance.
    pub fn new(api: &Api) -> Self {
        UpdatesStream {
            api: api.clone(),
            last_update: 0,
            buffer: VecDeque::new(),
            current_request: None,
            timeout: Duration::from_secs(TELEGRAM_LONG_POLL_TIMEOUT_SECONDS),
            allowed_updates: Vec::new(),
            limit: TELEGRAM_LONG_POLL_LIMIT_MESSAGES,
            error_delay: Duration::from_millis(TELEGRAM_LONG_POLL_ERROR_DELAY_MILLISECONDS),
            next_poll_id: 0,
        }
    }

    /// Set timeout for long polling requests, this corresponds with `timeout` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method,
    /// also this stream sets an additional request timeout for `timeout + 1 second`
    /// in case of invalid Telegram API server behaviour.
    ///
    /// Default timeout is 5 seconds.
    pub fn timeout(&mut self, timeout: Duration) -> &mut Self {
        self.timeout = timeout;
        self
    }

    /// Set allowed updates to receive, this corresponds with `allowed_updates` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method.
    /// List the types of updates you want your bot to receive. For example,
    /// specify [“message”, “edited_channel_post”, “callback_query”] to only receive updates of these types.
    /// See Update for a complete list of available update types. Specify an empty list to receive all
    /// updates regardless of type (default). If not specified, the previous setting will be used.
    ///
    /// Please note that this parameter doesn't affect updates created before the call to the getUpdates,
    /// so unwanted updates may be received for a short period of time.
    pub fn allowed_updates(&mut self, allowed_updates: &[AllowedUpdate]) -> &mut Self {
        self.allowed_updates = allowed_updates.to_vec();
        self
    }

    /// Set limits the number of updates to be retrieved, this corresponds with `limit` field
    /// in [getUpdates](https://core.telegram.org/bots/api#getupdates) method.
    /// Values between 1—100 are accepted.
    ///
    /// Defaults to 100.
    pub fn limit(&mut self, limit: Integer) -> &mut Self {
        self.limit = limit;
        self
    }

    /// Set a delay between erroneous request and next request.
    /// This delay prevents busy looping in some cases.
    ///
    /// Default delay is 500 ms.
    pub fn error_delay(&mut self, delay: Duration) -> &mut Self {
        self.error_delay = delay;
        self
    }
}
<|endoftext|>


<commit_before>#[cfg(test)]use error::*;
#[cfg(test)]use engine;
#[cfg(test)]use engine::*;
#[cfg(test)]use il;
#[cfg(test)]use loader;
#[cfg(test)]use loader::Loader;
#[cfg(test)]use platform::*;
#[cfg(test)]use std::path::Path;
#[cfg(test)]use std::rc::Rc;

#[cfg(test)]
fn simple_0_test () -> Result<Vec<u8>> {
    // let filename = Path::new("test_binaries/Palindrome/Palindrome.json");
    // let elf = ::falcon::loader::json::Json::from_file(filename)?;
    let filename = Path::new("test_binaries/simple-0/simple-0");
    let elf = loader::elf::ElfLinker::new(filename)?;
    // let mut elf = ::falcon::loader::elf::Elf::from_file(filename)?;

    let mut program = il::Program::new();
    program.add_function(elf.function(elf.program_entry())?);

    // Initialize memory.
    let mut memory = SymbolicMemory::new(engine::Endian::Little);

    // Load all memory as given by the loader.
    for (address, segment) in elf.memory()?.segments() {
        let bytes = segment.bytes();
        for i in 0..bytes.len() {
            memory.store(*address + i as u64, il::expr_const(bytes[i] as u64, 8))?;
        }
    }

    let mut platform = linux_x86::LinuxX86::new();

    // Create the engine
    let mut engine = SymbolicEngine::new(memory);
    platform.initialize(&mut engine)?;

    // Get the first instruction we care about
    let pl = ProgramLocation::from_address(elf.program_entry(), &program).unwrap();
    // let pl = ProgramLocation::from_address(0x804880f, &program).unwrap();
    let translator = elf.translator()?;
    let driver = EngineDriver::new(
        Rc::new(program),
        pl,
        engine,
        &translator,
        Rc::new(platform)
    );
    let mut drivers = vec![driver];

    let target_address: u64 = 0x8048512;

    loop {
        let mut new_drivers = Vec::new();
        for driver in drivers {
            {
                let location = driver.location();
                let program = driver.program();
                let function_location = location.function_location();
                if let FunctionLocation::Instruction{block_index, instruction_index} = *function_location {
                    let function = program.function(location.function_index()).unwrap();
                    let block = function.block(block_index).unwrap();
                    let instruction = block.instruction(instruction_index).unwrap();
                    let address = instruction.address().unwrap();
                    if address == target_address {
                        println!("Reached Target Address");
                        for assertion in driver.engine().assertions() {
                            println!("Assertion: {}", assertion);
                        }
                        let mut stdin: Vec<u8> = Vec::new();
                        for scalar in driver.platform().symbolic_scalars() {
                            let byte = driver.engine().eval(&scalar.clone().into(), None)?.unwrap();
                            assert!(byte.bits() == 8);
                            stdin.push(byte.value() as u8);
                        }
                        return Ok(stdin);
                    }
                }
            }
            new_drivers.append(&mut driver.step()?);
        }
        drivers = new_drivers;
        if drivers.is_empty() {
            break;
        }
    }

    bail!("Did not find result")
}

#[test]
pub fn engine_test () -> () {
    let result: Vec<u8> = vec![0x61, 0x62, 0x63, 0x64 ,0x65, 0x66, 0x67, 0x68];
    let found = simple_0_test();
    assert!(found.is_ok());

    let found = found.unwrap();

    for i in 0..result.len() {
        println!("{} {}", result[i], found[i]);
        assert!(result[i] == found[i]);
    }
}

<commit_msg>Fixing simple-0 test.<commit_after>#[cfg(test)]use error::*;
#[cfg(test)]use engine;
#[cfg(test)]use engine::*;
#[cfg(test)]use il;
#[cfg(test)]use loader;
#[cfg(test)]use loader::Loader;
#[cfg(test)]use platform::*;
#[cfg(test)]use std::path::Path;
#[cfg(test)]use std::rc::Rc;

#[cfg(test)]
fn simple_0_test () -> Result<Vec<u8>> {
    // let filename = Path::new("test_binaries/Palindrome/Palindrome.json");
    // let elf = ::falcon::loader::json::Json::from_file(filename)?;
    let filename = Path::new("test_binaries/simple-0/simple-0");
    let elf = loader::elf::ElfLinker::new(filename)?;
    // let mut elf = ::falcon::loader::elf::Elf::from_file(filename)?;

    let mut program = il::Program::new();
    program.add_function(elf.function(elf.program_entry())?);

    // Initialize memory.
    let mut memory = SymbolicMemory::new(engine::Endian::Little);

    // Load all memory as given by the loader.
    for (address, segment) in elf.memory()?.segments() {
        let bytes = segment.bytes();
        for i in 0..bytes.len() {
            memory.store(*address + i as u64, il::expr_const(bytes[i] as u64, 8))?;
        }
    }

    let mut platform = linux_x86::LinuxX86::new();

    // Create the engine
    let mut engine = SymbolicEngine::new(memory);
    platform.initialize(&mut engine)?;

    // Get the first instruction we care about
    let pl = ProgramLocation::from_address(elf.program_entry(), &program).unwrap();
    // let pl = ProgramLocation::from_address(0x804880f, &program).unwrap();
    let translator = elf.translator()?;
    let driver = EngineDriver::new(
        Rc::new(program),
        pl,
        engine,
        &translator,
        Rc::new(platform)
    );
    let mut drivers = vec![driver];

    let target_address: u64 = 0x8048512;

    loop {
        let mut new_drivers = Vec::new();
        for driver in drivers {
            {
                let location = driver.location();
                let program = driver.program();
                let function_location = location.function_location();
                if let FunctionLocation::Instruction{block_index, instruction_index} = *function_location {
                    let function = program.function(location.function_index()).unwrap();
                    let block = function.block(block_index).unwrap();
                    let instruction = block.instruction(instruction_index).unwrap();
                    let address = instruction.address().unwrap();
                    if address == target_address {
                        println!("Reached Target Address");
                        for constraint in driver.engine().constraints() {
                            println!("Constraint: {}", constraint);
                        }
                        let mut stdin: Vec<u8> = Vec::new();
                        for scalar in driver.platform().symbolic_scalars() {
                            let byte = driver.engine().eval(&scalar.clone().into(), None)?.unwrap();
                            assert!(byte.bits() == 8);
                            stdin.push(byte.value() as u8);
                        }
                        return Ok(stdin);
                    }
                }
            }
            new_drivers.append(&mut driver.step()?);
        }
        drivers = new_drivers;
        if drivers.is_empty() {
            break;
        }
    }

    bail!("Did not find result")
}

#[test]
pub fn engine_test () -> () {
    let result: Vec<u8> = vec![0x61, 0x62, 0x63, 0x64 ,0x65, 0x66, 0x67, 0x68];
    let found = simple_0_test();
    assert!(found.is_ok());

    let found = found.unwrap();

    for i in 0..result.len() {
        println!("{} {}", result[i], found[i]);
        assert!(result[i] == found[i]);
    }
}

<|endoftext|>


<commit_before>use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use std::fmt;
use std::sync::Arc;
use vm::{EnvironmentRef, Trampoline};

#[derive(Debug, IntoHeap)]
pub struct Pair<'h> {
    pub car: Value<'h>,
    pub cdr: Value<'h>,
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub enum Value<'h> {
    Nil,
    Bool(bool),
    Int(i32),
    Symbol(Arc<String>),
    Lambda(PairRef<'h>),
    Builtin(GcLeaf<BuiltinFnPtr>),
    Cons(PairRef<'h>),
    Vector(VecRef<'h, Value<'h>>),
    Environment(EnvironmentRef<'h>),
}

pub use self::Value::*;

pub struct BuiltinFnPtr(
    pub for<'b> fn(&mut GcHeapSession<'b>, Vec<Value<'b>>)
        -> Result<Trampoline<'b>, String>,
);

// This can't be #[derive]d because function pointers aren't Clone.
// But they are Copy. A very weird thing about Rust.
impl Clone for BuiltinFnPtr {
    fn clone(&self) -> BuiltinFnPtr {
        BuiltinFnPtr(self.0)
    }
}

impl PartialEq for BuiltinFnPtr {
    fn eq(&self, other: &BuiltinFnPtr) -> bool {
        self.0 as usize == other.0 as usize
    }
}

impl fmt::Debug for BuiltinFnPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BuiltinFn({:p})", self.0 as usize as *mut ())?;
        Ok(())
    }
}

impl<'h> Value<'h> {
    pub fn is_nil(&self) -> bool {
        match *self {
            Nil => true,
            _ => false,
        }
    }

    pub fn is_boolean(&self) -> bool {
        match *self {
            Bool(_) => true,
            _ => false,
        }
    }

    /// True unless this value is `#f`. Conditional expressions (`if`, `cond`,
    /// etc.) should use this to check whether a value is a "true value".
    pub fn to_bool(&self) -> bool {
        match *self {
            Bool(false) => false,
            _ => true,
        }
    }

    pub fn as_int(self, error_msg: &str) -> Result<i32, String> {
        match self {
            Int(i) => Ok(i),
            _ => Err(format!("{}: number required", error_msg)),
        }
    }

    pub fn as_index(self, error_msg: &str) -> Result<usize, String> {
        match self {
            Int(i) => {
                if i >= 0 {
                    Ok(i as usize)
                } else {
                    Err(format!("{}: negative vector index", error_msg))
                }
            }
            _ => Err(format!("{}: vector index required", error_msg)),
        }
    }

    pub fn is_pair(&self) -> bool {
        match *self {
            Cons(_) => true,
            _ => false,
        }
    }

    pub fn is_vector(&self) -> bool {
        match *self {
            Vector(_) => true,
            _ => false,
        }
    }

    pub fn as_vector(self, error_msg: &str) -> Result<VecRef<'h, Value<'h>>, String> {
        match self {
            Vector(v) => Ok(v),
            _ => Err(format!("{}: vector expected", error_msg)),
        }
    }

    pub fn as_symbol(self, error_msg: &str) -> Result<Arc<String>, String> {
        match self {
            Symbol(s) => Ok(s),
            _ => Err(error_msg.to_string()),
        }
    }

    pub fn is_procedure(&self) -> bool {
        match *self {
            Lambda(_) => true,
            Builtin(_) => true,
            _ => false,
        }
    }
}

impl<'h> Iterator for Value<'h> {
    type Item = Result<Value<'h>, String>;

    fn next(&mut self) -> Option<Self::Item> {
        let (car, cdr) = match *self {
            Nil => return None,
            Cons(ref pair) => (pair.car(), pair.cdr()),
            _ => return Some(Err("improper list".into())),
        };
        *self = cdr;
        Some(Ok(car))
    }
}
<commit_msg>lisp: impl Display for Value<commit_after>use cell_gc::{GcHeapSession, GcLeaf};
use cell_gc::collections::VecRef;
use std::fmt;
use std::sync::Arc;
use vm::{EnvironmentRef, Trampoline};

#[derive(Debug, IntoHeap)]
pub struct Pair<'h> {
    pub car: Value<'h>,
    pub cdr: Value<'h>,
}

#[derive(Clone, Debug, PartialEq, IntoHeap)]
pub enum Value<'h> {
    Nil,
    Bool(bool),
    Int(i32),
    Symbol(Arc<String>),
    Lambda(PairRef<'h>),
    Builtin(GcLeaf<BuiltinFnPtr>),
    Cons(PairRef<'h>),
    Vector(VecRef<'h, Value<'h>>),
    Environment(EnvironmentRef<'h>),
}

pub use self::Value::*;

pub struct BuiltinFnPtr(
    pub for<'b> fn(&mut GcHeapSession<'b>, Vec<Value<'b>>)
        -> Result<Trampoline<'b>, String>,
);

// This can't be #[derive]d because function pointers aren't Clone.
// But they are Copy. A very weird thing about Rust.
impl Clone for BuiltinFnPtr {
    fn clone(&self) -> BuiltinFnPtr {
        BuiltinFnPtr(self.0)
    }
}

impl PartialEq for BuiltinFnPtr {
    fn eq(&self, other: &BuiltinFnPtr) -> bool {
        self.0 as usize == other.0 as usize
    }
}

impl fmt::Debug for BuiltinFnPtr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "BuiltinFn({:p})", self.0 as usize as *mut ())?;
        Ok(())
    }
}

impl<'h> fmt::Display for Value<'h> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        // Note that this will need to add a set of already-printed pairs if we add
        // `set-car!` and/or `set-cdr!` and introduce the possibility of cycles.
        match *self {
            Nil => write!(f, "nil"),
            Bool(true) => write!(f, "#t"),
            Bool(false) => write!(f, "#f"),
            Int(n) => write!(f, "{}", n),
            Symbol(ref s) => write!(f, "{}", s),
            Lambda(_) => write!(f, "#lambda"),
            Builtin(_) => write!(f, "#builtin"),
            Cons(ref p) => {
                write!(f, "(")?;
                write_pair(f, p.clone())?;
                write!(f, ")")
            }
            Vector(ref v) => {
                write!(f, "#(")?;
                for i in 0..v.len() {
                    if i != 0 {
                        write!(f, " ")?;
                    }
                    write!(f, "{}", v.get(i))?;
                }
                write!(f, ")")
            }
            Environment(_) => write!(f, "#environment"),
        }
    }
}

fn write_pair<'h>(f: &mut fmt::Formatter, pair: PairRef<'h>) -> fmt::Result {
    write!(f, "{}", pair.car())?;
    match pair.cdr() {
        Nil => Ok(()),
        Cons(p) => {
            write!(f, " ")?;
            write_pair(f, p)
        }
        otherwise => {
            write!(f, " . ")?;
            write!(f, "{}", otherwise)
        }
    }
}

impl<'h> Value<'h> {
    pub fn is_nil(&self) -> bool {
        match *self {
            Nil => true,
            _ => false,
        }
    }

    pub fn is_boolean(&self) -> bool {
        match *self {
            Bool(_) => true,
            _ => false,
        }
    }

    /// True unless this value is `#f`. Conditional expressions (`if`, `cond`,
    /// etc.) should use this to check whether a value is a "true value".
    pub fn to_bool(&self) -> bool {
        match *self {
            Bool(false) => false,
            _ => true,
        }
    }

    pub fn as_int(self, error_msg: &str) -> Result<i32, String> {
        match self {
            Int(i) => Ok(i),
            _ => Err(format!("{}: number required", error_msg)),
        }
    }

    pub fn as_index(self, error_msg: &str) -> Result<usize, String> {
        match self {
            Int(i) => {
                if i >= 0 {
                    Ok(i as usize)
                } else {
                    Err(format!("{}: negative vector index", error_msg))
                }
            }
            _ => Err(format!("{}: vector index required", error_msg)),
        }
    }

    pub fn is_pair(&self) -> bool {
        match *self {
            Cons(_) => true,
            _ => false,
        }
    }

    pub fn is_vector(&self) -> bool {
        match *self {
            Vector(_) => true,
            _ => false,
        }
    }

    pub fn as_vector(self, error_msg: &str) -> Result<VecRef<'h, Value<'h>>, String> {
        match self {
            Vector(v) => Ok(v),
            _ => Err(format!("{}: vector expected", error_msg)),
        }
    }

    pub fn as_symbol(self, error_msg: &str) -> Result<Arc<String>, String> {
        match self {
            Symbol(s) => Ok(s),
            _ => Err(error_msg.to_string()),
        }
    }

    pub fn is_procedure(&self) -> bool {
        match *self {
            Lambda(_) => true,
            Builtin(_) => true,
            _ => false,
        }
    }
}

impl<'h> Iterator for Value<'h> {
    type Item = Result<Value<'h>, String>;

    fn next(&mut self) -> Option<Self::Item> {
        let (car, cdr) = match *self {
            Nil => return None,
            Cons(ref pair) => (pair.car(), pair.cdr()),
            _ => return Some(Err("improper list".into())),
        };
        *self = cdr;
        Some(Ok(car))
    }
}
<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::io::{Read,Write,BufStream};
use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,BufRead};
use std::str::FromStr;
use std::fmt;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_messages::*;

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started, ready to accept");
  for stream in listener.incoming() {
    let next = next.clone();
    thread::spawn(move || {
	let mut sock = &stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        let mut strm = BufStream::new(sock);
        process_requests(peer, strm).unwrap()
      });
  }
}

fn process_requests<Id: fmt::Display, S: Read + Write>(id: Id, mut strm: BufStream<S>) -> Result<(), ServerError> {
  loop {
    debug!("{}: Waiting for message", id);
    let message_reader = try!(serialize_packed::read_message(&mut strm, ReaderOptions::new()));
    let msg = try!(message_reader.get_root::<client_request::Reader>());
    debug!("{}: Read message", id);

    match try!(msg.which()) {
      client_request::Truncate(v) => info!("{}: truncate:{:?}", id, v),
      client_request::Read(v) => info!("{}: read:{:?}", id, v),
    };

    let mut message = MallocMessageBuilder::new_default();
    {
      let mut rec = message.init_root::<client_response::Builder>();
    }

    try!(serialize_packed::write_message(&mut strm, &mut message));
    try!(strm.flush())
  }
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<commit_msg>Look for end of stream on client sockets.<commit_after>#![feature(convert)]
#![feature(buf_stream)]
#[macro_use] extern crate log;
extern crate env_logger;
extern crate yak_client;
extern crate capnp;

use std::io::{Read,Write,BufStream};
use std::net::{TcpListener, TcpStream, Ipv4Addr};
use std::thread;
use std::io::{self,BufRead};
use std::str::FromStr;
use std::fmt;

use capnp::serialize_packed;
use capnp::{MessageBuilder, MessageReader, MallocMessageBuilder, ReaderOptions};

use yak_client::yak_messages::*;

#[derive(Debug)]
enum ServerError {
  CapnpError(capnp::Error),
  CapnpNotInSchema(capnp::NotInSchema),
  IoError(std::io::Error)
}

pub fn main() {
  env_logger::init().unwrap();

  let mut a = std::env::args().skip(1);
  let local : String = a.next().unwrap();
  let next : Option<String> = a.next();

  let listener = TcpListener::bind(local.as_str()).unwrap();
  info!("listening started, ready to accept");
  for stream in listener.incoming() {
    let next = next.clone();
    thread::spawn(move || {
	let mut sock = &stream.unwrap();
	let peer = sock.peer_addr().unwrap();
	info!("Accept stream from {:?}", peer);
        let mut strm = BufStream::new(sock);
        process_requests(peer, strm).unwrap()
      });
  }
}

fn process_requests<Id: fmt::Display, S: Read + Write>(id: Id, mut strm: BufStream<S>) -> Result<(), ServerError> {
  loop {
    debug!("{}: Waiting for message", id);
    let len = try!(strm.fill_buf()).len();
    if len == 0 {
        debug!("{}: End of client stream", id);
        return Ok(())
    }
    let message_reader = try!(serialize_packed::read_message(&mut strm, ReaderOptions::new()));
    let msg = try!(message_reader.get_root::<client_request::Reader>());
    debug!("{}: Read message", id);

    match try!(msg.which()) {
      client_request::Truncate(v) => info!("{}: truncate:{:?}", id, v),
      client_request::Read(v) => info!("{}: read:{:?}", id, v),
    };

    let mut message = MallocMessageBuilder::new_default();
    {
      let mut rec = message.init_root::<client_response::Builder>();
    }

    try!(serialize_packed::write_message(&mut strm, &mut message));
    try!(strm.flush())
  }
}

impl From<capnp::Error> for ServerError {
  fn from(err: capnp::Error) -> ServerError {
    ServerError::CapnpError(err)
  }
}

impl From<capnp::NotInSchema> for ServerError {
  fn from(err: capnp::NotInSchema) -> ServerError {
    ServerError::CapnpNotInSchema(err)
  }
}

impl From<io::Error> for ServerError {
  fn from(err: io::Error) -> ServerError {
    ServerError::IoError(err)
  }
}
<|endoftext|>


<commit_before>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg, ArgGroup};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub bin: Option<String>,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    bin: config.get_defaults_bin().map(|s| s.to_owned()),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let mut app = App::new(name.as_ref())
    .version(version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("bin")
      .short("b")
      .long("bin")
      .help("bin to use when uploading")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("legacy flag included for backwards compatibility. use --bin, as this will be removed in 2.0.0")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .group(ArgGroup::with_name("bin_or_service")
      .args(&["bin", "service"])
      .required(arguments.bin.is_none()))
    .arg(Arg::with_name("list-bins")
      .short("l")
      .long("list-bins")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .arg(Arg::with_name("list-services")
      .long("list-services")
      .help("legacy flag included for backwards compatibility. use --list-bins, as this will be removed in 2.0.0")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .group(ArgGroup::with_name("list-bins_or_list-services").args(&["list-bins", "list-services"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "bin_or_service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output a json object instead of normal values")
      .conflicts_with_all(&["write", "urls", "raw-urls"]));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-bins_or_list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(bin) = res.value_of("bin_or_service") {
    arguments.bin = Some(bin.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref bin) = arguments.bin {
      if bin.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<commit_msg>feat: add feature information to version string<commit_after>use bins::error::*;
use bins::Bins;
use bins::configuration::BinsConfiguration;
use bins::engines;
use bins::FlexibleRange;
use bins::network;
use clap::{App, Arg, ArgGroup};
use hyper::Url;
use std::path::Path;
use std::process;

pub struct Arguments {
  pub all: bool,
  pub auth: bool,
  pub bin: Option<String>,
  pub copy: bool,
  pub files: Vec<String>,
  pub force: bool,
  pub input: Option<String>,
  pub json: bool,
  pub message: Option<String>,
  pub name: Option<String>,
  pub number_lines: bool,
  pub output: Option<String>,
  pub private: bool,
  pub range: Option<FlexibleRange>,
  pub raw_urls: bool,
  pub server: Option<Url>,
  pub urls: bool,
  pub write: bool
}

include!(concat!(env!("OUT_DIR"), "/git_short_tag.rs"));

fn get_name() -> String {
  option_env!("CARGO_PKG_NAME").unwrap_or("unknown_name").to_owned()
}

fn get_version() -> String {
  let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown_version").to_owned();
  let git_tag = git_short_tag();
  format!("{}{}", version, git_tag)
}

fn get_feature_info() -> String {
  let mut features = Vec::new();
  if cfg!(feature = "clipboard_support") {
    features.push("clipboard_support");
  }
  if cfg!(feature = "file_type_checking") {
    features.push("file_type_checking");
  }
  if features.is_empty() {
    String::new()
  } else {
    format!("features: {}", features.join(", "))
  }
}

cfg_if! {
  if #[cfg(feature = "clipboard_support")] {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      vec![Arg::with_name("copy")
             .short("C")
             .long("copy")
             .help("copies the output of the command to the clipboard without a newline")
             .conflicts_with("no-copy"),
           Arg::with_name("no-copy")
             .short("c")
             .long("no-copy")
             .help("does not copy the output of the command to the clipboard")]
    }
  } else {
    fn get_clipboard_args<'a, 'b>() -> Vec<Arg<'a, 'b>> {
      Vec::new()
    }
  }
}

pub fn get_arguments(config: &BinsConfiguration) -> Result<Arguments> {
  let mut arguments = Arguments {
    all: false,
    auth: config.get_defaults_auth(),
    bin: config.get_defaults_bin().map(|s| s.to_owned()),
    copy: config.get_defaults_copy(),
    files: Vec::new(),
    force: false,
    input: None,
    json: false,
    message: None,
    name: None,
    number_lines: false,
    output: None,
    private: config.get_defaults_private(),
    range: None,
    raw_urls: false,
    server: None,
    urls: false,
    write: false
  };
  let name = get_name();
  let version = get_version();
  let feature_info = get_feature_info();
  let combined_version = if feature_info.is_empty() {
    version
  } else {
    format!("{}\n{}", version, feature_info)
  };
  let mut app = App::new(name.as_ref())
    .version(combined_version.as_ref())
    .about("A tool for pasting from the terminal")
    .arg(Arg::with_name("files")
      .help("files to paste")
      .takes_value(true)
      .multiple(true))
    .arg(Arg::with_name("message")
      .short("m")
      .long("message")
      .help("message to paste")
      .use_delimiter(false)
      .takes_value(true)
      .value_name("string"))
    .arg(Arg::with_name("private")
      .short("p")
      .long("private")
      .help("if the paste should be private")
      .conflicts_with("public"))
    .arg(Arg::with_name("public")
      .short("P")
      .long("public")
      .help("if the paste should be public"))
    .arg(Arg::with_name("auth")
      .short("a")
      .long("auth")
      .help("if authentication (like api keys and tokens) should be used")
      .conflicts_with("anon"))
    .arg(Arg::with_name("anon")
      .short("A")
      .long("anon")
      .help("if pastes should be posted without authentication"))
    .arg(Arg::with_name("bin")
      .short("b")
      .long("bin")
      .help("bin to use when uploading")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .arg(Arg::with_name("service")
      .short("s")
      .long("service")
      .help("legacy flag included for backwards compatibility. use --bin, as this will be removed in 2.0.0")
      .takes_value(true)
      .possible_values(&*engines::get_bin_names()))
    .group(ArgGroup::with_name("bin_or_service")
      .args(&["bin", "service"])
      .required(arguments.bin.is_none()))
    .arg(Arg::with_name("list-bins")
      .short("l")
      .long("list-bins")
      .help("lists available bins and exits")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .arg(Arg::with_name("list-services")
      .long("list-services")
      .help("legacy flag included for backwards compatibility. use --list-bins, as this will be removed in 2.0.0")
      .conflicts_with_all(&["files", "message", "private", "public", "auth", "anon", "bin_or_service", "input"]))
    .group(ArgGroup::with_name("list-bins_or_list-services").args(&["list-bins", "list-services"]))
    .arg(Arg::with_name("input")
      .short("i")
      .long("input")
      .help("displays raw contents of input paste")
      .takes_value(true)
      .value_name("url")
      .conflicts_with_all(&["auth", "anon", "public", "private", "message", "bin_or_service"]))
    .arg(Arg::with_name("range")
      .short("n")
      .long("range")
      .help("chooses the files to get in input mode, starting from 0 (e.g. \"0\", \"0,1\", \"0-2\", \"2-0,3\")")
      .takes_value(true)
      .value_name("range")
      .use_delimiter(false)
      .requires("input")
      .conflicts_with("files"))
    .arg(Arg::with_name("all")
      .short("L")
      .long("all")
      .help("gets all files in input mode")
      .requires("input")
      .conflicts_with_all(&["files", "range"]))
    .arg(Arg::with_name("raw-urls")
      .short("r")
      .long("raw-urls")
      .help("gets the raw urls instead of the content in input mode")
      .requires("input"))
    .arg(Arg::with_name("urls")
      .short("u")
      .long("urls")
      .help("gets the urls instead of the content in input mode")
      .requires("input")
      .conflicts_with("raw-urls"))
    .arg(Arg::with_name("server")
      .short("S")
      .long("server")
      .help("specifies the server to use for the service (only support on hastebin)")
      .takes_value(true)
      .value_name("server_url"))
    .arg(Arg::with_name("name")
      .short("N")
      .long("name")
      .help("specifies a file name for --message or stdin")
      .takes_value(true)
      .value_name("name")
      .conflicts_with("files"))
    .arg(Arg::with_name("force")
      .short("f")
      .long("force")
      .help("overrides warnings about file type or size when uploading")
      .conflicts_with("input"))
    .arg(Arg::with_name("number_lines")
      .short("e")
      .long("number-lines")
      .help("display line numbers for each file in input mode")
      .requires("input"))
    .arg(Arg::with_name("write")
      .short("w")
      .long("write")
      .help("writes pastes to files in input mode")
      .requires("input"))
    .arg(Arg::with_name("output")
      .short("o")
      .long("output")
      .help("specifies where to save files in write mode")
      .takes_value(true)
      .value_name("dir")
      .requires("write"))
    .arg(Arg::with_name("json")
      .short("j")
      .long("json")
      .help("output a json object instead of normal values")
      .conflicts_with_all(&["write", "urls", "raw-urls"]));
  for arg in get_clipboard_args() {
    app = app.arg(arg);
  }
  let res = app.get_matches();
  if res.is_present("list-bins_or_list-services") {
    println!("{}", engines::get_bin_names().join("\n"));
    process::exit(0);
  }
  if let Some(files) = res.values_of("files") {
    arguments.files = files.map(|s| s.to_owned()).collect();
  }
  if let Some(message) = res.value_of("message") {
    arguments.message = Some(message.to_owned());
  }
  if let Some(bin) = res.value_of("bin_or_service") {
    arguments.bin = Some(bin.to_owned());
  }
  if let Some(input) = res.value_of("input") {
    arguments.input = Some(input.to_owned());
  }
  if let Some(range) = res.value_of("range") {
    arguments.range = Some(try!(FlexibleRange::parse(range)));
  }
  if let Some(server) = res.value_of("server") {
    if let Some(ref bin) = arguments.bin {
      if bin.to_lowercase() != "hastebin" {
        return Err("--server may only be used if --service is hastebin".into());
      }
    }
    arguments.server = Some(try!(network::parse_url(server).chain_err(|| "invalid --server")));
  }
  if let Some(name) = res.value_of("name") {
    let name = try!(Bins::sanitize_path(Path::new(name)));
    arguments.name = Some(name.to_owned());
  }
  if let Some(output) = res.value_of("output") {
    arguments.output = Some(output.to_owned());
  }
  arguments.all = res.is_present("all");
  arguments.force = res.is_present("force");
  arguments.json = res.is_present("json");
  arguments.number_lines = res.is_present("number_lines");
  arguments.raw_urls = res.is_present("raw-urls");
  arguments.urls = res.is_present("urls");
  arguments.write = res.is_present("write");
  if res.is_present("private") {
    arguments.private = true;
  } else if res.is_present("public") {
    arguments.private = false;
  }
  if res.is_present("anon") {
    arguments.auth = false;
  } else if res.is_present("auth") {
    arguments.auth = true;
  }
  if res.is_present("copy") {
    arguments.copy = true;
  } else if res.is_present("no-copy") {
    arguments.copy = false;
  }
  Ok(arguments)
}
<|endoftext|>