<commit_before>use std::net::{SocketAddr};
use std::cmp::max;

use mioco;
use mioco::JoinHandle;
use mioco::udp::UdpSocket;
use mioco::tcp::{TcpListener};
use mioco::sync::mpsc::{channel};
use trust_dns::op::{Message, ResponseCode, Edns, OpCode};
use trust_dns::rr::{DNSClass, RecordType};
use trust_dns_proto::rr::dnssec::rdata::DNSSECRecordType;
use trust_dns_proto::serialize::binary::BinEncodable;

use utils::{Result, Error, MessageExt, WithTimeout};
use transport::{DnsTransport};
use query::{EDNS_VER};
use resolver::{RcResolver};

/// This function should never fail, otherwise we have a panic
fn handle_request(resolver: &RcResolver, msg: &Message, should_truncate: bool) -> Result<Vec<u8>> {
    let mut ret : Message = msg.new_resp();
    ret.set_recursion_available(true);
    let mut have_dnssec = false;
    if let Some(req_edns) = msg.edns() {
        let mut resp_edns = Edns::new();
        resp_edns.set_version(EDNS_VER);
        have_dnssec = req_edns.dnssec_ok();
        resp_edns.set_dnssec_ok(have_dnssec);
        resp_edns.set_max_payload(max(512, req_edns.max_payload()));
        ret.set_edns(resp_edns);
        if req_edns.version() > EDNS_VER {
            warn!("Got EDNS version {}", req_edns.version());
            ret.set_response_code(ResponseCode::BADVERS);
            return ret.to_bytes().map_err(|e| e.into());
        }
    }
    if msg.queries().len() != 1 || msg.op_code() != OpCode::Query {
        // For simplicity, only support one question
        ret.set_response_code(ResponseCode::Refused);
        return ret.to_bytes().map_err(|e| e.into());
    }
    if msg.queries()[0].query_class() != DNSClass::IN {
        ret.set_response_code(ResponseCode::NotImp);
        return ret.to_bytes().map_err(|e| e.into());
    }
    match resolver.resolve(&mut ret) {
        Ok(_) => { /* Message is filled with answers */ },
        Err(e) => {
            warn!("Resolver returned error: {:?}", e);
            ret.set_response_code(ResponseCode::ServFail);
        },
    };
    if !have_dnssec {
        ret = ret.strip_dnssec_records();
    } else {
        let is_authenticated = ret.answers().iter()
        .chain(ret.name_servers())
        .any(|rec| rec.rr_type() == RecordType::DNSSEC(DNSSECRecordType::RRSIG));
        ret.set_authentic_data(is_authenticated);
    }
    let bytes = try!(ret.to_bytes());
    if should_truncate && bytes.len() > (msg.max_payload() as usize) {
        return ret.truncate().to_bytes().map_err(|e| e.into());
    }
    Ok(bytes)
}
#[allow(similar_names)]
fn serve_transport_async<TRecv, TSend, F>(mut recv: TRecv, mut send: TSend, resolver: RcResolver, on_error: F) -> JoinHandle<()>
    where TRecv: DnsTransport + Send + 'static,
          TSend: DnsTransport + Send + 'static,
          F: FnOnce(Error) + Send + 'static,
{
    let (sch, rch) = channel::<(Vec<u8>, Option<SocketAddr>)>();
    mioco::spawn(move || {
        loop {
            match rch.recv() {
                Ok((buf, addr)) => {
                    match send.send_msg_bytes(&buf, addr.as_ref()) {
                        Ok(_) => { },
                        Err(e) => { warn!("Failed to respond to DNS request: {:?}", e); },
                    };
                },
                Err(_) => {
                    trace!("Channel is broken");
                    return;
                },
            };
        }
    });
    mioco::spawn(move || {
        loop {
            let (msg, addr) = match recv.recv_msg(None) {
                Ok(x) => x,
                Err(e) => {
                    on_error(e);
                    return;
                },
            };
            let sch_req = sch.clone();
            let res = resolver.clone();
            mioco::spawn(move || {
                let resp = handle_request(&res, &msg, TSend::should_truncate()).expect("handle_request should not return error");
                sch_req.send((resp, addr)).expect("Result pipe should not break here");
            });
        }
    })
}
pub fn serve_tcp(addr: &SocketAddr, resolver: RcResolver) -> Result<JoinHandle<()>> {
    let listener = try!(TcpListener::bind(addr));
    Ok(mioco::spawn(move || {
        loop {
            let sock = listener.accept().expect("Failed to accept TCP socket");
            sock.set_nodelay(true).unwrap_or(());
            let sock_clone = sock.try_clone().expect("Failed to clone TCP socket");
            serve_transport_async(
                sock.with_resetting_timeout(*resolver.config.serve.tcp_timeout),
                sock_clone.with_resetting_timeout(*resolver.config.serve.tcp_timeout),
                resolver.clone(),
                |e| trace!("Client TCP connection is broken: {:?}", e)
            );
        }
    }))
}
pub fn serve_udp(addr: &SocketAddr, resolver: RcResolver) -> Result<JoinHandle<()>> {
    let sock : UdpSocket = try!(UdpSocket::bound(addr));
    let sock_clone = try!(sock.try_clone());
    Ok(serve_transport_async(
        sock, sock_clone, resolver, |e| {
            match e {
                Error::Proto(reason) => warn!("Invalid DNS request: {:?}", reason),
                e2 => panic!("UDP listener is broken: {:?}", e2),
            }
        }
    ))
}
<commit_msg>Properly truncate responses<commit_after>use std::net::{SocketAddr};
use std::cmp::max;

use mioco;
use mioco::JoinHandle;
use mioco::udp::UdpSocket;
use mioco::tcp::{TcpListener};
use mioco::sync::mpsc::{channel};
use trust_dns::op::{Message, ResponseCode, Edns, OpCode};
use trust_dns::rr::{DNSClass, RecordType};
use trust_dns_proto::rr::dnssec::rdata::DNSSECRecordType;
use trust_dns_proto::serialize::binary::BinEncodable;

use utils::{Result, Error, MessageExt, WithTimeout};
use transport::{DnsTransport};
use query::{EDNS_VER};
use resolver::{RcResolver};

/// This function should never fail, otherwise we have a panic
fn handle_request(resolver: &RcResolver, msg: &Message, should_truncate: bool) -> Result<Vec<u8>> {
    let mut ret : Message = msg.new_resp();
    ret.set_recursion_available(true);
    let mut have_dnssec = false;
    if let Some(req_edns) = msg.edns() {
        let mut resp_edns = Edns::new();
        resp_edns.set_version(EDNS_VER);
        have_dnssec = req_edns.dnssec_ok();
        resp_edns.set_dnssec_ok(have_dnssec);
        resp_edns.set_max_payload(max(512, req_edns.max_payload()));
        ret.set_edns(resp_edns);
        if req_edns.version() > EDNS_VER {
            warn!("Got EDNS version {}", req_edns.version());
            ret.set_response_code(ResponseCode::BADVERS);
            return ret.to_bytes().map_err(|e| e.into());
        }
    }
    if msg.queries().len() != 1 || msg.op_code() != OpCode::Query {
        // For simplicity, only support one question
        ret.set_response_code(ResponseCode::Refused);
        return ret.to_bytes().map_err(|e| e.into());
    }
    if msg.queries()[0].query_class() != DNSClass::IN {
        ret.set_response_code(ResponseCode::NotImp);
        return ret.to_bytes().map_err(|e| e.into());
    }
    match resolver.resolve(&mut ret) {
        Ok(_) => { /* Message is filled with answers */ },
        Err(e) => {
            warn!("Resolver returned error: {:?}", e);
            ret.set_response_code(ResponseCode::ServFail);
        },
    };
    if !have_dnssec {
        ret = ret.strip_dnssec_records();
    } else {
        let is_authenticated = ret.answers().iter()
        .chain(ret.name_servers())
        .any(|rec| rec.rr_type() == RecordType::DNSSEC(DNSSECRecordType::RRSIG));
        ret.set_authentic_data(is_authenticated);
    }
    let mut bytes = try!(ret.to_bytes());
    if should_truncate && bytes.len() > (msg.max_payload() as usize) {
        ret.set_truncated(true);
        ret.take_name_servers();
        ret.take_additionals();
        bytes = ret.to_bytes()?;
        while bytes.len() > (msg.max_payload() as usize) {
            let mut answers = ret.take_answers();
            let new_len = answers.len() / 2;
            answers.truncate(new_len);
            ret.insert_answers(answers);
            bytes = ret.to_bytes()?;
        }
    }
    Ok(bytes)
}
#[allow(similar_names)]
fn serve_transport_async<TRecv, TSend, F>(mut recv: TRecv, mut send: TSend, resolver: RcResolver, on_error: F) -> JoinHandle<()>
    where TRecv: DnsTransport + Send + 'static,
          TSend: DnsTransport + Send + 'static,
          F: FnOnce(Error) + Send + 'static,
{
    let (sch, rch) = channel::<(Vec<u8>, Option<SocketAddr>)>();
    mioco::spawn(move || {
        loop {
            match rch.recv() {
                Ok((buf, addr)) => {
                    match send.send_msg_bytes(&buf, addr.as_ref()) {
                        Ok(_) => { },
                        Err(e) => { warn!("Failed to respond to DNS request: {:?}", e); },
                    };
                },
                Err(_) => {
                    trace!("Channel is broken");
                    return;
                },
            };
        }
    });
    mioco::spawn(move || {
        loop {
            let (msg, addr) = match recv.recv_msg(None) {
                Ok(x) => x,
                Err(e) => {
                    on_error(e);
                    return;
                },
            };
            let sch_req = sch.clone();
            let res = resolver.clone();
            mioco::spawn(move || {
                let resp = handle_request(&res, &msg, TSend::should_truncate()).expect("handle_request should not return error");
                sch_req.send((resp, addr)).expect("Result pipe should not break here");
            });
        }
    })
}
pub fn serve_tcp(addr: &SocketAddr, resolver: RcResolver) -> Result<JoinHandle<()>> {
    let listener = try!(TcpListener::bind(addr));
    Ok(mioco::spawn(move || {
        loop {
            let sock = listener.accept().expect("Failed to accept TCP socket");
            sock.set_nodelay(true).unwrap_or(());
            let sock_clone = sock.try_clone().expect("Failed to clone TCP socket");
            serve_transport_async(
                sock.with_resetting_timeout(*resolver.config.serve.tcp_timeout),
                sock_clone.with_resetting_timeout(*resolver.config.serve.tcp_timeout),
                resolver.clone(),
                |e| trace!("Client TCP connection is broken: {:?}", e)
            );
        }
    }))
}
pub fn serve_udp(addr: &SocketAddr, resolver: RcResolver) -> Result<JoinHandle<()>> {
    let sock : UdpSocket = try!(UdpSocket::bound(addr));
    let sock_clone = try!(sock.try_clone());
    Ok(serve_transport_async(
        sock, sock_clone, resolver, |e| {
            match e {
                Error::Proto(reason) => warn!("Invalid DNS request: {:?}", reason),
                e2 => panic!("UDP listener is broken: {:?}", e2),
            }
        }
    ))
}
<|endoftext|>


