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

use std::net::{SocketAddr, IpAddr, Ipv4Addr, UdpSocket};
use std::os::unix::io::AsRawFd;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::io::{Write, Read};
use mio;
use dns_lookup;
use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use tuntap;
use utils;
use snap;

pub static INTERRUPTED: AtomicBool = ATOMIC_BOOL_INIT;

#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
enum Message {
    Request,
    Response { id: u8 },
    Data { id: u8, data: Vec<u8> },
}

const TUN: mio::Token = mio::Token(0);
const SOCK: mio::Token = mio::Token(1);

fn resolve(host: &str) -> Result<IpAddr, String> {
    let mut ip_list = try!(dns_lookup::lookup_host(host).map_err(|_| "dns_lookup::lookup_host"));
    let ip = ip_list.next().unwrap().unwrap();
    Ok(ip)
}

fn initiate(socket: &UdpSocket, addr: &SocketAddr) -> Result<u8, String> {
    let req_msg = Message::Request;
    let encoded_req_msg: Vec<u8> = try!(encode(&req_msg, SizeLimit::Infinite)
        .map_err(|e| e.to_string()));

    let mut remaining_len = encoded_req_msg.len();
    while remaining_len > 0 {
        let sent_bytes = try!(socket.send_to(&encoded_req_msg, addr)
            .map_err(|e| e.to_string()));
        remaining_len -= sent_bytes;
    }
    info!("Request sent to {}.", addr);

    let mut buf = [0u8; 1600];
    let (len, recv_addr) = try!(socket.recv_from(&mut buf).map_err(|e| e.to_string()));
    assert_eq!(&recv_addr, addr);
    info!("Response received from {}.", addr);

    let resp_msg: Message = try!(decode(&buf[0..len]).map_err(|e| e.to_string()));
    match resp_msg {
        Message::Response { id } => Ok(id),
        _ => Err(format!("Invalid message {:?} from {}", resp_msg, addr)),
    }
}

pub fn connect(host: &str, port: u16, default: bool) {
    info!("Working in client mode.");
    let remote_ip = resolve(host).unwrap();
    let remote_addr = SocketAddr::new(remote_ip, port);
    info!("Remote server: {}", remote_addr);

    let local_addr: SocketAddr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
    let socket = UdpSocket::bind(&local_addr).unwrap();

    let id = initiate(&socket, &remote_addr).unwrap();
    info!("Session established. Assigned IP address: 10.10.10.{}.", id);

    info!("Bringing up TUN device tun1.");
    let mut tun = tuntap::Tun::create(1);
    let tun_rawfd = tun.as_raw_fd();
    tun.up(id);
    let tunfd = mio::unix::EventedFd(&tun_rawfd);
    info!("TUN device tun1 initialized. Internal IP: 10.10.10.{}/24.",
          id);

    let poll = mio::Poll::new().unwrap();
    info!("Setting up TUN device for polling.");
    poll.register(&tunfd, TUN, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    info!("Setting up socket for polling.");
    let sockfd = mio::udp::UdpSocket::from_socket(socket).unwrap();
    poll.register(&sockfd, SOCK, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    let mut events = mio::Events::with_capacity(1024);
    let mut buf = [0u8; 1600];

    // RAII so ignore unused variable warning
    let _gw = if default {
        Some(utils::DefaultGateway::create("10.10.10.1", &format!("{}", remote_addr.ip())))
    } else {
        None
    };

    let mut encoder = snap::Encoder::new();
    let mut decoder = snap::Decoder::new();

    info!("Ready for transmission.");

    loop {
        if INTERRUPTED.load(Ordering::Relaxed) {
            break;
        }

        poll.poll(&mut events, None).unwrap();

        for event in events.iter() {
            match event.token() {
                SOCK => {
                    let (len, addr) = sockfd.recv_from(&mut buf).unwrap().unwrap();
                    let msg: Message = decode(&buf[0..len]).unwrap();
                    match msg {
                        Message::Request |
                        Message::Response { id: _ } => {
                            panic!("Invalid message {:?} from {}", msg, addr);
                        }
                        Message::Data { id: _, data } => {
                            let decompressed_data = decoder.decompress_vec(&data).unwrap();
                            let data_len = decompressed_data.len();
                            let sent_len = tun.write(&decompressed_data).unwrap();
                            assert_eq!(sent_len, data_len);
                        }
                    }
                }
                TUN => {
                    let len: usize = tun.read(&mut buf).unwrap();
                    let data = &buf[0..len];

                    let msg = Message::Data {
                        id: id,
                        data: encoder.compress_vec(data).unwrap(),
                    };
                    let encoded_msg = encode(&msg, SizeLimit::Infinite).unwrap();
                    sockfd.send_to(&encoded_msg, &remote_addr).unwrap().unwrap();
                }
                _ => unreachable!(),
            }
        }
    }
}

pub fn serve(port: u16) {
    if cfg!(not(target_os = "linux")) {
        panic!("Server mode is only available in Linux!");
    }
    info!("Working in server mode.");

    info!("Enabling kernel's IPv4 forwarding.");
    utils::enable_ipv4_forwarding().unwrap();

    info!("Bringing up TUN device tun0.");
    let mut tun = tuntap::Tun::create(0);
    tun.up(1);

    let tun_rawfd = tun.as_raw_fd();
    let tunfd = mio::unix::EventedFd(&tun_rawfd);
    info!("TUN device tun0 initialized. Internal IP: 10.10.10.1/24.");

    let addr = format!("0.0.0.0:{}", port).parse().unwrap();
    let sockfd = mio::udp::UdpSocket::bind(&addr).unwrap();
    info!("Listening on: 0.0.0.0:{}.", port);

    let poll = mio::Poll::new().unwrap();
    poll.register(&sockfd, SOCK, mio::Ready::readable(), mio::PollOpt::level()).unwrap();
    poll.register(&tunfd, TUN, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    let mut events = mio::Events::with_capacity(1024);
    let mut available_ids: Vec<u8> = (2..254).collect();
    let mut client_map: HashMap<u8, SocketAddr> = HashMap::new();

    let mut buf = [0u8; 1600];
    let mut encoder = snap::Encoder::new();
    let mut decoder = snap::Decoder::new();
    info!("Ready for transmission.");

    loop {
        if INTERRUPTED.load(Ordering::Relaxed) {
            break;
        }

        poll.poll(&mut events, None).unwrap();

        for event in events.iter() {
            match event.token() {
                SOCK => {
                    let (len, addr) = sockfd.recv_from(&mut buf).unwrap().unwrap();
                    let msg: Message = decode(&buf[0..len]).unwrap();
                    match msg {
                        Message::Request => {
                            let client_id: u8 = available_ids.pop().unwrap();
                            client_map.insert(client_id, addr);

                            info!("Got request from {}. Assigning IP address: 10.10.10.{}.",
                                  addr,
                                  client_id);

                            let reply = Message::Response { id: client_id };
                            let encoded_reply = encode(&reply, SizeLimit::Infinite).unwrap();
                            let sent_len = sockfd.send_to(&encoded_reply, &addr).unwrap().unwrap();
                            assert_eq!(sent_len, encoded_reply.len());
                        }
                        Message::Response { id: _ } => {
                            warn!("Invalid message {:?} from {}", msg, addr)
                        }
                        Message::Data { id: _, data } => {
                            let decompressed_data = decoder.decompress_vec(&data).unwrap();
                            let data_len = decompressed_data.len();
                            let sent_len = tun.write(&decompressed_data).unwrap();
                            assert_eq!(sent_len, data_len);
                        }
                    }
                }
                TUN => {
                    let len: usize = tun.read(&mut buf).unwrap();
                    let data = &buf[0..len];
                    let client_id: u8 = data[19];

                    match client_map.get(&client_id) {
                        None => warn!("Unknown IP packet from TUN for client {}.", client_id),
                        Some(addr) => {
                            let msg = Message::Data {
                                id: client_id,
                                data: encoder.compress_vec(data).unwrap(),
                            };
                            let encoded_msg = encode(&msg, SizeLimit::Infinite).unwrap();
                            sockfd.send_to(&encoded_msg, addr).unwrap().unwrap();
                        }
                    }
                }
                _ => unreachable!(),
            }
        }
    }
}

#[test]
fn resolve_ip() {
    assert_eq!(resolve("127.0.0.1").unwrap(),
               IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
}
<commit_msg>No panic when write() and sento() is incomplete<commit_after>// Copyright 2016-2017 Chang Lan
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::net::{SocketAddr, IpAddr, Ipv4Addr, UdpSocket};
use std::os::unix::io::AsRawFd;
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering, ATOMIC_BOOL_INIT};
use std::io::{Write, Read};
use mio;
use dns_lookup;
use bincode::SizeLimit;
use bincode::rustc_serialize::{encode, decode};
use tuntap;
use utils;
use snap;

pub static INTERRUPTED: AtomicBool = ATOMIC_BOOL_INIT;

#[derive(RustcEncodable, RustcDecodable, PartialEq, Debug)]
enum Message {
    Request,
    Response { id: u8 },
    Data { id: u8, data: Vec<u8> },
}

const TUN: mio::Token = mio::Token(0);
const SOCK: mio::Token = mio::Token(1);

fn resolve(host: &str) -> Result<IpAddr, String> {
    let mut ip_list = try!(dns_lookup::lookup_host(host).map_err(|_| "dns_lookup::lookup_host"));
    let ip = ip_list.next().unwrap().unwrap();
    Ok(ip)
}

fn initiate(socket: &UdpSocket, addr: &SocketAddr) -> Result<u8, String> {
    let req_msg = Message::Request;
    let encoded_req_msg: Vec<u8> = try!(encode(&req_msg, SizeLimit::Infinite)
        .map_err(|e| e.to_string()));

    let mut remaining_len = encoded_req_msg.len();
    while remaining_len > 0 {
        let sent_bytes = try!(socket.send_to(&encoded_req_msg, addr)
            .map_err(|e| e.to_string()));
        remaining_len -= sent_bytes;
    }
    info!("Request sent to {}.", addr);

    let mut buf = [0u8; 1600];
    let (len, recv_addr) = try!(socket.recv_from(&mut buf).map_err(|e| e.to_string()));
    assert_eq!(&recv_addr, addr);
    info!("Response received from {}.", addr);

    let resp_msg: Message = try!(decode(&buf[0..len]).map_err(|e| e.to_string()));
    match resp_msg {
        Message::Response { id } => Ok(id),
        _ => Err(format!("Invalid message {:?} from {}", resp_msg, addr)),
    }
}

pub fn connect(host: &str, port: u16, default: bool) {
    info!("Working in client mode.");
    let remote_ip = resolve(host).unwrap();
    let remote_addr = SocketAddr::new(remote_ip, port);
    info!("Remote server: {}", remote_addr);

    let local_addr: SocketAddr = "0.0.0.0:0".parse::<SocketAddr>().unwrap();
    let socket = UdpSocket::bind(&local_addr).unwrap();

    let id = initiate(&socket, &remote_addr).unwrap();
    info!("Session established. Assigned IP address: 10.10.10.{}.", id);

    info!("Bringing up TUN device tun1.");
    let mut tun = tuntap::Tun::create(1);
    let tun_rawfd = tun.as_raw_fd();
    tun.up(id);
    let tunfd = mio::unix::EventedFd(&tun_rawfd);
    info!("TUN device tun1 initialized. Internal IP: 10.10.10.{}/24.",
          id);

    let poll = mio::Poll::new().unwrap();
    info!("Setting up TUN device for polling.");
    poll.register(&tunfd, TUN, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    info!("Setting up socket for polling.");
    let sockfd = mio::udp::UdpSocket::from_socket(socket).unwrap();
    poll.register(&sockfd, SOCK, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    let mut events = mio::Events::with_capacity(1024);
    let mut buf = [0u8; 1600];

    // RAII so ignore unused variable warning
    let _gw = if default {
        Some(utils::DefaultGateway::create("10.10.10.1", &format!("{}", remote_addr.ip())))
    } else {
        None
    };

    let mut encoder = snap::Encoder::new();
    let mut decoder = snap::Decoder::new();

    info!("Ready for transmission.");

    loop {
        if INTERRUPTED.load(Ordering::Relaxed) {
            break;
        }

        poll.poll(&mut events, None).unwrap();

        for event in events.iter() {
            match event.token() {
                SOCK => {
                    let (len, addr) = sockfd.recv_from(&mut buf).unwrap().unwrap();
                    let msg: Message = decode(&buf[0..len]).unwrap();
                    match msg {
                        Message::Request |
                        Message::Response { id: _ } => {
                            panic!("Invalid message {:?} from {}", msg, addr);
                        }
                        Message::Data { id: _, data } => {
                            let decompressed_data = decoder.decompress_vec(&data).unwrap();
                            let data_len = decompressed_data.len();
                            let mut sent_len = 0;
                            while sent_len < data_len {
                                sent_len += tun.write(&decompressed_data[sent_len..data_len])
                                    .unwrap();
                            }
                        }
                    }
                }
                TUN => {
                    let len: usize = tun.read(&mut buf).unwrap();
                    let data = &buf[0..len];
                    let msg = Message::Data {
                        id: id,
                        data: encoder.compress_vec(data).unwrap(),
                    };
                    let encoded_msg = encode(&msg, SizeLimit::Infinite).unwrap();
                    let data_len = encoded_msg.len();
                    let mut sent_len = 0;
                    while sent_len < data_len {
                        sent_len += sockfd.send_to(&encoded_msg[sent_len..data_len], &remote_addr)
                            .unwrap()
                            .unwrap();
                    }
                }
                _ => unreachable!(),
            }
        }
    }
}

pub fn serve(port: u16) {
    if cfg!(not(target_os = "linux")) {
        panic!("Server mode is only available in Linux!");
    }
    info!("Working in server mode.");

    info!("Enabling kernel's IPv4 forwarding.");
    utils::enable_ipv4_forwarding().unwrap();

    info!("Bringing up TUN device tun0.");
    let mut tun = tuntap::Tun::create(0);
    tun.up(1);

    let tun_rawfd = tun.as_raw_fd();
    let tunfd = mio::unix::EventedFd(&tun_rawfd);
    info!("TUN device tun0 initialized. Internal IP: 10.10.10.1/24.");

    let addr = format!("0.0.0.0:{}", port).parse().unwrap();
    let sockfd = mio::udp::UdpSocket::bind(&addr).unwrap();
    info!("Listening on: 0.0.0.0:{}.", port);

    let poll = mio::Poll::new().unwrap();
    poll.register(&sockfd, SOCK, mio::Ready::readable(), mio::PollOpt::level()).unwrap();
    poll.register(&tunfd, TUN, mio::Ready::readable(), mio::PollOpt::level()).unwrap();

    let mut events = mio::Events::with_capacity(1024);
    let mut available_ids: Vec<u8> = (2..254).collect();
    let mut client_map: HashMap<u8, SocketAddr> = HashMap::new();

    let mut buf = [0u8; 1600];
    let mut encoder = snap::Encoder::new();
    let mut decoder = snap::Decoder::new();
    info!("Ready for transmission.");

    loop {
        if INTERRUPTED.load(Ordering::Relaxed) {
            break;
        }

        poll.poll(&mut events, None).unwrap();

        for event in events.iter() {
            match event.token() {
                SOCK => {
                    let (len, addr) = sockfd.recv_from(&mut buf).unwrap().unwrap();
                    let msg: Message = decode(&buf[0..len]).unwrap();
                    match msg {
                        Message::Request => {
                            let client_id: u8 = available_ids.pop().unwrap();
                            client_map.insert(client_id, addr);

                            info!("Got request from {}. Assigning IP address: 10.10.10.{}.",
                                  addr,
                                  client_id);

                            let reply = Message::Response { id: client_id };
                            let encoded_reply = encode(&reply, SizeLimit::Infinite).unwrap();
                            let data_len = encoded_reply.len();
                            let mut sent_len = 0;
                            while sent_len < data_len {
                                sent_len +=
                                    sockfd.send_to(&encoded_reply[sent_len..data_len], &addr)
                                        .unwrap()
                                        .unwrap();
                            }
                        }
                        Message::Response { id: _ } => {
                            warn!("Invalid message {:?} from {}", msg, addr)
                        }
                        Message::Data { id: _, data } => {
                            let decompressed_data = decoder.decompress_vec(&data).unwrap();
                            let data_len = decompressed_data.len();
                            let mut sent_len = 0;
                            while sent_len < data_len {
                                sent_len += tun.write(&decompressed_data[sent_len..data_len])
                                    .unwrap();
                            }
                        }
                    }
                }
                TUN => {
                    let len: usize = tun.read(&mut buf).unwrap();
                    let data = &buf[0..len];
                    let client_id: u8 = data[19];

                    match client_map.get(&client_id) {
                        None => warn!("Unknown IP packet from TUN for client {}.", client_id),
                        Some(addr) => {
                            let msg = Message::Data {
                                id: client_id,
                                data: encoder.compress_vec(data).unwrap(),
                            };
                            let encoded_msg = encode(&msg, SizeLimit::Infinite).unwrap();
                            sockfd.send_to(&encoded_msg, addr).unwrap().unwrap();
                        }
                    }
                }
                _ => unreachable!(),
            }
        }
    }
}

#[test]
fn resolve_ip() {
    assert_eq!(resolve("127.0.0.1").unwrap(),
               IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)));
}
<|endoftext|>


<commit_before>#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg_attr(not(expandtest), ignore)]
#[rustversion::attr(not(nightly), ignore)]
#[allow(unused_attributes)]
#[test]
fn expandtest() {
    macrotest::expand("tests/expand/*.rs");
}
<commit_msg>Disable expandtest on miri<commit_after>#[cfg_attr(target_os = "emscripten", ignore)]
#[cfg_attr(not(expandtest), ignore)]
#[rustversion::attr(not(nightly), ignore)]
#[cfg_attr(miri, ignore)]
#[allow(unused_attributes)]
#[test]
fn expandtest() {
    macrotest::expand("tests/expand/*.rs");
}
<|endoftext|>


<commit_before>extern crate dailyschedule;
extern crate time;

use dailyschedule::*;
use time::{Timespec, at_utc, Duration};

const ON: ScheduleContext = ScheduleContext(0);
const OFF: ScheduleContext = ScheduleContext(1);

struct PrintAction;

impl ScheduleAction for PrintAction {
    fn kick(&self, timestamp: &Timespec, event: &ScheduleMoment, context: &ScheduleContext) {
        let action = match context {
            &ON => "on:",
            &OFF => "off:",
            _ => unreachable!()
        };
        println!("{:5}{} {}", action, at_utc(*timestamp).rfc822(), event);
    }
}

fn main() {
    let action_handler = PrintAction;

    let mut schedule = Schedule::new().unwrap();

    schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(10,0,0),
                                             ScheduleTime::new(11,0,0)), &action_handler, ON);
    schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(12,0,0),
                                             ScheduleTime::new(13,0,0)), &action_handler, OFF);
    schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(14,0,0)), Duration::minutes(1)), &action_handler, ON);
    schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(15,0,0)), Duration::minutes(1)), &action_handler, OFF);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(19,0,0)), &action_handler, ON);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(21,0,0)), &action_handler, OFF);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(22,0,0)), &action_handler, ON);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(23,0,0)), &action_handler, OFF);

    schedule.update_schedule(Timespec{sec:0, nsec:0});
    schedule.update_schedule(Timespec{sec:24*3600, nsec:0});

    let mut now = Timespec::new(0,0);

    loop {
        match schedule.kick_event(now) {
            Some(next) => {
                now = next;
            }
            None => break
        }
    }

    //schedule.print_keys();
    //schedule.kick_event(Timespec::new(15*3600, 0));
    //schedule.print_keys();
}
<commit_msg>schedule_printer: use real contexts<commit_after>extern crate dailyschedule;
extern crate time;