<commit_before>///! Constructors for [predefined push rules].
///!
///! [predefined push rules]: https://matrix.org/docs/spec/client_server/r0.6.1#predefined-rules
use super::{
    Action::*, ConditionalPushRule, ContentPushRule, OverridePushRule, PatternedPushRule,
    PushCondition::*, RoomMemberCountIs, Ruleset, Tweak, UnderridePushRule,
};

use ruma_identifiers::UserId;

macro_rules! set {
    ($( $elt:expr ),*) => {
        {
            use std::collections::BTreeSet;

            let mut s = BTreeSet::new();
            $( s.insert( $elt ); )*
            s
        }
    };
    ($( $elt:expr ),* ,) => {
        set![ $( $elt ),* ]
    };
}

impl Ruleset {
    /// The list of all [predefined push rules].
    ///
    /// [predefined push rules]: https://matrix.org/docs/spec/client_server/r0.6.1#predefined-rules
    ///
    /// # Parameters
    ///
    /// - `user_id`: the user for which to generate the default rules. Some rules depend on the
    ///   user's ID (for instance those to send notifications when they are mentioned).
    pub fn server_default(user_id: &UserId) -> Self {
        Self {
            content: set![ContentPushRule::contains_user_name(user_id)],
            override_: set![
                OverridePushRule::master(),
                OverridePushRule::suppress_notices(),
                OverridePushRule::invite_for_me(user_id),
                OverridePushRule::member_event(),
                OverridePushRule::contains_display_name(),
                OverridePushRule::tombstone(),
                OverridePushRule::roomnotif(),
            ],
            underride: set![
                UnderridePushRule::call(),
                UnderridePushRule::encrypted_room_one_to_one(),
                UnderridePushRule::room_one_to_one(),
                UnderridePushRule::message(),
                UnderridePushRule::encrypted(),
            ],
            ..Default::default()
        }
    }
}

/// Default override push rules
impl OverridePushRule {
    /// Matches all events, this can be enabled to turn off all push notifications other than those
    /// generated by override rules set by the user.
    pub fn master() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: false,
            rule_id: ".m.rule.master".into(),
            conditions: vec![],
        })
    }

    /// Matches messages with a `msgtype` of `notice`.
    pub fn suppress_notices() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.suppress_notices".into(),
            conditions: vec![EventMatch {
                key: "content.msgtype".into(),
                pattern: "m.notice".into(),
            }],
        })
    }

    /// Matches any invites to a new room for this user.
    pub fn invite_for_me(user_id: &UserId) -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.invite_for_me".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.member".into() },
                EventMatch { key: "content.membership".into(), pattern: "invite".into() },
                EventMatch { key: "state_key".into(), pattern: user_id.to_string() },
            ],
        })
    }

    /// Matches any `m.room.member_event`.
    pub fn member_event() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.member_event".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.member".into() }],
        })
    }

    /// Matches any message whose content is unencrypted and contains the user's current display
    /// name in the room in which it was sent.
    pub fn contains_display_name() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.contains_display_name".into(),
            conditions: vec![ContainsDisplayName],
        })
    }

    /// Matches any state event whose type is `m.room.tombstone`. This
    /// is intended to notify users of a room when it is upgraded,
    /// similar to what an `@room` notification would accomplish.
    pub fn tombstone() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: false,
            rule_id: ".m.rule.tombstone".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.tombstone".into() },
                EventMatch { key: "state_key".into(), pattern: "".into() },
            ],
        })
    }

    /// Matches any message whose content is unencrypted and contains the text `@room`, signifying
    /// the whole room should be notified of the event.
    pub fn roomnotif() -> Self {
        OverridePushRule(ConditionalPushRule {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: true,
            rule_id: ".m.rule.roomnotif".into(),
            conditions: vec![
                EventMatch { key: "content.body".into(), pattern: "@room".into() },
                SenderNotificationPermission { key: "room".into() },
            ],
        })
    }
}

/// Default content push rules
impl ContentPushRule {
    /// Matches any message whose content is unencrypted and contains the local part of the user's
    /// Matrix ID, separated by word boundaries.
    pub fn contains_user_name(user_id: &UserId) -> Self {
        ContentPushRule(PatternedPushRule {
            rule_id: ".m.rules.contains_user_name".into(),
            enabled: true,
            default: true,
            pattern: user_id.localpart().into(),
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
        })
    }
}