use dailyschedule::*;
use time::{Timespec, at_utc, Duration};

const ON: ScheduleContext = ScheduleContext(0);
const OFF: ScheduleContext = ScheduleContext(1);

struct PrintAction {
    id: String
}

impl PrintAction {
    fn new(name: &str) -> PrintAction {
        PrintAction {
            id: name.to_string()
        }
    }
}

impl ScheduleAction for PrintAction {
    fn kick(&self, timestamp: &Timespec, event: &ScheduleMoment, context: &ScheduleContext) {
        let action = match context {
            &ON => "on:",
            &OFF => "off:",
            _ => unreachable!()
        };
        println!("{} {:5}{} {}", self.id, action, at_utc(*timestamp).rfc822(), event);
    }
}

fn main() {
    let action_handler_1 = PrintAction::new("1");
    let action_handler_2 = PrintAction::new("2");
    let action_handler_3 = PrintAction::new("3");
    let action_handler_4 = PrintAction::new("4");

    let mut schedule = Schedule::new().unwrap();

    schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(10,0,0),
                                             ScheduleTime::new(11,0,0)), &action_handler_1, ON);
    schedule.add_event(ScheduleMoment::Fuzzy(ScheduleTime::new(12,0,0),
                                             ScheduleTime::new(13,0,0)), &action_handler_1, OFF);
    schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(14,0,0)), Duration::minutes(1)), &action_handler_2, ON);
    schedule.add_event(ScheduleMoment::ByClosure(Box::new(|_| ScheduleTime::new(15,0,0)), Duration::minutes(1)), &action_handler_2, OFF);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(19,0,0)), &action_handler_3, ON);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(21,0,0)), &action_handler_3, OFF);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(22,0,0)), &action_handler_4, ON);
    schedule.add_event(ScheduleMoment::Fixed(ScheduleTime::new(23,0,0)), &action_handler_4, OFF);

    schedule.update_schedule(Timespec{sec:0, nsec:0});
    schedule.update_schedule(Timespec{sec:24*3600, nsec:0});

    let mut now = Timespec::new(0,0);

    loop {
        match schedule.kick_event(now) {
            Some(next) => {
                now = next;
            }
            None => break
        }
    }

    //schedule.print_keys();
    //schedule.kick_event(Timespec::new(15*3600, 0));
    //schedule.print_keys();
}
<|endoftext|>


<commit_before>#[cfg(feature = "multipart")]
use super::multipart::Form;
/// dox
use bytes::Bytes;
use js_sys::Uint8Array;
use std::fmt;
use wasm_bindgen::JsValue;

/// The body of a `Request`.
///
/// In most cases, this is not needed directly, as the
/// [`RequestBuilder.body`][builder] method uses `Into<Body>`, which allows
/// passing many things (like a string or vector of bytes).
///
/// [builder]: ./struct.RequestBuilder.html#method.body
pub struct Body {
    inner: Inner,
}

enum Inner {
    Bytes(Bytes),
    #[cfg(feature = "multipart")]
    Multipart(Form),
}

impl Body {
    pub(crate) fn to_js_value(&self) -> crate::Result<JsValue> {
        match &self.inner {
            Inner::Bytes(body_bytes) => {
                let body_bytes: &[u8] = body_bytes.as_ref();
                let body_array: Uint8Array = body_bytes.into();
                let js_value: &JsValue = body_array.as_ref();
                Ok(js_value.to_owned())
            }
            #[cfg(feature = "multipart")]
            Inner::Multipart(form) => {
                let form_data = form.to_form_data()?;
                let js_value: &JsValue = form_data.as_ref();
                Ok(js_value.to_owned())
            }
        }
    }

    #[inline]
    #[cfg(feature = "multipart")]
    pub(crate) fn from_form(f: Form) -> Body {
        Self {
            inner: Inner::Multipart(f),
        }
    }

    pub(crate) fn is_empty(&self) -> bool {
        match &self.inner {
            Inner::Bytes(bytes) => bytes.is_empty(),
            #[cfg(feature = "multipart")]
            Inner::Multipart(form) => form.is_empty(),
        }
    }

    pub(crate) fn try_clone(&self) -> Option<Body> {
        match &self.inner {
            Inner::Bytes(bytes) => Some(Self {
                inner: Inner::Bytes(bytes.clone()),
            }),
            #[cfg(feature = "multipart")]
            Inner::Multipart(_) => None,
        }
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from(bytes: Bytes) -> Body {
        Body {
            inner: Inner::Bytes(bytes),
        }
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from(vec: Vec<u8>) -> Body {
        Body {
            inner: Inner::Bytes(vec.into()),
        }
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from(s: &'static [u8]) -> Body {
        Body {
            inner: Inner::Bytes(Bytes::from_static(s)),
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from(s: String) -> Body {
        Body {
            inner: Inner::Bytes(s.into()),
        }
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(s: &'static str) -> Body {
        s.as_bytes().into()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Body").finish()
    }
}
<commit_msg>use Array when converting bytes into JsValue (#1341)<commit_after>#[cfg(feature = "multipart")]
use super::multipart::Form;
/// dox
use bytes::Bytes;
use js_sys::{Array, Uint8Array};
use std::fmt;
use wasm_bindgen::JsValue;

/// The body of a `Request`.
///
/// In most cases, this is not needed directly, as the
/// [`RequestBuilder.body`][builder] method uses `Into<Body>`, which allows
/// passing many things (like a string or vector of bytes).
///
/// [builder]: ./struct.RequestBuilder.html#method.body
pub struct Body {
    inner: Inner,
}

enum Inner {
    Bytes(Bytes),
    #[cfg(feature = "multipart")]
    Multipart(Form),
}

impl Body {
    pub(crate) fn to_js_value(&self) -> crate::Result<JsValue> {
        match &self.inner {
            Inner::Bytes(body_bytes) => {
                let body_bytes: &[u8] = body_bytes.as_ref();
                let body_uint8_array: Uint8Array = body_bytes.into();
                let body_array = Array::new();
                body_array.push(&body_uint8_array);
                let js_value: &JsValue = body_array.as_ref();
                Ok(js_value.to_owned())
            }
            #[cfg(feature = "multipart")]
            Inner::Multipart(form) => {
                let form_data = form.to_form_data()?;
                let js_value: &JsValue = form_data.as_ref();
                Ok(js_value.to_owned())
            }
        }
    }

    #[inline]
    #[cfg(feature = "multipart")]
    pub(crate) fn from_form(f: Form) -> Body {
        Self {
            inner: Inner::Multipart(f),
        }
    }

    pub(crate) fn is_empty(&self) -> bool {
        match &self.inner {
            Inner::Bytes(bytes) => bytes.is_empty(),
            #[cfg(feature = "multipart")]
            Inner::Multipart(form) => form.is_empty(),
        }
    }

    pub(crate) fn try_clone(&self) -> Option<Body> {
        match &self.inner {
            Inner::Bytes(bytes) => Some(Self {
                inner: Inner::Bytes(bytes.clone()),
            }),
            #[cfg(feature = "multipart")]
            Inner::Multipart(_) => None,
        }
    }
}

impl From<Bytes> for Body {
    #[inline]
    fn from(bytes: Bytes) -> Body {
        Body {
            inner: Inner::Bytes(bytes),
        }
    }
}

impl From<Vec<u8>> for Body {
    #[inline]
    fn from(vec: Vec<u8>) -> Body {
        Body {
            inner: Inner::Bytes(vec.into()),
        }
    }
}

impl From<&'static [u8]> for Body {
    #[inline]
    fn from(s: &'static [u8]) -> Body {
        Body {
            inner: Inner::Bytes(Bytes::from_static(s)),
        }
    }
}

impl From<String> for Body {
    #[inline]
    fn from(s: String) -> Body {
        Body {
            inner: Inner::Bytes(s.into()),
        }
    }
}

impl From<&'static str> for Body {
    #[inline]
    fn from(s: &'static str) -> Body {
        s.as_bytes().into()
    }
}

impl fmt::Debug for Body {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("Body").finish()
    }
}
<|endoftext|>


<commit_before>// See erts-6.1/doc/html/erl_ext_dist.html

#![feature(struct_variant)]     // this is for enum Eterm
#![allow(non_camel_case_types)] // this is for enum ErlTermTag

extern crate num;
extern crate collections;
extern crate debug;

use std::string::String;
use std::vec::Vec;
use std::num::FromPrimitive;
use num::bigint::BigInt;
use collections::bitv::Bitv;
use std::collections::TreeMap;

#[deriving(FromPrimitive)]
enum ErlTermTag {
    // ATOM_CACHE_REF = 82,
    SMALL_INTEGER_EXT = 97,
    INTEGER_EXT = 98,
    FLOAT_EXT = 99,
    ATOM_EXT = 100,
    REFERENCE_EXT = 101,
    PORT_EXT = 102,
    PID_EXT = 103,
    SMALL_TUPLE_EXT = 104,
    LARGE_TUPLE_EXT = 105,
    MAP_EXT = 116,
    NIL_EXT = 106,
    STRING_EXT = 107,
    LIST_EXT = 108,
    BINARY_EXT = 109,
    SMALL_BIG_EXT = 110,
    LARGE_BIG_EXT = 111,
    NEW_REFERENCE_EXT = 114,
    SMALL_ATOM_EXT = 115,
    FUN_EXT = 117,
    NEW_FUN_EXT = 112,
    EXPORT_EXT = 113,
    BIT_BINARY_EXT = 77,
    NEW_FLOAT_EXT = 70,
    ATOM_UTF8_EXT = 118,
    SMALL_ATOM_UTF8_EXT = 119,
}

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
pub enum Eterm {
    SmallInteger(u8),           // small_integer
    Integer(int),               // integer
    // Float(f64),                 // float, new_float
    Atom(Atom),                 // atom, small_atom, atom_utf8, small_atom_utf8
    Reference {                 // reference, new_reference
        node: Atom,
        id: Vec<u8>,
        creation: u8},
    Port {                      // poort
        node: Atom,
        id: u8,
        creation: u8},
    Pid(Pid),                   // pid
    Tuple(Tuple),               // small_tuple, large_tuple
    Map(EMap),                  // map
    Nil,                        // nil
    String(String),             // string
    List(List),                 // list
    Binary(Vec<u8>),            // binary
    BigNum(BigInt),             // small_big, large_big
    Fun {                       // fun
        pid: Pid,
        module: Atom,
        index: u32,
        uniq: u32,
        free_vars: Vec<Eterm>},
    NewFun {                    // new_fun
        arity: u8,
        uniq: u16,
        index: u32,
        module: Atom,
        old_index: u32,
        old_uniq: u16,
        pid: Pid,
        free_vars: Vec<Eterm>},
    Export {                    // export
        module: Atom,
        function: Atom,
        arity: u8,
    },
    BitBinary(Bitv),            // bit_binary; XXX: maybe choose some other representation?
}
pub type Atom = String;
pub type Tuple = Vec<Eterm>;
pub type EMap = Vec<(Eterm, Eterm)>; // k-v pairs //TreeMap<Eterm, Eterm>;
pub type List = Vec<Eterm>;

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
pub struct Pid {                // moved out from enum because it used in Eterm::{Fun,NewFun}
    node: Atom,
    id: u8,
    serial: u32,
    creation: u8,
}

fn main() {
    for i in range(70, 120) {
        let tag: Option<ErlTermTag> = FromPrimitive::from_int(i);
        println!("{} => {:?}", i, tag);
    }

    let map = vec!( (Atom("my_map_key".to_string()), Nil) );

    let term: Eterm = NewFun {
        arity: 3,
        uniq: 1234,
        index: 10,
        module: "my_mod".to_string(),
        old_index: 1212,
        old_uniq: 1234,
        pid: Pid {node: "wasd".to_string(), id: 1, serial: 123, creation: 2},
        free_vars: vec!(//Float(3.14),
                        Nil,
                        Binary(vec!(1, 2, 3, 4)),
                        Export {
                            module: "my_mod".to_string(),
                            function: "my_func".to_string(),
                            arity: 4},
                        List(vec!(SmallInteger(1), Integer(1000000), Nil)),
                        Tuple(vec!(Atom("record".to_string()), Map(map))),
                        ),
    };
    println!("{:?}", term);
    match term {
        NewFun {free_vars: vars, ..} =>
            println!("{:?}", vars.as_slice()),
        _ => ()
    }
}
<commit_msg>Eterm builder prototype (only some types implemented)<commit_after>// See erts-6.1/doc/html/erl_ext_dist.html

#![feature(struct_variant)]     // this is for enum Eterm
#![allow(non_camel_case_types)] // this is for enum ErlTermTag
#![feature(macro_rules)]        // for try_io!

extern crate num;
extern crate collections;
extern crate debug;

use std::string::String;
use std::vec::Vec;
use std::num::FromPrimitive;
use std::io;
use num::bigint::BigInt;
use collections::bitv::Bitv;

#[deriving(FromPrimitive, Show)]
enum ErlTermTag {
    // ATOM_CACHE_REF = 82,
    SMALL_INTEGER_EXT = 97,
    INTEGER_EXT = 98,
    FLOAT_EXT = 99,
    ATOM_EXT = 100,
    REFERENCE_EXT = 101,
    PORT_EXT = 102,
    PID_EXT = 103,
    SMALL_TUPLE_EXT = 104,
    LARGE_TUPLE_EXT = 105,
    MAP_EXT = 116,
    NIL_EXT = 106,
    STRING_EXT = 107,
    LIST_EXT = 108,
    BINARY_EXT = 109,
    SMALL_BIG_EXT = 110,
    LARGE_BIG_EXT = 111,
    NEW_REFERENCE_EXT = 114,
    SMALL_ATOM_EXT = 115,
    FUN_EXT = 117,
    NEW_FUN_EXT = 112,
    EXPORT_EXT = 113,
    BIT_BINARY_EXT = 77,
    NEW_FLOAT_EXT = 70,
    ATOM_UTF8_EXT = 118,
    SMALL_ATOM_UTF8_EXT = 119,
}

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
#[deriving(Show)]
pub enum Eterm {
    SmallInteger(u8),           // small_integer
    Integer(int),               // integer
    // Float(f64),                 // float, new_float
    Atom(Atom),                 // atom, small_atom, atom_utf8, small_atom_utf8
    Reference {                 // reference, new_reference
        node: Atom,
        id: Vec<u8>,
        creation: u8},
    Port {                      // poort
        node: Atom,
        id: u8,
        creation: u8},
    Pid(Pid),                   // pid
    Tuple(Tuple),               // small_tuple, large_tuple
    Map(EMap),                  // map
    Nil,                        // nil
    String(String),             // string
    List(List),                 // list
    Binary(Vec<u8>),            // binary
    BigNum(BigInt),             // small_big, large_big
    Fun {                       // fun
        pid: Pid,
        module: Atom,
        index: u32,
        uniq: u32,
        free_vars: Vec<Eterm>},
    NewFun {                    // new_fun
        arity: u8,
        uniq: u16,
        index: u32,
        module: Atom,
        old_index: u32,
        old_uniq: u16,
        pid: Pid,
        free_vars: Vec<Eterm>},
    Export {                    // export
        module: Atom,
        function: Atom,
        arity: u8,
    },
    BitBinary(Bitv),            // bit_binary; XXX: maybe choose some other representation?
}
pub type Atom = String;
pub type Tuple = Vec<Eterm>;
pub type EMap = Vec<(Eterm, Eterm)>; // k-v pairs //TreeMap<Eterm, Eterm>;
pub type List = Vec<Eterm>;

//#[deriving(PartialOrd, PartialEq, Ord, Eq)]
#[deriving(Show)]
pub struct Pid {                // moved out from enum because it used in Eterm::{Fun,NewFun}
    node: Atom,
    id: u8,
    serial: u32,
    creation: u8,
}

// enum BuildError {
//     IoError(io::IoError),
//     BErr,
// }
type BuildResult = io::IoResult<Eterm>;//, BuildError>;

struct Builder<T> {
    rdr: T,
}

// macro_rules! try_io(
//     ($e:expr) => (
//         match $e {
//             Ok(e) => e,
//             Err(e) => return IoError(e)
//         }
//         )
// )

impl<T: io::Reader> Builder<T> {
    fn new(rdr: T) -> Builder<T> {
        Builder{rdr: rdr}
    }
    fn read_prelude(&mut self) -> io::IoResult<bool> {
        Ok(131 == try!(self.rdr.read_u8()))
    }
    fn build(&mut self) -> BuildResult {
        let int_tag = try!(self.rdr.read_u8());
        let tag: Option<ErlTermTag> = FromPrimitive::from_u8(int_tag);
        match tag {
            Some(SMALL_INTEGER_EXT) =>
                Ok(SmallInteger(try!(self.rdr.read_u8()))),
            Some(INTEGER_EXT) =>
                Ok(Integer(try!(self.rdr.read_be_int()))),
            Some(ATOM_EXT) | Some(ATOM_UTF8_EXT) => {
                let len = try!(self.rdr.read_be_u16());
                let data = try!(self.rdr.read_exact(len as uint));
                // XXX: data is in latin1 in case of ATOM_EXT
                match String::from_utf8(data) {
                    Ok(atom) =>
                        Ok(Atom(atom)),
                    Err(_) =>
                        Err(io::IoError{
                            kind: io::OtherIoError,
                            desc: "Bad utf-8",
                            detail: None // format!("{}", data)
                            })
                }
            },
            Some(SMALL_TUPLE_EXT) => {
                let mut tuple: Tuple = Vec::new();
                let arity = try!(self.rdr.read_u8());
                for _ in range(0, arity) {
                    let term = try!(self.build());
                    tuple.push(term)
                }
                Ok(Tuple(tuple))
            },
            Some(MAP_EXT) => {
                let mut map: EMap = Vec::new();
                let arity = try!(self.rdr.read_be_u32());
                for _ in range(0, arity) {
                    let key = try!(self.build());
                    let val = try!(self.build());
                    map.push((key, val))
                }
                Ok(Map(map))
            },
            Some(BINARY_EXT) => {
                let len = try!(self.rdr.read_be_u32());
                Ok(Binary(try!(self.rdr.read_exact(len as uint))))
            }
            Some(t) =>
                Err(io::IoError{
                    kind: io::OtherIoError,
                    desc: "Tag not implemented",
                    detail: Some(format!("Tag: #{} - {}", int_tag, t))
                }),
            None =>
                Err(io::IoError{
                    kind: io::OtherIoError,
                    desc: "Invalid data type",
                    detail: Some(format!("Tag: #{}", int_tag))
                })
        }
    }
}

fn main() {
    use std::io::{File,BufferedReader};

    for i in range(70, 120) {
        let tag: Option<ErlTermTag> = FromPrimitive::from_int(i);
        println!("{} => {:?}", i, tag);
    }
    println!("==============================");
    let map = vec!( (Atom("my_map_key".to_string()), Nil) );

    let term: Eterm = NewFun {
        arity: 3,
        uniq: 1234,
        index: 10,
        module: "my_mod".to_string(),
        old_index: 1212,
        old_uniq: 1234,
        pid: Pid {node: "wasd".to_string(), id: 1, serial: 123, creation: 2},
        free_vars: vec!(//Float(3.14),
                        Nil,
                        Binary(vec!(1, 2, 3, 4)),
                        Export {
                            module: "my_mod".to_string(),
                            function: "my_func".to_string(),
                            arity: 4},
                        List(vec!(SmallInteger(1), Integer(1000000), Nil)),
                        Tuple(vec!(Atom("record".to_string()), Map(map))),
                        ),
    };
    println!("{:?}", term);
    println!("==============================");
    match term {
        NewFun {free_vars: vars, ..} =>
            println!("{:?}", vars.as_slice()),
        _ => ()
    }
    println!("==============================");
    let f = BufferedReader::new(File::open(&Path::new("test/test_terms.bin")));
    let mut builder = Builder::new(f);
    match builder.read_prelude() {
        Ok(true) =>
            println!("Valid eterm"),
        Ok(false) =>
            println!("Invalid eterm!"),
        Err(io::IoError{desc: d, ..}) => {
            println!("IoError: {}", d);
            return
        }
    }
    println!("{}", builder.build());
}
<|endoftext|>


<commit_before>use tcod::{BackgroundFlag, Console, Key, KeyCode};
use tcod::{KEY_PRESSED, FONT_LAYOUT_ASCII_INROW, FONT_TYPE_GREYSCALE};

use engine::Game;
use util::units::{Direction, XYPair};

#[deriving(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI {
    game: Game,
    width: int,
    height: int,
    pub console: Console,
}

impl GUI {
    pub fn new(game: Game) -> GUI {
        let (width, height) = (100, 50);

        Console::set_custom_font(Path::new("/home/jonny/code/rslike/assets/fonts/terminal12x12_gs_ro.png"), FONT_LAYOUT_ASCII_INROW | FONT_TYPE_GREYSCALE, 0, 0);
        let console = Console::init_root(width, height, "Libtcod Rust Tutorial", false);

        GUI {
            game: game,
            width: width,
            height: height,
            console: console,
        }
    }

    pub fn run(&mut self) {
        while !self.window_closed() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        let check_key = Console::check_for_keypress(KEY_PRESSED);

        if let Some(keypress) = check_key {
            match keypress.key {
                Key::Special(KeyCode::Up) => {
                    self.game.walk(Direction::Up);
                },
                Key::Special(KeyCode::Down) => {
                    self.game.walk(Direction::Down);
                },
                Key::Special(KeyCode::Left) => {
                    self.game.walk(Direction::Left);
                },
                Key::Special(KeyCode::Right) => {
                    self.game.walk(Direction::Right);
                },
                Key::Special(KeyCode::Escape) => {
                    self.state = State::Exited;
                },
                _ => {}
            }
        }

    }

    pub fn render(&mut self) {
        self.clear();

        let (px, py) = self.game.world.player.pos().as_xy();

        self.console.put_char(px, py, '@', BackgroundFlag::Set);

        self.flush();
    }

    pub fn clear(&mut self) {
        self.console.clear();
    }

    pub fn flush(&mut self) {
        Console::flush();
    }

    pub fn window_closed(&self) -> bool {
        Console::window_closed()
    }
}
<commit_msg>Hide GUI::render() function<commit_after>use tcod::{BackgroundFlag, Console, Key, KeyCode};
use tcod::{KEY_PRESSED, FONT_LAYOUT_ASCII_INROW, FONT_TYPE_GREYSCALE};

use engine::Game;
use util::units::{Direction, XYPair};

#[deriving(PartialEq)]
pub enum State {
    Running,
    Exited
}

pub struct GUI {
    game: Game,
    width: int,
    height: int,
    pub console: Console,
}

impl GUI {
    pub fn new(game: Game) -> GUI {
        let (width, height) = (100, 50);

        Console::set_custom_font(Path::new("/home/jonny/code/rslike/assets/fonts/terminal12x12_gs_ro.png"), FONT_LAYOUT_ASCII_INROW | FONT_TYPE_GREYSCALE, 0, 0);
        let console = Console::init_root(width, height, "Libtcod Rust Tutorial", false);

        GUI {
            game: game,
            width: width,
            height: height,
            console: console,
        }
    }

    pub fn run(&mut self) {
        while !self.window_closed() {
            self.render();
            self.handle_input();
        }
    }

    fn handle_input(&mut self) {
        let check_key = Console::check_for_keypress(KEY_PRESSED);

        if let Some(keypress) = check_key {
            match keypress.key {
                Key::Special(KeyCode::Up) => {
                    self.game.walk(Direction::Up);
                },
                Key::Special(KeyCode::Down) => {
                    self.game.walk(Direction::Down);
                },
                Key::Special(KeyCode::Left) => {
                    self.game.walk(Direction::Left);
                },
                Key::Special(KeyCode::Right) => {
                    self.game.walk(Direction::Right);
                },
                Key::Special(KeyCode::Escape) => {
                    self.state = State::Exited;
                },
                _ => {}
            }
        }

    }

    fn render(&mut self) {
        self.clear();

        let (px, py) = self.game.world.player.pos().as_xy();

        self.console.put_char(px, py, '@', BackgroundFlag::Set);

        self.flush();
    }

    pub fn clear(&mut self) {
        self.console.clear();
    }

    pub fn flush(&mut self) {
        Console::flush();
    }

    pub fn window_closed(&self) -> bool {
        Console::window_closed()
    }
}
<|endoftext|>


<commit_before>extern crate crossbeam;
#[macro_use]
extern crate crossbeam_channel as channel;

use std::ops::Deref;

#[test]
fn references() {
    let (s, r) = channel::unbounded::<i32>();
    select! {
        send(s, 0) => {}
        recv(r) => {}
    }
    select! {
        send(&&&&s, 0) => {}
        recv(&&&&r) => {}
    }

    select! {
        send([&s].iter().map(|x| *x), 0) => {}
        recv([&r].iter().map(|x| *x)) => {}
    }

    let ss = &&&&[s];
    let rr = &&&&[r];
    select! {
        send(ss.iter(), 0) => {}
        recv(rr.iter()) => {}
    }
    select! {
        send(&&&&ss.iter(), 0) => {}
        recv(&&&&rr.iter()) => {}
    }
}

#[test]
fn blocks() {
    let (s, r) = channel::unbounded::<i32>();

    select! {
        recv(r) => 3.0
        recv(r) => loop {
            unreachable!()
        }
        recv(r) => match 7 + 3 {
            _ => unreachable!()
        }
        default => 7.
    };

    select! {
        recv(r, msg) => if msg.is_some() {
            unreachable!()
        }
        default => ()
    }

    drop(s);
}

#[test]
fn move_handles() {
    let (s, r) = channel::unbounded::<i32>();
    select! {
        recv((move || r)()) => {}
        send((move || s)(), 0) => {}
    }
}

#[test]
fn default() {
    let (s, r) = channel::bounded::<i32>(0);

    select! {
        recv(r) => panic!(),
        default => {}
    }
    select! {
        send(s, 0) => panic!(),
        default() => {}
    }
    select! {
        default => {}
    }
    select! {
        default() => {}
    }
}

#[test]
fn same_variable_name() {
    let (_, r) = channel::unbounded::<i32>();
    select! {
        recv(r, r) => assert!(r.is_none()),
    }

    let (s, _) = channel::unbounded::<i32>();
    let s2 = s.clone();
    select! {
        send(s, 0, s) => assert_eq!(s, &s2),
    }
}

#[test]
fn handles_on_heap() {
    let (s, r) = channel::unbounded::<i32>();
    let (s, r) = (Box::new(s), Box::new(r));

    select! {
        send(*s, 0) => {}
        recv(*r) => {}
        default => {}
    }

    drop(s);
    drop(r);
}

#[test]
fn option_receiver() {
    let (_, r) = channel::unbounded::<i32>();
    select! {
        recv(Some(&r)) => {}
    }
    select! {
        recv(Some(&r)) => {}
        recv(Some(&r)) => {}
    }

    let r: Option<channel::Receiver<u32>> = None;
    select! {
        recv(r.as_ref()) => {}
        default => {}
    }
    select! {
        recv(r.as_ref()) => {}
        recv(r.as_ref()) => {}
        default => {}
    }

    let r: Option<&&&Box<&&channel::Receiver<u32>>> = None;
    let r: Option<&channel::Receiver<u32>> = match r {
        None => None,
        Some(r) => Some(r),
    };
    select! {
        recv(r) => {}
        default => {}
    }
    select! {
        recv(r) => {}
        recv(r) => {}
        default => {}
    }
}

#[test]
fn option_sender() {
    let (s, _) = channel::unbounded::<i32>();
    select! {
        send(Some(&s), 0) => {}
        default => {}
    }
    select! {
        send(Some(&s), 0) => {}
        send(Some(&s), 0) => {}
        default => {}
    }

    let s: Option<channel::Sender<u32>> = None;
    select! {
        send(s.as_ref(), 0) => {}
        default => {}
    }
    select! {
        send(s.as_ref(), 0) => {}
        send(s.as_ref(), 0) => {}
        default => {}
    }

    let s: Option<&&&Box<&&channel::Sender<u32>>> = None;
    let s: Option<&channel::Sender<u32>> = match s {
        None => None,
        Some(s) => Some(s),
    };
    select! {
        send(s, 0) => {}
        default => {}
    }
    select! {
        send(s, 0) => {}
        send(s, 0) => {}
        default => {}
    }
}

#[test]
fn once_receiver() {
    let (_, r) = channel::unbounded::<i32>();

    let once = Box::new(());
    let get = move || {
        drop(once);
        r
    };

    select! {
        recv(get()) => {}
    }
}

#[test]
fn once_sender() {
    let (s, _) = channel::unbounded::<i32>();

    let once = Box::new(());
    let get = move || {
        drop(once);
        s
    };

    select! {
        send(get(), 5) => {}
    }
}

#[test]
fn nesting() {
    let (_, r) = channel::unbounded::<i32>();

    select! {
        recv(r) => {
            select! {
                recv(r) => {
                    select! {
                        recv(r) => {
                            select! {
                                default => {}
                            }
                        }
                    }
                }
            }
        }
    }
}

#[test]
fn evaluate() {
    let (s, r) = channel::unbounded::<i32>();

    let v = select! {
        recv(r) => "foo".into(),
        send(s, 0) => "bar".to_owned(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "bar");

    let v = select! {
        recv(r) => "foo".into(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "foo");

    let v = select! {
        recv(r) => "foo".into(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "baz");
}

#[test]
fn variety() {
    let (s1, r1) = channel::unbounded::<i32>();
    let (s2, r2) = channel::bounded::<String>(1);
    let (s3, r3) = channel::bounded::<()>(0);

    select! {
        recv(r1) => {}
        send(s1, 7) => {}
        recv(Some(r2)) => {}
        send(Some(s2), "foo".to_string()) => {}
        recv([&r3].iter().map(|x| *x)) => {}
        send([&s3].iter().map(|x| *x), ()) => {}
        default => {}
    }
}

#[test]
fn deref() {
    struct Sender<T>(channel::Sender<T>);
    struct Receiver<T>(channel::Receiver<T>);

    impl<T> Deref for Receiver<T> {
        type Target = channel::Receiver<T>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<T> Deref for Sender<T> {
        type Target = channel::Sender<T>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    let (s, r) = channel::bounded::<i32>(0);
    let (s, r) = (Sender(s), Receiver(r));

    select! {
        send(s, 0) => panic!(),
        recv(r) => panic!(),
        default => {}
    }
}
<commit_msg>More tests<commit_after>extern crate crossbeam;
#[macro_use]
extern crate crossbeam_channel as channel;

use std::ops::Deref;

#[test]
fn references() {
    let (s, r) = channel::unbounded::<i32>();
    select! {
        send(s, 0) => {}
        recv(r) => {}
    }
    select! {
        send(&&&&s, 0) => {}
        recv(&&&&r) => {}
    }

    select! {
        send([&s].iter().map(|x| *x), 0) => {}
        recv([&r].iter().map(|x| *x)) => {}
    }

    let ss = &&&&[s];
    let rr = &&&&[r];
    select! {
        send(ss.iter(), 0) => {}
        recv(rr.iter()) => {}
    }
    select! {
        send(&&&&ss.iter(), 0) => {}
        recv(&&&&rr.iter()) => {}
    }
}

#[test]
fn blocks() {
    let (s, r) = channel::unbounded::<i32>();

    select! {
        recv(r) => 3.0
        recv(r) => loop {
            unreachable!()
        }
        recv(r) => match 7 + 3 {
            _ => unreachable!()
        }
        default => 7.
    };

    select! {
        recv(r, msg) => if msg.is_some() {
            unreachable!()
        }
        default => ()
    }

    drop(s);
}

#[test]
fn move_handles() {
    let (s, r) = channel::unbounded::<i32>();
    select! {
        recv((move || r)()) => {}
        send((move || s)(), 0) => {}
    }
}

#[test]
fn default() {
    let (s, r) = channel::bounded::<i32>(0);

    select! {
        recv(r) => panic!(),
        default => {}
    }
    select! {
        send(s, 0) => panic!(),
        default() => {}
    }
    select! {
        default => {}
    }
    select! {
        default() => {}
    }
}

#[test]
fn same_variable_name() {
    let (_, r) = channel::unbounded::<i32>();
    select! {
        recv(r, r) => assert!(r.is_none()),
    }

    let (s, _) = channel::unbounded::<i32>();
    let s2 = s.clone();
    select! {
        send(s, 0, s) => assert_eq!(s, &s2),
    }
}

#[test]
fn handles_on_heap() {
    let (s, r) = channel::unbounded::<i32>();
    let (s, r) = (Box::new(s), Box::new(r));

    select! {
        send(*s, 0) => {}
        recv(*r) => {}
        default => {}
    }

    drop(s);
    drop(r);
}

#[test]
fn option_receiver() {
    let (_, r) = channel::unbounded::<i32>();
    select! {
        recv(Some(&r)) => {}
    }
    select! {
        recv(Some(&r)) => {}
        recv(Some(&r)) => {}
    }

    let r: Option<channel::Receiver<u32>> = None;
    select! {
        recv(r.as_ref()) => {}
        default => {}
    }
    select! {
        recv(r.as_ref()) => {}
        recv(r.as_ref()) => {}
        default => {}
    }

    let r: Option<&&&Box<&&channel::Receiver<u32>>> = None;
    let r: Option<&channel::Receiver<u32>> = match r {
        None => None,
        Some(r) => Some(r),
    };
    select! {
        recv(r) => {}
        default => {}
    }
    select! {
        recv(r) => {}
        recv(r) => {}
        default => {}
    }
}

#[test]
fn option_sender() {
    let (s, _) = channel::unbounded::<i32>();
    select! {
        send(Some(&s), 0) => {}
        default => {}
    }
    select! {
        send(Some(&s), 0) => {}
        send(Some(&s), 0) => {}
        default => {}
    }

    let s: Option<channel::Sender<u32>> = None;
    select! {
        send(s.as_ref(), 0) => {}
        default => {}
    }
    select! {
        send(s.as_ref(), 0) => {}
        send(s.as_ref(), 0) => {}
        default => {}
    }

    let s: Option<&&&Box<&&channel::Sender<u32>>> = None;
    let s: Option<&channel::Sender<u32>> = match s {
        None => None,
        Some(s) => Some(s),
    };
    select! {
        send(s, 0) => {}
        default => {}
    }
    select! {
        send(s, 0) => {}
        send(s, 0) => {}
        default => {}
    }
}

#[test]
fn once_blocks() {
    let (s, r) = channel::unbounded::<i32>();

    let once = Box::new(());
    select! {
        send(s, 0) => drop(once),
    }

    let once = Box::new(());
    select! {
        recv(r) => drop(once),
    }

    let once1 = Box::new(());
    let once2 = Box::new(());
    select! {
        send(s, 0) => drop(once1),
        default => drop(once2),
    }

    let once1 = Box::new(());
    let once2 = Box::new(());
    select! {
        recv(r) => drop(once1),
        default => drop(once2),
    }

    let once1 = Box::new(());
    let once2 = Box::new(());
    select! {
        recv(r) => drop(once1),
        send(s, 0) => drop(once2),
    }
}

#[test]
fn once_receiver() {
    let (_, r) = channel::unbounded::<i32>();

    let once = Box::new(());
    let get = move || {
        drop(once);
        r
    };

    select! {
        recv(get()) => {}
    }
}

#[test]
fn once_sender() {
    let (s, _) = channel::unbounded::<i32>();

    let once = Box::new(());
    let get = move || {
        drop(once);
        s
    };

    select! {
        send(get(), 5) => {}
    }
}

#[test]
fn once_receive() {

}

#[test]
fn nesting() {
    let (_, r) = channel::unbounded::<i32>();

    select! {
        recv(r) => {
            select! {
                recv(r) => {
                    select! {
                        recv(r) => {
                            select! {
                                default => {}
                            }
                        }
                    }
                }
            }
        }
    }
}

#[test]
fn evaluate() {
    let (s, r) = channel::unbounded::<i32>();

    let v = select! {
        recv(r) => "foo".into(),
        send(s, 0) => "bar".to_owned(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "bar");

    let v = select! {
        recv(r) => "foo".into(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "foo");

    let v = select! {
        recv(r) => "foo".into(),
        default => "baz".to_string(),
    };
    assert_eq!(v, "baz");
}

#[test]
fn variety() {
    let (s1, r1) = channel::unbounded::<i32>();
    let (s2, r2) = channel::bounded::<String>(1);
    let (s3, r3) = channel::bounded::<()>(0);

    select! {
        recv(r1) => {}
        send(s1, 7) => {}
        recv(Some(r2)) => {}
        send(Some(s2), "foo".to_string()) => {}
        recv([&r3].iter().map(|x| *x)) => {}
        send([&s3].iter().map(|x| *x), ()) => {}
        default => {}
    }
}

#[test]
fn deref() {
    struct Sender<T>(channel::Sender<T>);
    struct Receiver<T>(channel::Receiver<T>);

    impl<T> Deref for Receiver<T> {
        type Target = channel::Receiver<T>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    impl<T> Deref for Sender<T> {
        type Target = channel::Sender<T>;

        fn deref(&self) -> &Self::Target {
            &self.0
        }
    }

    let (s, r) = channel::bounded::<i32>(0);
    let (s, r) = (Sender(s), Receiver(r));

    select! {
        send(s, 0) => panic!(),
        recv(r) => panic!(),
        default => {}
    }
}
<|endoftext|>


<commit_before>use core::f64::MAX;
use rust_decimal::prelude::*;

use super::behaviors::MouseBehavior;

use crate::{
    api::prelude::*, prelude::*, proc_macros::*, shell::prelude::*, themes::theme_orbtk::*,
};

// --- KEYS --

pub static ID_INPUT: &str = "numeric_box_input";
pub static STYLE_INPUT: &str = "numeric_box_input";
pub static STYLE_BTN: &str = "numeric_box_button";

// --- KEYS --

/// Enumeration of valid input actions
pub enum InputAction {
    Inc,
    Dec,
    ChangeByKey(KeyEvent),
    ChangeByMouseScroll(Point),
    Focus,
}

/// Used to handle the numeric box status elements.
#[derive(Default, AsAny)]
pub struct NumericBoxState {
    pub action: Option<InputAction>,
    pub input: Entity,
    pub min: Decimal,
    pub max: Decimal,
    pub step: Decimal,
    pub current_value: Decimal,
    event_adapter: EventAdapter,
    window: Entity,
}

impl NumericBoxState {
    fn action(&mut self, action: InputAction) {
        self.action = Some(action);
    }

    fn change_val(&mut self, new_value: Decimal, ctx: &mut Context) {
        if self.current_value == self.min && new_value < self.min
            || self.current_value == self.max && new_value > self.max
        {
            return;
        }

        self.current_value = self.max(self.min(new_value));
        if let Some(val) = self.current_value.to_f64() {
            ctx.widget().set("val", val);
        }

        ctx.get_widget(self.input)
            .set::<String>("text", self.current_value.to_string());
    }

    fn min(&self, d: Decimal) -> Decimal {
        if d <= self.min {
            return self.min;
        }

        d
    }

    fn max(&self, d: Decimal) -> Decimal {
        if d >= self.max {
            return self.max;
        }

        d
    }

    fn request_focus(&self, ctx: &mut Context) {
        if !ctx.widget().get::<bool>("focused") {
            ctx.widget().set::<bool>("focused", true);
            self.event_adapter
                .push_event_direct(self.window, FocusEvent::RequestFocus(ctx.entity()));
        }
    }
}

fn default_or(key: &str, default_value: f64, ctx: &mut Context) -> Decimal {
    let property = ctx.widget().clone_or_default(key);

    match Decimal::from_f64(property) {
        Some(val) => val,
        None => Decimal::from_f64(default_value).unwrap(),
    }
}

impl State for NumericBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
        self.input = ctx.entity_of_child(ID_INPUT).expect(
            "NumericBoxState
        .init(): the child input could not be found!",
        );
        self.event_adapter = ctx.event_adapter();
        self.min = default_or("min", 0.0, ctx);
        self.max = default_or("max", MAX, ctx);
        self.step = default_or("step", 1.0, ctx);
        self.current_value = default_or("val", 0.0, ctx);

        let init_value = self.current_value.to_string();
        ctx.get_widget(self.input).set::<String>("text", init_value);
    }

    // TODO: let the user type the value, or select it for cut, copy, paste operations
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
        if let Some(action) = &self.action {
            match action {
                InputAction::Inc => {
                    self.change_val(self.current_value + self.step, ctx);
                }
                InputAction::Dec => {
                    self.change_val(self.current_value - self.step, ctx);
                }
                InputAction::ChangeByKey(key_event) => match key_event.key {
                    Key::Up | Key::NumpadAdd => {
                        self.change_val(self.current_value + self.step, ctx);
                    }
                    Key::Down | Key::NumpadSubtract => {
                        self.change_val(self.current_value - self.step, ctx);
                    }
                    Key::Enter => {
                        if *ctx.widget().get::<bool>("lose_focus_on_activation") {
                            self.event_adapter.push_event_direct(
                                self.window,
                                FocusEvent::RequestFocus(ctx.entity()),
                            );
                        }

                        self.event_adapter
                            .push_event_direct(ctx.entity(), ActivateEvent(ctx.entity()));
                    }
                    _ => {}
                },
                InputAction::ChangeByMouseScroll(delta) => {
                    if delta.y() < 0.0 {
                        self.change_val(self.current_value - self.step, ctx);
                    } else {
                        self.change_val(self.current_value + self.step, ctx);
                    }
                }
                InputAction::Focus => {
                    self.request_focus(ctx);
                }
            }
            self.action = None;
        }
    }
}

widget!(
    /// `NumericBox` is used to let the user increase or decrease
    /// the value of the input by a given, fixed value called `step` until it reaches the upper or
    /// lower bounds.
    /// The widget can be controlled by clicking on the two control buttons, or the keybaord's
    /// Up and Down, Numpad+ and Numpad- keys, or the mouse scroll.
    /// Note: after the widget is initialized, changing the min, max or step properties has no effect.
    ///
    /// # Examples:
    /// Create a NumericBox with default values:
    /// ```rust
    /// NumericBox::new().build(ctx)
    /// ```
    ///
    /// Create a NumericBox with custom values:
    /// ```rust
    /// NumericBox::new().min(10.0).max(100.0).val(50.0).step(5.0).build(ctx)
    /// ```
    NumericBox<NumericBoxState>: ActivateHandler, KeyDownHandler {
        /// Sets or shares the background color property
        background: Brush,

        /// Sets or shares the border color property
        border_brush: Brush,

        /// Sets or shares the border width property
        border_width: Thickness,

        /// Sets or shares the border radius property
        border_radius: f64,

        /// Sets or shares the focused property
        focused: bool,

        /// Sets or shares the foreground color property
        foreground: Brush,

        /// Sets or shares the font size property.
        font_size: f64,

        /// Sets or shares the font property.
        font: String,

        /// Sets or shares the value that describes if the NumericBox should lose focus on activation (when enter pressed).
        lose_focus_on_activation: bool,

        /// Sets or shares the minimum allowed value property
        min: f64,

        /// Sets or shares the maximum allowed value property
        max: f64,

        /// Sets or shares the stepping value property
        step: f64,

        /// Sets or shares the current value property
        val: f64,

        /// Indicates if the widget is hovered by the mouse cursor.
        hover: bool,

        /// Represents the up icon of the up button.
        icon_up: String,

        /// Represents the up icon of the down button
        icon_down: String,

        padding: Thickness
    }
);

impl Template for NumericBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
        self.name("NumericBox")
            .style("numeric_box")
            .background("transparent")
            .foreground(colors::LINK_WATER_COLOR)
            .border_brush("#647b91")
            .border_width(1.0)
            .border_radius(3.0)
            .focused(false)
            .height(32.0)
            .lose_focus_on_activation(true)
            .min(0.0)
            .max(200.0)
            .step(1.0)
            .val(0.0)
            .icon_up(material_icons_font::MD_KEYBOARD_ARROW_UP)
            .icon_down(material_icons_font::MD_KEYBOARD_ARROW_DOWN)
            .min_width(128.0)
            .child(
                MouseBehavior::new()
                    .on_mouse_down(move |states, _| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::Focus);
                        true
                    })
                    .on_scroll(move |states, delta| {
                        states
                            .get_mut::<NumericBoxState>(id)
                            .action(InputAction::ChangeByMouseScroll(delta));
                        true
                    })
                    .build(ctx),
            )
            .child(
                Grid::new()
                    .columns("*, 32")
                    .rows("16, 16")
                    .child(
                        TextBox::new()
                            .margin(("padding", id))
                            .id(ID_INPUT)
                            .style("")
                            .attach(Grid::column(0))
                            .attach(Grid::row_span(2))
                            .attach(Grid::row(0))
                            .foreground(id)
                            .border_brush("transparent")
                            .border_width(0)
                            .font_size(id)
                            .background("transparent")
                            .h_align("stretch")
                            .enabled(false)
                            .v_align("center")
                            .text("0")
                            .lose_focus_on_activation(id)
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .style("button_small")
                            .attach(Grid::column(1))
                            .attach(Grid::row(0))
                            .min_width(14)
                            .height(15)
                            .icon(("icon_up", id))
                            .margin(1)
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Inc);
                                true
                            })
                            .build(ctx),
                    )
                    .child(
                        Button::new()
                            .style("button_small")
                            .attach(Grid::column(1))
                            .attach(Grid::row(1))
                            .min_width(14)
                            .height(15)
                            .padding(0.0)
                            .margin(1)
                            .icon(("icon_down", id))
                            .on_click(move |states, _| {
                                states
                                    .get_mut::<NumericBoxState>(id)
                                    .action(InputAction::Dec);
                                true
                            })
                            .build(ctx),
                    )
                    .build(ctx),
            )
            .on_key_down(move |states, event| -> bool {
                states
                    .get_mut::<NumericBoxState>(id)
                    .action(InputAction::ChangeByKey(event));
                false
            })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
        RectangleRenderObject.into()
    }
}
<commit_msg>orbtk_widgets: numeric_box: update<commit_after>use core::f64::MAX;
use rust_decimal::prelude::*;

use super::behaviors::MouseBehavior;

use crate::{
    api::prelude::*, prelude::*, proc_macros::*, shell::prelude::*,
    // themes::theme_orbtk::*,
};

// --- KEYS --

pub static ID_INPUT: &str = "numeric_box_input";
pub static STYLE_INPUT: &str = "numeric_box_input";
pub static STYLE_BTN: &str = "numeric_box_button";

// --- KEYS --

/// Enumeration of valid input actions
pub enum InputAction {
    ChangeByKey(KeyEvent),
    ChangeByMouseScroll(Point),
    Dec,
    Focus,
    Inc
}

/// Handle the numeric box status elements.
#[derive(AsAny, Default)]
pub struct NumericBoxState {
    pub action: Option<InputAction>,
    pub input: Entity,
    pub min: Decimal,
    pub max: Decimal,
    pub step: Decimal,
    pub current_value: Decimal,
    event_adapter: EventAdapter,
    window: Entity,
}

impl NumericBoxState {
    fn action(&mut self, action: InputAction) {
	self.action = Some(action);
    }