/// Default underrides push rules
impl UnderridePushRule {
    /// Matches any incoming VOIP call.
    pub fn call() -> Self {
        UnderridePushRule(ConditionalPushRule {
            rule_id: ".m.rules.call".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.call.invite".into() }],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("ring".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches any encrypted event sent in a room with exactly two members. Unlike other push
    /// rules, this rule cannot be matched against the content of the event by nature of it being
    /// encrypted. This causes the rule to be an "all or nothing" match where it either matches all
    /// events that are encrypted (in 1:1 rooms) or none.
    pub fn encrypted_room_one_to_one() -> Self {
        UnderridePushRule(ConditionalPushRule {
            rule_id: ".m.rules.encrypted_room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches any message sent in a room with exactly two members.
    pub fn room_one_to_one() -> Self {
        UnderridePushRule(ConditionalPushRule {
            rule_id: ".m.rules.room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.message".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches all chat messages.
    pub fn message() -> Self {
        UnderridePushRule(ConditionalPushRule {
            rule_id: ".m.rules.message".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.message".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        })
    }

    /// Matches all encrypted events. Unlike other push rules, this rule cannot be matched against
    /// the content of the event by nature of it being encrypted. This causes the rule to be an
    /// "all or nothing" match where it either matches all events that are encrypted (in group
    /// rooms) or none.
    pub fn encrypted() -> Self {
        UnderridePushRule(ConditionalPushRule {
            rule_id: ".m.rules.encrypted".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        })
    }
}
<commit_msg>Use Self constructors when possible<commit_after>///! Constructors for [predefined push rules].
///!
///! [predefined push rules]: https://matrix.org/docs/spec/client_server/r0.6.1#predefined-rules
use super::{
    Action::*, ConditionalPushRule, ContentPushRule, OverridePushRule, PatternedPushRule,
    PushCondition::*, RoomMemberCountIs, Ruleset, Tweak, UnderridePushRule,
};

use ruma_identifiers::UserId;

macro_rules! set {
    ($( $elt:expr ),*) => {
        {
            use std::collections::BTreeSet;

            let mut s = BTreeSet::new();
            $( s.insert( $elt ); )*
            s
        }
    };
    ($( $elt:expr ),* ,) => {
        set![ $( $elt ),* ]
    };
}

impl Ruleset {
    /// The list of all [predefined push rules].
    ///
    /// [predefined push rules]: https://matrix.org/docs/spec/client_server/r0.6.1#predefined-rules
    ///
    /// # Parameters
    ///
    /// - `user_id`: the user for which to generate the default rules. Some rules depend on the
    ///   user's ID (for instance those to send notifications when they are mentioned).
    pub fn server_default(user_id: &UserId) -> Self {
        Self {
            content: set![ContentPushRule::contains_user_name(user_id)],
            override_: set![
                OverridePushRule::master(),
                OverridePushRule::suppress_notices(),
                OverridePushRule::invite_for_me(user_id),
                OverridePushRule::member_event(),
                OverridePushRule::contains_display_name(),
                OverridePushRule::tombstone(),
                OverridePushRule::roomnotif(),
            ],
            underride: set![
                UnderridePushRule::call(),
                UnderridePushRule::encrypted_room_one_to_one(),
                UnderridePushRule::room_one_to_one(),
                UnderridePushRule::message(),
                UnderridePushRule::encrypted(),
            ],
            ..Default::default()
        }
    }
}

/// Default override push rules
impl OverridePushRule {
    /// Matches all events, this can be enabled to turn off all push notifications other than those
    /// generated by override rules set by the user.
    pub fn master() -> Self {
        Self(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: false,
            rule_id: ".m.rule.master".into(),
            conditions: vec![],
        })
    }

    /// Matches messages with a `msgtype` of `notice`.
    pub fn suppress_notices() -> Self {
        Self(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.suppress_notices".into(),
            conditions: vec![EventMatch {
                key: "content.msgtype".into(),
                pattern: "m.notice".into(),
            }],
        })
    }

    /// Matches any invites to a new room for this user.
    pub fn invite_for_me(user_id: &UserId) -> Self {
        Self(ConditionalPushRule {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.invite_for_me".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.member".into() },
                EventMatch { key: "content.membership".into(), pattern: "invite".into() },
                EventMatch { key: "state_key".into(), pattern: user_id.to_string() },
            ],
        })
    }

    /// Matches any `m.room.member_event`.
    pub fn member_event() -> Self {
        Self(ConditionalPushRule {
            actions: vec![DontNotify],
            default: true,
            enabled: true,
            rule_id: ".m.rule.member_event".into(),
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.member".into() }],
        })
    }

    /// Matches any message whose content is unencrypted and contains the user's current display
    /// name in the room in which it was sent.
    pub fn contains_display_name() -> Self {
        Self(ConditionalPushRule {
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
            default: true,
            enabled: true,
            rule_id: ".m.rule.contains_display_name".into(),
            conditions: vec![ContainsDisplayName],
        })
    }

    /// Matches any state event whose type is `m.room.tombstone`. This
    /// is intended to notify users of a room when it is upgraded,
    /// similar to what an `@room` notification would accomplish.
    pub fn tombstone() -> Self {
        Self(ConditionalPushRule {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: false,
            rule_id: ".m.rule.tombstone".into(),
            conditions: vec![
                EventMatch { key: "type".into(), pattern: "m.room.tombstone".into() },
                EventMatch { key: "state_key".into(), pattern: "".into() },
            ],
        })
    }

    /// Matches any message whose content is unencrypted and contains the text `@room`, signifying
    /// the whole room should be notified of the event.
    pub fn roomnotif() -> Self {
        Self(ConditionalPushRule {
            actions: vec![Notify, SetTweak(Tweak::Highlight(true))],
            default: true,
            enabled: true,
            rule_id: ".m.rule.roomnotif".into(),
            conditions: vec![
                EventMatch { key: "content.body".into(), pattern: "@room".into() },
                SenderNotificationPermission { key: "room".into() },
            ],
        })
    }
}

/// Default content push rules
impl ContentPushRule {
    /// Matches any message whose content is unencrypted and contains the local part of the user's
    /// Matrix ID, separated by word boundaries.
    pub fn contains_user_name(user_id: &UserId) -> Self {
        Self(PatternedPushRule {
            rule_id: ".m.rules.contains_user_name".into(),
            enabled: true,
            default: true,
            pattern: user_id.localpart().into(),
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(true)),
            ],
        })
    }
}

/// Default underrides push rules
impl UnderridePushRule {
    /// Matches any incoming VOIP call.
    pub fn call() -> Self {
        Self(ConditionalPushRule {
            rule_id: ".m.rules.call".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.call.invite".into() }],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("ring".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches any encrypted event sent in a room with exactly two members. Unlike other push
    /// rules, this rule cannot be matched against the content of the event by nature of it being
    /// encrypted. This causes the rule to be an "all or nothing" match where it either matches all
    /// events that are encrypted (in 1:1 rooms) or none.
    pub fn encrypted_room_one_to_one() -> Self {
        Self(ConditionalPushRule {
            rule_id: ".m.rules.encrypted_room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches any message sent in a room with exactly two members.
    pub fn room_one_to_one() -> Self {
        Self(ConditionalPushRule {
            rule_id: ".m.rules.room_one_to_one".into(),
            default: true,
            enabled: true,
            conditions: vec![
                RoomMemberCount { is: RoomMemberCountIs::from(js_int::uint!(2)) },
                EventMatch { key: "type".into(), pattern: "m.room.message".into() },
            ],
            actions: vec![
                Notify,
                SetTweak(Tweak::Sound("default".into())),
                SetTweak(Tweak::Highlight(false)),
            ],
        })
    }

    /// Matches all chat messages.
    pub fn message() -> Self {
        Self(ConditionalPushRule {
            rule_id: ".m.rules.message".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.message".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        })
    }

    /// Matches all encrypted events. Unlike other push rules, this rule cannot be matched against
    /// the content of the event by nature of it being encrypted. This causes the rule to be an
    /// "all or nothing" match where it either matches all events that are encrypted (in group
    /// rooms) or none.
    pub fn encrypted() -> Self {
        Self(ConditionalPushRule {
            rule_id: ".m.rules.encrypted".into(),
            default: true,
            enabled: true,
            conditions: vec![EventMatch { key: "type".into(), pattern: "m.room.encrypted".into() }],
            actions: vec![Notify, SetTweak(Tweak::Highlight(false))],
        })
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Modules/fs_fat/dir.rs
use kernel::prelude::*;
use kernel::lib::mem::aref::ArefBorrow;
use kernel::vfs::{self,node};
use kernel::lib::byte_str::{ByteStr,ByteString};

pub struct DirNode
{
	fs: ArefBorrow<super::FilesystemInner>,
	start_cluster: u32,
	// - Uses the cluster chain
}
pub struct RootDirNode
{
	fs: ArefBorrow<super::FilesystemInner>,
}

struct DirCluster<'a>
{
	buf: &'a mut [u8],
}
struct DirEnts<'a>
{
	cluster: DirCluster<'a>,
	ofs: usize,
}

/// Directory entry returned by the DirEnts iterator
enum DirEnt {
	End,
	Empty,
	Short(DirEntShort),
	Long(DirEntLong),
}
struct DirEntShort {
	/// NUL-padded string with extention joined
	name: [u8; 11+1],
	cluster: u32,
	size: u32,
	attributes: u8,
	//creation_time: ::kernel::time::Timestamp,
	//modified_time: ::kernel::time::Timestamp,
	//accessed_time: ::kernel::time::Timestamp,
}
struct DirEntLong {
	id: u8,
	_type: u8,
	chars: [u16; 13],
}

impl DirNode {
	pub fn new(fs: &super::Filesystem, start_cluster: u32) -> DirNode {
		DirNode {
			fs: fs.inner.borrow(),
			start_cluster: start_cluster,
		}
	}
}
impl RootDirNode {
	pub fn new(fs: &super::Filesystem) -> RootDirNode {
		RootDirNode {
			fs: fs.inner.borrow(),
		}
	}
}

impl node::NodeBase for DirNode {
	fn get_id(&self) -> node::InodeId {
		todo!("")
	}
}
impl node::NodeBase for RootDirNode {
	fn get_id(&self) -> node::InodeId {
		todo!("")
	}
}

impl node::Dir for DirNode {
	fn lookup(&self, name: &ByteStr) -> node::Result<node::InodeId> {
		todo!("DirNode::lookup");
	}
	fn read(&self, ofs: usize, items: &mut [(node::InodeId,ByteString)]) -> node::Result<(usize,usize)> {
		todo!("DirNode::read");
	}
	fn create(&self, name: &ByteStr, nodetype: node::NodeType) -> node::Result<node::InodeId> {
		todo!("DirNode::create");
	}
	fn link(&self, name: &ByteStr, inode: node::InodeId) -> node::Result<()> {
		todo!("DirNode::link");
	}
	fn unlink(&self, name: &ByteStr) -> node::Result<()> {
		todo!("DirNode::unlink");
	}
}
impl node::Dir for RootDirNode {
	fn lookup(&self, name: &ByteStr) -> node::Result<node::InodeId> {
		todo!("DirNode::lookup");
	}
	fn read(&self, ofs: usize, items: &mut [(node::InodeId,ByteString)]) -> node::Result<(usize,usize)> {
		todo!("DirNode::read");
	}
	fn create(&self, name: &ByteStr, nodetype: node::NodeType) -> node::Result<node::InodeId> {
		todo!("DirNode::create");
	}
	fn link(&self, name: &ByteStr, inode: node::InodeId) -> node::Result<()> {
		todo!("DirNode::link");
	}
	fn unlink(&self, name: &ByteStr) -> node::Result<()> {
		todo!("DirNode::unlink");
	}
}

<commit_msg>Modules/FAT - Compiling and running<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Modules/fs_fat/dir.rs
use kernel::prelude::*;
use kernel::lib::mem::aref::ArefBorrow;
use kernel::vfs::{self,node};
use kernel::lib::byte_str::{ByteStr,ByteString};

pub type Filesystem = super::Filesystem;

pub struct DirNode
{
	fs: ArefBorrow<super::FilesystemInner>,
	start_cluster: u32,
	// - Uses the cluster chain
}
pub struct RootDirNode
{
	fs: ArefBorrow<super::FilesystemInner>,
}

struct DirCluster<'a>
{
	buf: &'a mut [u8],
}
struct DirEnts<'a>
{
	cluster: DirCluster<'a>,
	ofs: usize,
}

/// Directory entry returned by the DirEnts iterator
enum DirEnt {
	End,
	Empty,
	Short(DirEntShort),
	Long(DirEntLong),
}
struct DirEntShort {
	/// NUL-padded string with extention joined
	name: [u8; 11+1],
	cluster: u32,
	size: u32,
	attributes: u8,
	//creation_time: ::kernel::time::Timestamp,
	//modified_time: ::kernel::time::Timestamp,
	//accessed_time: ::kernel::time::Timestamp,
}
struct DirEntLong {
	id: u8,
	_type: u8,
	chars: [u16; 13],
}

impl DirNode {
	pub fn new(fs: &Filesystem, start_cluster: u32) -> DirNode {
		DirNode {
			fs: fs.inner.borrow(),
			start_cluster: start_cluster,
		}
	}
}
impl RootDirNode {
	pub fn new(fs: &Filesystem) -> RootDirNode {
		RootDirNode {
			fs: fs.inner.borrow(),
		}
	}
}

impl node::NodeBase for DirNode {
	fn get_id(&self) -> node::InodeId {
		todo!("")
	}
}
impl node::NodeBase for RootDirNode {
	fn get_id(&self) -> node::InodeId {
		todo!("")
	}
}

impl node::Dir for DirNode {
	fn lookup(&self, name: &ByteStr) -> node::Result<node::InodeId> {
		todo!("DirNode::lookup");
	}
	fn read(&self, ofs: usize, items: &mut [(node::InodeId,ByteString)]) -> node::Result<(usize,usize)> {
		todo!("DirNode::read");
	}
	fn create(&self, name: &ByteStr, nodetype: node::NodeType) -> node::Result<node::InodeId> {
		todo!("DirNode::create");
	}
	fn link(&self, name: &ByteStr, inode: node::InodeId) -> node::Result<()> {
		todo!("DirNode::link");
	}
	fn unlink(&self, name: &ByteStr) -> node::Result<()> {
		todo!("DirNode::unlink");
	}
}
impl node::Dir for RootDirNode {
	fn lookup(&self, name: &ByteStr) -> node::Result<node::InodeId> {
		todo!("DirNode::lookup");
	}
	fn read(&self, ofs: usize, items: &mut [(node::InodeId,ByteString)]) -> node::Result<(usize,usize)> {
		todo!("DirNode::read");
	}
	fn create(&self, name: &ByteStr, nodetype: node::NodeType) -> node::Result<node::InodeId> {
		todo!("DirNode::create");
	}
	fn link(&self, name: &ByteStr, inode: node::InodeId) -> node::Result<()> {
		todo!("DirNode::link");
	}
	fn unlink(&self, name: &ByteStr) -> node::Result<()> {
		todo!("DirNode::unlink");
	}
}

<|endoftext|>


<commit_before>use super::ipv4_header::{IPv4Header, Protocol};
use super::tcp_header::TCPHeader;
use super::transport_header::TransportHeader;
use super::udp_header::UDPHeader;

pub const MAX_PACKET_LENGTH: usize = 1 << 16;

pub struct IPv4Packet<'a> {
    raw: &'a mut [u8],
    ipv4_header: IPv4Header,
    transport_header: Option<TransportHeader>,
}

impl<'a> IPv4Packet<'a> {
    pub fn parse(raw: &'a mut [u8]) -> Self {
        let ipv4_header = IPv4Header::parse(raw);
        let transport_header = {
            let payload = &raw[ipv4_header.header_length() as usize..];
            TransportHeader::parse(ipv4_header.protocol(), payload)
        };
        Self {
            raw: raw,
            ipv4_header: ipv4_header,
            transport_header: transport_header,
        }
    }

    pub fn new(raw: &'a mut [u8], ipv4_header: IPv4Header, transport_header: TransportHeader) -> Self {
        Self {
            raw: raw,
            ipv4_header: ipv4_header,
            transport_header: Some(transport_header),
        }
    }

    pub fn raw(&self) -> &[u8] {
        self.raw
    }

    pub fn raw_mut(&mut self) -> &mut [u8] {
        self.raw
    }

    pub fn ipv4_header(&self) -> &IPv4Header {
        &self.ipv4_header
    }

    pub fn ipv4_header_mut(&mut self) -> &mut IPv4Header {
        &mut self.ipv4_header
    }

    pub fn transport_header(&self) -> &Option<TransportHeader> {
        &self.transport_header
    }

    pub fn transport_header_mut(&mut self) -> &mut Option<TransportHeader> {
        &mut self.transport_header
    }

    pub fn is_valid(&self) -> bool {
        self.transport_header.is_some()
    }

    pub fn length(&self) -> u16 {
        self.ipv4_header.total_length()
    }

    pub fn payload_index(&self) -> Option<u16> {
        if let Some(ref transport_header) = self.transport_header {
            Some(self.ipv4_header.header_length() as u16 + transport_header.header_length() as u16)
        } else {
            None
        }
    }

    pub fn payload_length(&self) -> Option<u16> {
        if let Some(payload_index) = self.payload_index() {
            Some(self.length() - payload_index)
        } else {
            None
        }
    }

    pub fn payload(&self) -> &[u8] {
        &self.raw[self.payload_index().unwrap() as usize..]
    }

    pub fn compute_checksums(&mut self) {
        self.ipv4_header.compute_checksum(self.raw);
        let mut transport = self.transport_header.as_mut().expect("No known transport header");
        transport.compute_checksum(self.raw, &self.ipv4_header);
    }

    pub fn swap_source_and_destination(&mut self) {
        self.ipv4_header.swap_source_and_destination(&mut self.raw);
        if let Some(ref mut transport_header) = self.transport_header {
            let raw_payload = &mut self.raw[self.ipv4_header.header_length() as usize..];
            transport_header.swap_source_and_destination(raw_payload);
        }
    }
}

<commit_msg>IPv4Packet slice length<commit_after>use super::ipv4_header::{IPv4Header, Protocol};
use super::tcp_header::TCPHeader;
use super::transport_header::TransportHeader;
use super::udp_header::UDPHeader;

pub const MAX_PACKET_LENGTH: usize = 1 << 16;

pub struct IPv4Packet<'a> {
    raw: &'a mut [u8],
    ipv4_header: IPv4Header,
    transport_header: Option<TransportHeader>,
}

impl<'a> IPv4Packet<'a> {
    pub fn parse(raw: &'a mut [u8]) -> Self {
        let ipv4_header = IPv4Header::parse(raw);
        let transport_header = {
            let payload = &raw[ipv4_header.header_length() as usize..];
            TransportHeader::parse(ipv4_header.protocol(), payload)
        };
        Self {
            raw: &mut raw[..ipv4_header.total_length() as usize],
            ipv4_header: ipv4_header,
            transport_header: transport_header,
        }
    }

    pub fn new(raw: &'a mut [u8], ipv4_header: IPv4Header, transport_header: TransportHeader) -> Self {
        Self {
            raw: raw,
            ipv4_header: ipv4_header,
            transport_header: Some(transport_header),
        }
    }

    pub fn raw(&self) -> &[u8] {
        self.raw
    }

    pub fn raw_mut(&mut self) -> &mut [u8] {
        self.raw
    }

    pub fn ipv4_header(&self) -> &IPv4Header {
        &self.ipv4_header
    }

    pub fn ipv4_header_mut(&mut self) -> &mut IPv4Header {
        &mut self.ipv4_header
    }

    pub fn transport_header(&self) -> &Option<TransportHeader> {
        &self.transport_header
    }

    pub fn transport_header_mut(&mut self) -> &mut Option<TransportHeader> {
        &mut self.transport_header
    }

    pub fn is_valid(&self) -> bool {
        self.transport_header.is_some()
    }

    pub fn length(&self) -> u16 {
        self.ipv4_header.total_length()
    }

    pub fn payload_index(&self) -> Option<u16> {
        if let Some(ref transport_header) = self.transport_header {
            Some(self.ipv4_header.header_length() as u16 + transport_header.header_length() as u16)
        } else {
            None
        }
    }

    pub fn payload_length(&self) -> Option<u16> {
        if let Some(payload_index) = self.payload_index() {
            Some(self.length() - payload_index)
        } else {
            None
        }
    }

    pub fn payload(&self) -> &[u8] {
        &self.raw[self.payload_index().unwrap() as usize..]
    }

    pub fn compute_checksums(&mut self) {
        self.ipv4_header.compute_checksum(self.raw);
        let mut transport = self.transport_header.as_mut().expect("No known transport header");
        transport.compute_checksum(self.raw, &self.ipv4_header);
    }

    pub fn swap_source_and_destination(&mut self) {
        self.ipv4_header.swap_source_and_destination(&mut self.raw);
        if let Some(ref mut transport_header) = self.transport_header {
            let raw_payload = &mut self.raw[self.ipv4_header.header_length() as usize..];
            transport_header.swap_source_and_destination(raw_payload);
        }
    }
}

<|endoftext|>


<commit_before>use std::f64;
use std::f64::consts::PI;

use rand::{Rand, Rng};

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 50.,
            Two => 100.,
            Three => 150.,
            Four => 200.,
            Five => 250.,
            Six => 300.,
            Seven => 350.,
            Eight => 400.,
            Nine => 450.,
            Ten => 500.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => 0.7 * PI,
            Two => 0.9 * PI,
            Three => 1.1 * PI,
            Four => 1.3 * PI,
            Five =>  1.5 * PI,
            Six => 1.8 * PI,
            Seven => 2.1 * PI,
            Eight => 2.4 * PI,
            Nine => 2.7 * PI,
            Ten => 3.0 * PI,
            Instant => f64::INFINITY,
        })
    }
}

impl Rand for Speed {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        (rng.gen::<i32>() % 10).into()
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Eight,
            "fastest" => Ten,
            "instant" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest', 'instant'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<commit_msg>Increasing rotation speed<commit_after>use std::f64;
use std::f64::consts::PI;

use rand::{Rand, Rng};

use radians::Radians;
use {Distance};

/// Represents the various supported speeds that the turtle can move at
///
/// See [`Turtle::set_speed` method](struct.Turtle.html#method.set_speed) for more information.
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum Speed {
    One,
    Two,
    Three,
    Four,
    Five,
    Six,
    Seven,
    Eight,
    Nine,
    Ten,
    Instant,
}

impl Speed {
    /// Converts a speed to its value as pixels per second
    pub fn to_absolute(self) -> Distance {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        match self {
            One => 50.,
            Two => 100.,
            Three => 150.,
            Four => 200.,
            Five => 250.,
            Six => 300.,
            Seven => 350.,
            Eight => 400.,
            Nine => 450.,
            Ten => 500.,
            Instant => f64::INFINITY,
        }
    }

    /// Converts a speed to its value as radians per second
    pub fn to_rotation(self) -> Radians {
        use self::Speed::*;
        // Arbitrary values that can be tweaked
        // Just make sure to keep invariants like Five > Three, etc.
        Radians::from_radians_value(match self {
            One => 0.7 * PI,
            Two => 0.9 * PI,
            Three => 1.1 * PI,
            Four => 1.3 * PI,
            Five =>  1.5 * PI,
            Six => 2.0 * PI,
            Seven => 2.5 * PI,
            Eight => 3.0 * PI,
            Nine => 3.5 * PI,
            Ten => 6.0 * PI,
            Instant => f64::INFINITY,
        })
    }
}

impl Rand for Speed {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        (rng.gen::<i32>() % 10).into()
    }
}

impl<'a> From<&'a str> for Speed {
    fn from(s: &'a str) -> Self {
        use Speed::*;

        match s {
            "slowest" => One,
            "slow" => Three,
            "normal" => Six,
            "fast" => Eight,
            "fastest" => Ten,
            "instant" => Instant,
            _ => panic!("Invalid speed specified, use one of the words: 'slowest', 'slow', 'normal', 'fast', 'fastest', 'instant'"),
        }
    }
}

impl From<i32> for Speed {
    fn from(n: i32) -> Self {
        use Speed::*;

        match n {
            1 => One,
            2 => Two,
            3 => Three,
            4 => Four,
            5 => Five,
            6 => Six,
            7 => Seven,
            8 => Eight,
            9 => Nine,
            10 => Ten,
            _ => Instant,
        }
    }
}
<|endoftext|>


<commit_before>use eventual::Async;
use protobuf::{self, Message};

use util;
use session::Session;
use util::SpotifyId;
use util::version::version_string;
use mercury::{MercuryRequest, MercuryMethod};
use player::{Player, PlayerState};

use std::sync::{Mutex, Arc};
use std::collections::HashMap;

use protocol;
pub use protocol::spirc::{PlayStatus, MessageType};

pub struct SpircManager(Arc<Mutex<SpircInternal>>);

struct SpircInternal {
    player: Player,
    session: Session,

    seq_nr: u32,

    name: String,
    ident: String,
    device_type: u8,
    can_play: bool,

    repeat: bool,
    shuffle: bool,

    is_active: bool,
    became_active_at: i64,

    last_command_ident: String,
    last_command_msgid: u32,

    tracks: Vec<SpotifyId>,
    index: u32,

    devices: HashMap<String, String>,
}

impl SpircManager {
    pub fn new(session: Session, player: Player) -> SpircManager {
        let ident = session.device_id();
        let name = session.config().device_name.clone();

        SpircManager(Arc::new(Mutex::new(SpircInternal {
            player: player,
            session: session,

            seq_nr: 0,

            name: name,
            ident: ident,
            device_type: 5,
            can_play: true,

            repeat: false,
            shuffle: false,

            is_active: false,
            became_active_at: 0,

            last_command_ident: String::new(),
            last_command_msgid: 0,

            tracks: Vec::new(),
            index: 0,

            devices: HashMap::new(),
        })))
    }

    pub fn run(&mut self) {
        let rx = {
            let mut internal = self.0.lock().unwrap();

            let rx = internal.session.mercury_sub(internal.uri());

            internal.notify(true, None);

            // Use a weak pointer to avoid creating an Rc cycle between the player and the
            // SpircManager
            let _self = Arc::downgrade(&self.0);
            internal.player.add_observer(Box::new(move |state| {
                if let Some(_self) = _self.upgrade() {
                    let mut internal = _self.lock().unwrap();
                    internal.on_update(state);
                }
            }));

            rx
        };

        for pkt in rx {
            let data = pkt.payload.first().unwrap();
            let frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(data).unwrap();

            println!("{:?} {} {} {} {}",
                     frame.get_typ(),
                     frame.get_device_state().get_name(),
                     frame.get_ident(),
                     frame.get_seq_nr(),
                     frame.get_state_update_id());

            self.0.lock().unwrap().handle(frame);
        }
    }

    pub fn devices(&self) -> HashMap<String, String> {
        self.0.lock().unwrap().devices.clone()
    }

    pub fn send_play(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        send_cmd(&mut *internal,
                 protocol::spirc::MessageType::kMessageTypePlay,
                 Some(recipient),
                 None);
    }

    pub fn send_pause(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        send_cmd(&mut *internal,
                 protocol::spirc::MessageType::kMessageTypePause,
                 Some(recipient),
                 None);
    }

    pub fn send_prev(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        send_cmd(&mut *internal,
                 protocol::spirc::MessageType::kMessageTypePrev,
                 Some(recipient),
                 None);
    }

    pub fn send_next(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        send_cmd(&mut *internal,
                 protocol::spirc::MessageType::kMessageTypeNext,
                 Some(recipient),
                 None);
    }
}

impl SpircInternal {
    fn on_update(&mut self, player_state: &PlayerState) {
        let end_of_track = player_state.end_of_track();
        if end_of_track {
            self.index = (self.index + 1) % self.tracks.len() as u32;
            let track = self.tracks[self.index as usize];
            self.player.load(track, true, 0);
        } else {
            self.notify_with_player_state(false, None, player_state);
        }
    }

    fn handle(&mut self, mut frame: protocol::spirc::Frame) {
        if frame.get_ident() == self.ident ||
           (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) {
            return;
        }

        if frame.get_recipient().len() > 0 {
            self.last_command_ident = frame.get_ident().to_owned();
            self.last_command_msgid = frame.get_seq_nr();
        }

        if frame.has_ident() && !frame.has_goodbye() && frame.has_device_state() {
            self.devices.insert(frame.take_ident(), frame.take_device_state().take_name());
        }

        match frame.get_typ() {
            protocol::spirc::MessageType::kMessageTypeHello => {
                self.notify(false, Some(frame.get_ident()));
            }
            protocol::spirc::MessageType::kMessageTypeLoad => {
                if !self.is_active {
                    self.is_active = true;
                    self.became_active_at = util::now_ms();
                }

                self.reload_tracks(&frame);

                let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay;
                let track = self.tracks[self.index as usize];
                let position = frame.get_state().get_position_ms();
                self.player.load(track, play, position);
            }
            protocol::spirc::MessageType::kMessageTypePlay => {
                self.player.play();
            }
            protocol::spirc::MessageType::kMessageTypePause => {
                self.player.pause();
            }
            protocol::spirc::MessageType::kMessageTypeNext => {
                self.index = (self.index + 1) % self.tracks.len() as u32;
                let track = self.tracks[self.index as usize];
                self.player.load(track, true, 0);
            }
            protocol::spirc::MessageType::kMessageTypePrev => {
                self.index = (self.index - 1) % self.tracks.len() as u32;
                let track = self.tracks[self.index as usize];
                self.player.load(track, true, 0);
            }
            protocol::spirc::MessageType::kMessageTypeSeek => {
                self.player.seek(frame.get_position());
            }
            protocol::spirc::MessageType::kMessageTypeReplace => {
                self.reload_tracks(&frame);
            }
            protocol::spirc::MessageType::kMessageTypeNotify => {
                if self.is_active && frame.get_device_state().get_is_active() {
                    self.is_active = false;
                    self.player.stop();
                }

                if frame.has_ident() && frame.has_goodbye() {
                    self.devices.remove(&frame.take_ident());
                }
            }
            protocol::spirc::MessageType::kMessageTypeVolume => {
                self.player.volume(frame.get_volume() as u16);
            }
            _ => (),
        }
    }

    fn reload_tracks(&mut self, ref frame: &protocol::spirc::Frame) {
        self.index = frame.get_state().get_playing_track_index();
        self.tracks = frame.get_state()
                           .get_track()
                           .iter()
                           .filter(|track| track.has_gid())
                           .map(|track| SpotifyId::from_raw(track.get_gid()))
                           .collect();
    }

    fn notify(&mut self, hello: bool, recipient: Option<&str>) {
        send_cmd(self,
                 if hello {
                     MessageType::kMessageTypeHello
                 } else {
                     MessageType::kMessageTypeNotify
                 },
                 recipient,
                 None);
    }

    fn notify_with_player_state(&mut self,
                                hello: bool,
                                recipient: Option<&str>,
                                player_state: &PlayerState) {
        send_cmd(self,
                 if hello {
                     MessageType::kMessageTypeHello
                 } else {
                     MessageType::kMessageTypeNotify
                 },
                 recipient,
                 Some(player_state));
    }

    fn spirc_state(&self, player_state: &PlayerState) -> protocol::spirc::State {
        let (position_ms, position_measured_at) = player_state.position();

        protobuf_init!(protocol::spirc::State::new(), {
            status: player_state.status(),
            position_ms: position_ms,
            position_measured_at: position_measured_at as u64,

            playing_track_index: self.index,
            track: self.tracks.iter().map(|track| {
                protobuf_init!(protocol::spirc::TrackRef::new(), {
                    gid: track.to_raw().to_vec()
                })
            }).collect(),

            shuffle: self.shuffle,
            repeat: self.repeat,

            playing_from_fallback: true,

            last_command_ident: self.last_command_ident.clone(),
            last_command_msgid: self.last_command_msgid
        })
    }

    fn device_state(&self, player_state: &PlayerState) -> protocol::spirc::DeviceState {
        protobuf_init!(protocol::spirc::DeviceState::new(), {
            sw_version: version_string(),
            is_active: self.is_active,
            can_play: self.can_play,
            volume: player_state.volume() as u32,
            name: self.name.clone(),
            error_code: 0,
            became_active_at: if self.is_active { self.became_active_at as i64 } else { 0 },
            capabilities => [
                @{
                    typ: protocol::spirc::CapabilityType::kCanBePlayer,
                    intValue => [0]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kDeviceType,
                    intValue => [ self.device_type as i64 ]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kGaiaEqConnectId,
                    intValue => [1]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportsLogout,
                    intValue => [0]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kIsObservable,
                    intValue => [1]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kVolumeSteps,
                    intValue => [10]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportedContexts,
                    stringValue => [
                        "album".to_owned(),
                        "playlist".to_owned(),
                        "search".to_owned(),
                        "inbox".to_owned(),
                        "toplist".to_owned(),
                        "starred".to_owned(),
                        "publishedstarred".to_owned(),
                        "track".to_owned(),
                    ]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportedTypes,
                    stringValue => [
                        "audio/local".to_owned(),
                        "audio/track".to_owned(),
                        "local".to_owned(),
                        "track".to_owned(),
                    ]
                }
            ],
        })
    }

    fn uri(&self) -> String {
        format!("hm://remote/user/{}", self.session.username())
    }
}

fn send_cmd(spirc_internal: &mut SpircInternal,
            cmd: protocol::spirc::MessageType,
            recipient: Option<&str>,
            player_state: Option<&PlayerState>) {
    let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
        version: 1,
        ident: spirc_internal.ident.clone(),
        protocol_version: "2.0.0".to_owned(),
        seq_nr: { spirc_internal.seq_nr += 1; spirc_internal.seq_nr  },
        typ: cmd,
        recipient: protobuf::RepeatedField::from_vec(
            recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
        ),
    });

    if let Some(s) = player_state {
        pkt.set_device_state(spirc_internal.device_state(s));
        pkt.set_state_update_id(s.update_time() as i64);
        if spirc_internal.is_active {
            pkt.set_state(spirc_internal.spirc_state(s));
        }
    } else {
        let s = &*spirc_internal.player.state();
        pkt.set_device_state(spirc_internal.device_state(s));
        pkt.set_state_update_id(s.update_time() as i64);
        if spirc_internal.is_active {
            pkt.set_state(spirc_internal.spirc_state(s));
        }
    }

    spirc_internal.session
                  .mercury(MercuryRequest {
                      method: MercuryMethod::SEND,
                      uri: spirc_internal.uri(),
                      content_type: None,
                      payload: vec![pkt.write_to_bytes().unwrap()],
                  })
                  .fire();
}
<commit_msg>Add support for replacing tracks. Make a builder out of send_cmd.<commit_after>use eventual::Async;
use protobuf::{self, Message, RepeatedField};

use util;
use session::Session;
use util::SpotifyId;
use util::version::version_string;
use mercury::{MercuryRequest, MercuryMethod};
use player::{Player, PlayerState};

use std::sync::{Mutex, Arc};
use std::collections::HashMap;

use protocol;
pub use protocol::spirc::{PlayStatus, MessageType};

pub struct SpircManager(Arc<Mutex<SpircInternal>>);

struct SpircInternal {
    player: Player,
    session: Session,

    seq_nr: u32,

    name: String,
    ident: String,
    device_type: u8,
    can_play: bool,

    repeat: bool,
    shuffle: bool,

    is_active: bool,
    became_active_at: i64,

    last_command_ident: String,
    last_command_msgid: u32,

    tracks: Vec<SpotifyId>,
    index: u32,

    devices: HashMap<String, String>,
}

impl SpircManager {
    pub fn new(session: Session, player: Player) -> SpircManager {
        let ident = session.device_id();
        let name = session.config().device_name.clone();

        SpircManager(Arc::new(Mutex::new(SpircInternal {
            player: player,
            session: session,

            seq_nr: 0,

            name: name,
            ident: ident,
            device_type: 5,
            can_play: true,

            repeat: false,
            shuffle: false,

            is_active: false,
            became_active_at: 0,

            last_command_ident: String::new(),
            last_command_msgid: 0,

            tracks: Vec::new(),
            index: 0,

            devices: HashMap::new(),
        })))
    }

    pub fn run(&mut self) {
        let rx = {
            let mut internal = self.0.lock().unwrap();

            let rx = internal.session.mercury_sub(internal.uri());

            internal.notify(true, None);

            // Use a weak pointer to avoid creating an Rc cycle between the player and the
            // SpircManager
            let _self = Arc::downgrade(&self.0);
            internal.player.add_observer(Box::new(move |state| {
                if let Some(_self) = _self.upgrade() {
                    let mut internal = _self.lock().unwrap();
                    internal.on_update(state);
                }
            }));

            rx
        };

        for pkt in rx {
            let data = pkt.payload.first().unwrap();
            let frame = protobuf::parse_from_bytes::<protocol::spirc::Frame>(data).unwrap();

            println!("{:?} {} {} {} {}",
                     frame.get_typ(),
                     frame.get_device_state().get_name(),
                     frame.get_ident(),
                     frame.get_seq_nr(),
                     frame.get_state_update_id());

            self.0.lock().unwrap().handle(frame);
        }
    }

    pub fn devices(&self) -> HashMap<String, String> {
        self.0.lock().unwrap().devices.clone()
    }

    pub fn send_play(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        CommandSender::new(&mut *internal,
                           protocol::spirc::MessageType::kMessageTypePlay)
            .recipient(recipient)
            .send();
    }

    pub fn send_pause(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        CommandSender::new(&mut *internal,
                           protocol::spirc::MessageType::kMessageTypePause)
            .recipient(recipient)
            .send();
    }

    pub fn send_prev(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        CommandSender::new(&mut *internal,
                           protocol::spirc::MessageType::kMessageTypePrev)
            .recipient(recipient)
            .send();
    }

    pub fn send_next(&mut self, recipient: &str) {
        let mut internal = self.0.lock().unwrap();
        CommandSender::new(&mut *internal,
                           protocol::spirc::MessageType::kMessageTypeNext)
            .recipient(recipient)
            .send();
    }

    pub fn send_replace_tracks<S: AsRef<str>, I: Iterator<Item = S>>(&mut self,
                                                                     recipient: &str,
                                                                     track_ids: I) {
        let tracks: Vec<protocol::spirc::TrackRef> = track_ids.map(|i| {
                    protobuf_init!(protocol::spirc::TrackRef::new(), { gid: SpotifyId::from_base62(i.as_ref()).to_raw().to_vec()})
                })
                .collect();

        let state = protobuf_init!(protocol::spirc::State::new(), {
                    track: RepeatedField::from_vec(tracks)
                });

        let mut internal = self.0.lock().unwrap();
        CommandSender::new(&mut *internal,
                           protocol::spirc::MessageType::kMessageTypeReplace)
            .recipient(recipient)
            .state(state)
            .send();
    }
}

impl SpircInternal {
    fn on_update(&mut self, player_state: &PlayerState) {
        let end_of_track = player_state.end_of_track();
        if end_of_track {
            self.index = (self.index + 1) % self.tracks.len() as u32;
            let track = self.tracks[self.index as usize];
            self.player.load(track, true, 0);
        } else {
            self.notify_with_player_state(false, None, player_state);
        }
    }

    fn handle(&mut self, mut frame: protocol::spirc::Frame) {
        if frame.get_ident() == self.ident ||
           (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) {
            return;
        }

        if frame.get_recipient().len() > 0 {
            self.last_command_ident = frame.get_ident().to_owned();
            self.last_command_msgid = frame.get_seq_nr();
        }

        if frame.has_ident() && !frame.has_goodbye() && frame.has_device_state() {
            self.devices.insert(frame.take_ident(), frame.take_device_state().take_name());
        }

        match frame.get_typ() {
            protocol::spirc::MessageType::kMessageTypeHello => {
                self.notify(false, Some(frame.get_ident()));
            }
            protocol::spirc::MessageType::kMessageTypeLoad => {
                if !self.is_active {
                    self.is_active = true;
                    self.became_active_at = util::now_ms();
                }

                self.reload_tracks(&frame);

                let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay;
                let track = self.tracks[self.index as usize];
                let position = frame.get_state().get_position_ms();
                self.player.load(track, play, position);
            }
            protocol::spirc::MessageType::kMessageTypePlay => {
                self.player.play();
            }
            protocol::spirc::MessageType::kMessageTypePause => {
                self.player.pause();
            }
            protocol::spirc::MessageType::kMessageTypeNext => {
                self.index = (self.index + 1) % self.tracks.len() as u32;
                let track = self.tracks[self.index as usize];
                self.player.load(track, true, 0);
            }
            protocol::spirc::MessageType::kMessageTypePrev => {
                self.index = (self.index - 1) % self.tracks.len() as u32;
                let track = self.tracks[self.index as usize];
                self.player.load(track, true, 0);
            }
            protocol::spirc::MessageType::kMessageTypeSeek => {
                self.player.seek(frame.get_position());
            }
            protocol::spirc::MessageType::kMessageTypeReplace => {
                self.reload_tracks(&frame);
            }
            protocol::spirc::MessageType::kMessageTypeNotify => {
                if self.is_active && frame.get_device_state().get_is_active() {
                    self.is_active = false;
                    self.player.stop();
                }

                if frame.has_ident() && frame.has_goodbye() {
                    self.devices.remove(&frame.take_ident());
                }
            }
            protocol::spirc::MessageType::kMessageTypeVolume => {
                self.player.volume(frame.get_volume() as u16);
            }
            _ => (),
        }
    }

    fn reload_tracks(&mut self, ref frame: &protocol::spirc::Frame) {
        self.index = frame.get_state().get_playing_track_index();
        self.tracks = frame.get_state()
                           .get_track()
                           .iter()
                           .filter(|track| track.has_gid())
                           .map(|track| SpotifyId::from_raw(track.get_gid()))
                           .collect();
    }

    fn notify(&mut self, hello: bool, recipient: Option<&str>) {
        let cs = CommandSender::new(self,
                                    if hello {
                                        MessageType::kMessageTypeHello
                                    } else {
                                        MessageType::kMessageTypeNotify
                                    });
        if let Some(s) = recipient {
            cs.recipient(&s)
              .send()
        } else {
            cs.send()
        }
    }

    fn notify_with_player_state(&mut self,
                                hello: bool,
                                recipient: Option<&str>,
                                player_state: &PlayerState) {
        let cs = CommandSender::new(self,
                                    if hello {
                                        MessageType::kMessageTypeHello
                                    } else {
                                        MessageType::kMessageTypeNotify
                                    })
                     .player_state(player_state);
        if let Some(s) = recipient {
            cs.recipient(&s)
              .send()
        } else {
            cs.send()
        }
    }

    fn spirc_state(&self, player_state: &PlayerState) -> protocol::spirc::State {
        let (position_ms, position_measured_at) = player_state.position();

        protobuf_init!(protocol::spirc::State::new(), {
            status: player_state.status(),
            position_ms: position_ms,
            position_measured_at: position_measured_at as u64,

            playing_track_index: self.index,
            track: self.tracks.iter().map(|track| {
                protobuf_init!(protocol::spirc::TrackRef::new(), {
                    gid: track.to_raw().to_vec()
                })
            }).collect(),

            shuffle: self.shuffle,
            repeat: self.repeat,

            playing_from_fallback: true,

            last_command_ident: self.last_command_ident.clone(),
            last_command_msgid: self.last_command_msgid
        })
    }

    fn device_state(&self, player_state: &PlayerState) -> protocol::spirc::DeviceState {
        protobuf_init!(protocol::spirc::DeviceState::new(), {
            sw_version: version_string(),
            is_active: self.is_active,
            can_play: self.can_play,
            volume: player_state.volume() as u32,
            name: self.name.clone(),
            error_code: 0,
            became_active_at: if self.is_active { self.became_active_at as i64 } else { 0 },
            capabilities => [
                @{
                    typ: protocol::spirc::CapabilityType::kCanBePlayer,
                    intValue => [0]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kDeviceType,
                    intValue => [ self.device_type as i64 ]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kGaiaEqConnectId,
                    intValue => [1]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportsLogout,
                    intValue => [0]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kIsObservable,
                    intValue => [1]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kVolumeSteps,
                    intValue => [10]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportedContexts,
                    stringValue => [
                        "album".to_owned(),
                        "playlist".to_owned(),
                        "search".to_owned(),
                        "inbox".to_owned(),
                        "toplist".to_owned(),
                        "starred".to_owned(),
                        "publishedstarred".to_owned(),
                        "track".to_owned(),
                    ]
                },
                @{
                    typ: protocol::spirc::CapabilityType::kSupportedTypes,
                    stringValue => [
                        "audio/local".to_owned(),
                        "audio/track".to_owned(),
                        "local".to_owned(),
                        "track".to_owned(),
                    ]
                }
            ],
        })
    }

    fn uri(&self) -> String {
        format!("hm://remote/user/{}", self.session.username())
    }
}

struct CommandSender<'a> {
    spirc_internal: &'a mut SpircInternal,
    cmd: protocol::spirc::MessageType,
    recipient: Option<&'a str>,
    player_state: Option<&'a PlayerState>,
    state: Option<protocol::spirc::State>,
}

impl<'a> CommandSender<'a> {
    fn new(spirc_internal: &'a mut SpircInternal,
           cmd: protocol::spirc::MessageType)
           -> CommandSender {
        CommandSender {
            spirc_internal: spirc_internal,
            cmd: cmd,
            recipient: None,
            player_state: None,
            state: None,
        }
    }

    fn recipient(mut self, r: &'a str) -> CommandSender {
        self.recipient = Some(r);
        self
    }

    fn player_state(mut self, s: &'a PlayerState) -> CommandSender {
        self.player_state = Some(s);
        self
    }

    fn state(mut self, s: protocol::spirc::State) -> CommandSender<'a> {
        self.state = Some(s);
        self
    }

    fn send(self) {
        let mut pkt = protobuf_init!(protocol::spirc::Frame::new(), {
            version: 1,
            ident: self.spirc_internal.ident.clone(),
            protocol_version: "2.0.0".to_owned(),
            seq_nr: { self.spirc_internal.seq_nr += 1; self.spirc_internal.seq_nr  },
            typ: self.cmd,
            recipient: protobuf::RepeatedField::from_vec(
                self.recipient.map(|r| vec![r.to_owned()] ).unwrap_or(vec![])
                ),
        });

        if let Some(s) = self.player_state {
            pkt.set_device_state(self.spirc_internal.device_state(s));
            pkt.set_state_update_id(s.update_time() as i64);
            if self.spirc_internal.is_active {
                pkt.set_state(self.spirc_internal.spirc_state(s));
            }
        } else {
            let s = &*self.spirc_internal.player.state();
            pkt.set_device_state(self.spirc_internal.device_state(s));
            pkt.set_state_update_id(s.update_time() as i64);
            if self.spirc_internal.is_active {
                pkt.set_state(self.spirc_internal.spirc_state(s));
            }
        }

        if let Some(s) = self.state {
            pkt.set_state(s);
        }

        self.spirc_internal
            .session
            .mercury(MercuryRequest {
                method: MercuryMethod::SEND,
                uri: self.spirc_internal.uri(),
                content_type: None,
                payload: vec![pkt.write_to_bytes().unwrap()],
            })
            .fire();
    }
}
<|endoftext|>


<commit_before>use super::job_queue::*;
use super::queue_state::*;
use super::core::*;
use super::active_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::mem;
use std::sync::*;
use std::pin::{Pin};

///
/// The possible states of a future result
///
enum FutureResultState<T> {
    None,
    Some(T),
    ReturnedViaFuture
}

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: FutureResultState<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// The scheduler core that this future belongs to
    scheduler: Arc<SchedulerCore>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> FutureResultState<T> {
    ///
    /// Returns true if no result has ever been generated for this future
    ///
    fn is_none(&self) -> bool {
        match self {
            FutureResultState::None                 => true,
            FutureResultState::Some(_)              => false,
            FutureResultState::ReturnedViaFuture    => false
        }
    }

    ///
    /// If a result has been generated by this future and has not previously been taken, returns it. Panics if the result has already
    /// been returned and is no longer available.
    ///
    fn take(&mut self) -> Option<T> {
        // Move the value out of this object
        let mut new_value = FutureResultState::ReturnedViaFuture;
        mem::swap(self, &mut new_value);

        // Return it if it contains a value
        match new_value {
            FutureResultState::None                 => { *self = FutureResultState::None; None },
            FutureResultState::ReturnedViaFuture    => { *self = FutureResultState::ReturnedViaFuture; panic!("Future result has already been returned") },
            FutureResultState::Some(value)          => { Some(value) }
        }
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // If no result has been generated, then mark the future as canceled
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = FutureResultState::Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // Set the result
            future_result.result = FutureResultState::Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}

///
/// Possible actions we can take based on the state of the signal for the future
///
enum SchedulerAction<T> {
    /// Queue is running elsewhere: we should wait for it to reach the point where the future's result is available
    WaitForCompletion,

    /// Future has already completed: we should return the value to sender
    ReturnValue(T),

    /// We've claimed the 'running' state of the queue and should drain it
    DrainQueue,

    /// The queue has panicked
    Panic
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: FutureResultState::None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:      Arc::clone(queue),
            scheduler:  core,
            result:     Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }

    ///
    /// We moved the queue into the running state and need to drain it until we've got a result
    ///
    fn drain_queue(&mut self, context: &mut task::Context) -> task::Poll<Result<T, oneshot::Canceled>> {
        debug_assert!(self.queue.core.lock().expect("JobQueue core lock").state == QueueState::Running);

        // Set the queue as active
        let _active     = ActiveQueue { queue: &*self.queue };
        let mut result;

        // While there is no result, run a job from the queue
        loop {
            // See if the result has arrived yet
            result = self.result.lock().unwrap().result.take();
            if !result.is_none() { break; }

            // Run the next job in the queue
            if let Some(mut job) = self.queue.dequeue() {
                // Queue is running
                debug_assert!(self.queue.core.lock().unwrap().state == QueueState::Running);

                let poll_result = job.run(context);

                match poll_result {
                    task::Poll::Ready(())   => {
                        // Keep running jobs and checking the results if ready
                    },

                    task::Poll::Pending     => {
                        // Need to wait until we're polled again
                        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForPoll;
                        return task::Poll::Pending;
                    }
                }
            } else {
                // Queue is empty and our result hasn't arrived yet?!

                // Assume the future will resolve eventually: move the queue in to the background
                self.result.lock().unwrap().waker = Some(context.waker().clone());

                // Reschedule the queue
                self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
                self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

                return task::Poll::Pending;
            }
        }

        // Reschedule the queue if there are any events left pending
        // Note: the queue is already pending when we start running events from it here.
        // This means it'll get dequeued by a thread eventually: maybe while it's running
        // here. As we've set the queue state to running while we're busy, the thread won't
        // start the queue while it's already running.
        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
        self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

        // Result must be available by this point
        task::Poll::Ready(result.unwrap())
    }
}

impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(mut self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        // Lock the result and determine which action to take
        let next_action = {
            let mut future_result = self.result.lock().unwrap();

            if let Some(result) = future_result.result.take() {
                // The result is available: we should return it immediately
                SchedulerAction::ReturnValue(result)
            } else {
                // If the queue is idle when this is called, we need to schedule this task on this thread rather than one owned by the background process
                let run_action = {
                    let mut core = self.queue.core.lock().expect("JobQueue core lock");

                    match core.state {
                        QueueState::Suspended           => SchedulerAction::WaitForCompletion,
                        QueueState::Suspending          => SchedulerAction::WaitForCompletion,
                        QueueState::Running             => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForWake      => SchedulerAction::WaitForCompletion,
                        QueueState::AwokenWhileRunning  => SchedulerAction::WaitForCompletion,
                        QueueState::Panicked            => SchedulerAction::Panic,
                        QueueState::WaitingForPoll      => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Pending             => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Idle                => { core.state = QueueState::Running; SchedulerAction::DrainQueue }
                    }
                };

                if let SchedulerAction::WaitForCompletion = run_action {
                    // Wake us up when the future is available
                    future_result.waker = Some(context.waker().clone());
                }

                run_action
            }
        };

        match next_action {
            SchedulerAction::WaitForCompletion  => task::Poll::Pending,
            SchedulerAction::ReturnValue(value) => task::Poll::Ready(value),
            SchedulerAction::DrainQueue         => self.drain_queue(context),
            SchedulerAction::Panic              => panic!("Cannot schedule jobs on a panicked queue"),
        }
    }
}
<commit_msg>Job needs to be requeued if we get a 'pending' poll state from it<commit_after>use super::job_queue::*;
use super::queue_state::*;
use super::core::*;
use super::active_queue::*;

use futures::prelude::*;
use futures::channel::oneshot;
use futures::task;

use std::mem;
use std::sync::*;
use std::pin::{Pin};

///
/// The possible states of a future result
///
enum FutureResultState<T> {
    None,
    Some(T),
    ReturnedViaFuture
}

///
/// Signalling structure used to return the result of a scheduler future
///
struct SchedulerFutureResult<T> {
    /// The result of the future, or None if it has not been generated yet
    result: FutureResultState<Result<T, oneshot::Canceled>>,

    /// The waker to be called when the future is available
    waker: Option<task::Waker>
}

///
/// Wrapper that cancels the future if it is dropped before it is signalled
///
pub (super) struct SchedulerFutureSignaller<T>(Arc<Mutex<SchedulerFutureResult<T>>>);

///
/// Future representing a task pending on a scheduler
///
/// If polled when no threads are available, this future will run synchronously on the current thread
/// (stealing its execution time rather than blocking)
///
pub struct SchedulerFuture<T> {
    /// The queue which will eventually evaluate the result of this future
    queue: Arc<JobQueue>,

    /// The scheduler core that this future belongs to
    scheduler: Arc<SchedulerCore>,

    /// A container for the result of this scheduler future
    result: Arc<Mutex<SchedulerFutureResult<T>>>
}

impl<T> FutureResultState<T> {
    ///
    /// Returns true if no result has ever been generated for this future
    ///
    fn is_none(&self) -> bool {
        match self {
            FutureResultState::None                 => true,
            FutureResultState::Some(_)              => false,
            FutureResultState::ReturnedViaFuture    => false
        }
    }

    ///
    /// If a result has been generated by this future and has not previously been taken, returns it. Panics if the result has already
    /// been returned and is no longer available.
    ///
    fn take(&mut self) -> Option<T> {
        // Move the value out of this object
        let mut new_value = FutureResultState::ReturnedViaFuture;
        mem::swap(self, &mut new_value);

        // Return it if it contains a value
        match new_value {
            FutureResultState::None                 => { *self = FutureResultState::None; None },
            FutureResultState::ReturnedViaFuture    => { *self = FutureResultState::ReturnedViaFuture; panic!("Future result has already been returned") },
            FutureResultState::Some(value)          => { Some(value) }
        }
    }
}

impl<T> Drop for SchedulerFutureSignaller<T> {
    fn drop(&mut self) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // If no result has been generated, then mark the future as canceled
            if future_result.result.is_none() {
                // Mark the future as canceled
                future_result.result = FutureResultState::Some(Err(oneshot::Canceled));

                // Wake up anything that was polling it
                let waker = future_result.waker.take();
                waker
            } else {
                // Result is already set, so don't wake anything up
                None
            }
        };

        // If we need to wake the future, then do so here (note that we're outside of the lock when we do this)
        waker.map(|waker| waker.wake());
    }
}

impl<T> SchedulerFutureSignaller<T> {
    ///
    /// Signals that the result of the calculation is available
    ///
    pub (super) fn signal(self, result: T) {
        let waker = {
            let mut future_result = self.0.lock().unwrap();

            // Set the result
            future_result.result = FutureResultState::Some(Ok(result));

            // Retrieve the waker
            future_result.waker.take()
        };

        // If we retrieved a waker from the result, wake it up
        waker.map(|waker| waker.wake());
    }
}

///
/// Possible actions we can take based on the state of the signal for the future
///
enum SchedulerAction<T> {
    /// Queue is running elsewhere: we should wait for it to reach the point where the future's result is available
    WaitForCompletion,

    /// Future has already completed: we should return the value to sender
    ReturnValue(T),

    /// We've claimed the 'running' state of the queue and should drain it
    DrainQueue,

    /// The queue has panicked
    Panic
}

impl<T> SchedulerFuture<T> {
    ///
    /// Creates a new scheduler future and the result needed to signal it
    ///
    pub (super) fn new(queue: &Arc<JobQueue>, core: Arc<SchedulerCore>) -> (SchedulerFuture<T>, SchedulerFutureSignaller<T>) {
        // Create an unfinished result
        let result = SchedulerFutureResult {
            result: FutureResultState::None,
            waker:  None
        };
        let result = Arc::new(Mutex::new(result));

        // Insert into a future
        let future = SchedulerFuture {
            queue:      Arc::clone(queue),
            scheduler:  core,
            result:     Arc::clone(&result)
        };

        (future, SchedulerFutureSignaller(result))
    }

    ///
    /// We moved the queue into the running state and need to drain it until we've got a result
    ///
    fn drain_queue(&mut self, context: &mut task::Context) -> task::Poll<Result<T, oneshot::Canceled>> {
        debug_assert!(self.queue.core.lock().expect("JobQueue core lock").state == QueueState::Running);

        // Set the queue as active
        let _active     = ActiveQueue { queue: &*self.queue };
        let mut result;

        // While there is no result, run a job from the queue
        loop {
            // See if the result has arrived yet
            result = self.result.lock().unwrap().result.take();
            if !result.is_none() { break; }

            // Run the next job in the queue
            if let Some(mut job) = self.queue.dequeue() {
                // Queue is running
                debug_assert!(self.queue.core.lock().unwrap().state == QueueState::Running);

                let poll_result = job.run(context);

                match poll_result {
                    task::Poll::Ready(())   => {
                        // Keep running jobs and checking the results if ready
                    },

                    task::Poll::Pending     => {
                        // Requeue the job
                        self.queue.requeue(job);

                        // Need to wait until we're polled again
                        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::WaitingForPoll;
                        return task::Poll::Pending;
                    }
                }
            } else {
                // Queue is empty and our result hasn't arrived yet?!

                // Assume the future will resolve eventually: move the queue in to the background
                self.result.lock().unwrap().waker = Some(context.waker().clone());

                // Reschedule the queue
                self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
                self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

                return task::Poll::Pending;
            }
        }

        // Reschedule the queue if there are any events left pending
        // Note: the queue is already pending when we start running events from it here.
        // This means it'll get dequeued by a thread eventually: maybe while it's running
        // here. As we've set the queue state to running while we're busy, the thread won't
        // start the queue while it's already running.
        self.queue.core.lock().expect("JobQueue core lock").state = QueueState::Idle;
        self.scheduler.reschedule_queue(&self.queue, Arc::clone(&self.scheduler));

        // Result must be available by this point
        task::Poll::Ready(result.unwrap())
    }
}

impl<T> Future for SchedulerFuture<T> {
    type Output = Result<T, oneshot::Canceled>;

    ///
    /// Polls this future
    ///
    fn poll(mut self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll<Self::Output> {
        // Lock the result and determine which action to take
        let next_action = {
            let mut future_result = self.result.lock().unwrap();

            if let Some(result) = future_result.result.take() {
                // The result is available: we should return it immediately
                SchedulerAction::ReturnValue(result)
            } else {
                // If the queue is idle when this is called, we need to schedule this task on this thread rather than one owned by the background process
                let run_action = {
                    let mut core = self.queue.core.lock().expect("JobQueue core lock");

                    match core.state {
                        QueueState::Suspended           => SchedulerAction::WaitForCompletion,
                        QueueState::Suspending          => SchedulerAction::WaitForCompletion,
                        QueueState::Running             => SchedulerAction::WaitForCompletion,
                        QueueState::WaitingForWake      => SchedulerAction::WaitForCompletion,
                        QueueState::AwokenWhileRunning  => SchedulerAction::WaitForCompletion,
                        QueueState::Panicked            => SchedulerAction::Panic,
                        QueueState::WaitingForPoll      => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Pending             => { core.state = QueueState::Running; SchedulerAction::DrainQueue },
                        QueueState::Idle                => { core.state = QueueState::Running; SchedulerAction::DrainQueue }
                    }
                };

                if let SchedulerAction::WaitForCompletion = run_action {
                    // Wake us up when the future is available
                    future_result.waker = Some(context.waker().clone());
                }

                run_action
            }
        };

        match next_action {
            SchedulerAction::WaitForCompletion  => task::Poll::Pending,
            SchedulerAction::ReturnValue(value) => task::Poll::Ready(value),
            SchedulerAction::DrainQueue         => self.drain_queue(context),
            SchedulerAction::Panic              => panic!("Cannot schedule jobs on a panicked queue"),
        }
    }
}
<|endoftext|>