    fn change_val(&mut self, new_value: Decimal, ctx: &mut Context) {
	if self.current_value == self.min && new_value < self.min
	    || self.current_value == self.max && new_value > self.max
	{
	    return;
	}

	self.current_value = self.max(self.min(new_value));
	if let Some(val) = self.current_value.to_f64() {
	    ctx.widget().set("val", val);
	}

	ctx.get_widget(self.input)
	    .set::<String>("text", self.current_value.to_string());
    }

    fn min(&self, d: Decimal) -> Decimal {
	if d <= self.min {
	    return self.min;
	}

	d
    }

    fn max(&self, d: Decimal) -> Decimal {
	if d >= self.max {
	    return self.max;
	}

	d
    }

    fn request_focus(&self, ctx: &mut Context) {
	if !ctx.widget().get::<bool>("focused") {
	    ctx.widget().set::<bool>("focused", true);
	    self.event_adapter
		.push_event_direct(self.window, FocusEvent::RequestFocus(ctx.entity()));
	}
    }
}

fn default_or(key: &str, default_value: f64, ctx: &mut Context) -> Decimal {
    let property = ctx.widget().clone_or_default(key);

    match Decimal::from_f64(property) {
	Some(val) => val,
	None => Decimal::from_f64(default_value).unwrap(),
    }
}

impl State for NumericBoxState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context) {
	self.input = ctx.entity_of_child(ID_INPUT).expect(
	    "NumericBoxState
	.init(): the child input could not be found!",
	);
	self.event_adapter = ctx.event_adapter();
	self.min = default_or("min", 0.0, ctx);
	self.max = default_or("max", MAX, ctx);
	self.step = default_or("step", 1.0, ctx);
	self.current_value = default_or("val", 0.0, ctx);

	let init_value = self.current_value.to_string();
	ctx.get_widget(self.input).set::<String>("text", init_value);
    }

    // TODO: let the user type the value, or select it for cut, copy, paste operations
    fn update(&mut self, _: &mut Registry, ctx: &mut Context) {
	if let Some(action) = &self.action {
	    match action {
		InputAction::Inc => {
		    self.change_val(self.current_value + self.step, ctx);
		}
		InputAction::Dec => {
		    self.change_val(self.current_value - self.step, ctx);
		}
		InputAction::ChangeByKey(key_event) => match key_event.key {
		    Key::Up | Key::NumpadAdd => {
			self.change_val(self.current_value + self.step, ctx);
		    }
		    Key::Down | Key::NumpadSubtract => {
			self.change_val(self.current_value - self.step, ctx);
		    }
		    Key::Enter => {
			if *ctx.widget().get::<bool>("lose_focus_on_activation") {
			    self.event_adapter.push_event_direct(
				self.window,
				FocusEvent::RequestFocus(ctx.entity()),
			    );
			}

			self.event_adapter
			    .push_event_direct(ctx.entity(), ActivateEvent(ctx.entity()));
		    }
		    _ => {}
		},
		InputAction::ChangeByMouseScroll(delta) => {
		    if delta.y() < 0.0 {
			self.change_val(self.current_value - self.step, ctx);
		    } else {
			self.change_val(self.current_value + self.step, ctx);
		    }
		}
		InputAction::Focus => {
		    self.request_focus(ctx);
		}
	    }
	    self.action = None;
	}
    }
}

widget!(
    /// `NumericBox` is used to let the user increase or decrease the
    /// value of the input by a given, fixed value called `step` until
    /// it reaches the upper or lower bounds.
    /// The widget is controlled using keyboard actions (Up and Down
    /// keys, Numpad+ and Numpad- keys) or mouse actions (wheel motion).
    /// Note: after the widget is initialized, changing the
    /// min, max or step properties has no effect.
    ///
    /// * style: `numeric_box`
    ///
    /// # Examples:
    /// Create a NumericBox with default values:
    /// ```rust
    /// NumericBox::new().build(ctx)
    /// ```
    ///
    /// Create a NumericBox with custom values:
    /// ```rust
    /// NumericBox::new().min(10.0).max(100.0).val(50.0).step(5.0).build(ctx)
    /// ```
    NumericBox<NumericBoxState>: ActivateHandler, KeyDownHandler {
	/// Sets or shares the background color property
	background: Brush,

	/// Sets or shares the border color property
	border_brush: Brush,

	/// Sets or shares the border width property
	border_width: Thickness,

	/// Sets or shares the border radius property
	border_radius: f64,

	/// Sets or shares the focused property
	focused: bool,

	/// Sets or shares the foreground color property
	foreground: Brush,

	/// Sets or shares the font size property.
	font_size: f64,

	/// Sets or shares the font property.
	font: String,

	/// Sets or shares the value that describes if the NumericBox should lose focus on activation (when enter pressed).
	lose_focus_on_activation: bool,

	/// Sets or shares the minimum allowed value property
	min: f64,

	/// Sets or shares the maximum allowed value property
	max: f64,

	/// Sets or shares the stepping value property
	step: f64,

	/// Sets or shares the current value property
	val: f64,

	/// Indicates if the widget is hovered by the mouse cursor.
	hover: bool,

	/// Represents the up icon of the up button.
	icon_up: String,

	/// Represents the up icon of the down button
	icon_down: String,

	padding: Thickness
    }
);

impl Template for NumericBox {
    fn template(self, id: Entity, ctx: &mut BuildContext) -> Self {
	self.name("NumericBox")
	    .style("numeric_box")
	    .focused(false)
	    .lose_focus_on_activation(true)
	    .min(0.0)
	    //.min_width(128)
	    .step(1.0)
	    .v_align("center")
	    .val(0.0)
	    .child(
		MouseBehavior::new()
		    .on_mouse_down(move |states, _| {
			states
			    .get_mut::<NumericBoxState>(id)
			    .action(InputAction::Focus);
			true
		    })
		    .on_scroll(move |states, delta| {
			states
			    .get_mut::<NumericBoxState>(id)
			    .action(InputAction::ChangeByMouseScroll(delta));
			true
		    })
		    .build(ctx),
	    )
	    .child(
		Grid::new()
		    .columns("*, 32")
		    .rows("16, 16")
		    .child(
			TextBox::new()
			    .id(ID_INPUT)
			    .style("")
			    .attach(Grid::column(0))
			    .attach(Grid::row_span(2))
			    .attach(Grid::row(0))
			    .border_width(0)
			    .enabled(false)
			    .foreground(("foreground", id))
			    .background("transparent")
			    .h_align("stretch")
			    .lose_focus_on_activation(id)
			    .margin(("padding", id))
			    .text("0")
			    .v_align("center")
			    .build(ctx),
		    )
		    .child(
			Button::new()
			    .style("button_small")
			    .attach(Grid::column(1))
			    .attach(Grid::row(0))
			    .icon(("icon_up", id))
			    .max_width(64)
			    .min_width(14)
			    .on_click(move |states, _| {
				states
				    .get_mut::<NumericBoxState>(id)
				    .action(InputAction::Inc);
				true
			    })
			    .build(ctx),
		    )
		    .child(
			Button::new()
			    .style("button_small")
			    .attach(Grid::column(1))
			    .attach(Grid::row(1))
			    .icon(("icon_down", id))
			    .max_width(64)
			    .min_width(14)
			    .padding(0.0)
			    .on_click(move |states, _| {
				states
				    .get_mut::<NumericBoxState>(id)
				    .action(InputAction::Dec);
				true
			    })
			    .build(ctx),
		    )
		    .build(ctx),
	    )
	    .on_key_down(move |states, event| -> bool {
		states
		    .get_mut::<NumericBoxState>(id)
		    .action(InputAction::ChangeByKey(event));
		false
	    })
    }

    fn render_object(&self) -> Box<dyn RenderObject> {
	RectangleRenderObject.into()
    }
}
<|endoftext|>