<commit_before>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::net::ToSocketAddrs;

use ring::rand::*;

const MAX_DATAGRAM_SIZE: usize = 1350;

const USAGE: &str = "Usage:
  http3-client [options] URL
  http3-client -h | --help

Options:
  --method METHOD          Use the given HTTP request method [default: GET].
  --body FILE              Send the given file as request body.
  --max-data BYTES         Connection-wide flow control limit [default: 10000000].
  --max-stream-data BYTES  Per-stream flow control limit [default: 1000000].
  --wire-version VERSION   The version number to send to the server [default: babababa].
  --no-verify              Don't verify server's certificate.
  --no-grease              Don't send GREASE.
  -H --header HEADER ...   Add a request header.
  -h --help                Show this screen.
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; MAX_DATAGRAM_SIZE];

    env_logger::builder()
        .default_format_timestamp_nanos(true)
        .init();

    let args = docopt::Docopt::new(USAGE)
        .and_then(|dopt| dopt.parse())
        .unwrap_or_else(|e| e.exit());

    let max_data = args.get_str("--max-data");
    let max_data = u64::from_str_radix(max_data, 10).unwrap();

    let max_stream_data = args.get_str("--max-stream-data");
    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();

    let version = args.get_str("--wire-version");
    let version = u32::from_str_radix(version, 16).unwrap();

    let url = url::Url::parse(args.get_str("URL")).unwrap();

    // Request headers (can be multiple).
    let req_headers = args.get_vec("--header");

    // Setup the event loop.
    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    // Resolve server address.
    let peer_addr = url.to_socket_addrs().unwrap().next().unwrap();
    info!("connecting to {:}", peer_addr);

    // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
    // server address. This is needed on macOS and BSD variants that don't
    // support binding to IN6ADDR_ANY for both v4 and v6.
    let bind_addr = match peer_addr {
        std::net::SocketAddr::V4(_) => "0.0.0.0:0",
        std::net::SocketAddr::V6(_) => "[::]:0",
    };

    // Create the UDP socket backing the QUIC connection, and register it with
    // the event loop.
    let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
    socket.connect(peer_addr).unwrap();

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(
        &socket,
        mio::Token(0),
        mio::Ready::readable(),
        mio::PollOpt::edge(),
    )
    .unwrap();

    // Create the configuration for the QUIC connection.
    let mut config = quiche::Config::new(version).unwrap();

    config.verify_peer(true);

    config
        .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
        .unwrap();

    config.set_idle_timeout(5000);
    config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
    config.set_initial_max_data(max_data);
    config.set_initial_max_stream_data_bidi_local(max_stream_data);
    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
    config.set_initial_max_stream_data_uni(max_stream_data);
    config.set_initial_max_streams_bidi(100);
    config.set_initial_max_streams_uni(100);
    config.set_disable_migration(true);

    let mut http3_conn = None;

    if args.get_bool("--no-verify") {
        config.verify_peer(false);
    }

    if args.get_bool("--no-grease") {
        config.grease(false);
    }

    if std::env::var_os("SSLKEYLOGFILE").is_some() {
        config.log_keys();
    }

    // Generate a random source connection ID for the connection.
    let mut scid = [0; quiche::MAX_CONN_ID_LEN];
    SystemRandom::new().fill(&mut scid[..]).unwrap();

    // Create a QUIC connection and initiate handshake.
    let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();

    let write = match conn.send(&mut out) {
        Ok(v) => v,

        Err(e) => panic!("initial send failed: {:?}", e),
    };

    while let Err(e) = socket.send(&out[..write]) {
        if e.kind() == std::io::ErrorKind::WouldBlock {
            debug!("send() would block");
            continue;
        }

        panic!("send() failed: {:?}", e);
    }

    debug!("written {}", write);

    let req_start = std::time::Instant::now();

    loop {
        poll.poll(&mut events, conn.timeout()).unwrap();

        // Read incoming UDP packets from the socket and feed them to quiche,
        // until there are no more packets to read.
        'read: loop {
            // If the event loop reported no events, it means that the timeout
            // has expired, so handle it without attempting to read packets. We
            // will then proceed with the send loop.
            if events.is_empty() {
                debug!("timed out");

                conn.on_timeout();

                break 'read;
            }

            let len = match socket.recv(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    // There are no more UDP packets to read, so end the read
                    // loop.
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("got {} bytes", len);

            // Process potentially coalesced packets.
            let read = match conn.recv(&mut buf[..len]) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("done reading");
                    break;
                },

                Err(e) => {
                    error!("recv failed: {:?}", e);
                    break 'read;
                },
            };

            debug!("processed {} bytes", read);
        }

        if conn.is_closed() {
            info!("connection closed, {:?}", conn.stats());
            break;
        }

        // Create a new HTTP/3 connection and end an HTTP request as soon as
        // the QUIC connection is established.
        if conn.is_established() && http3_conn.is_none() {
            let h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();

            let mut h3_conn =
                quiche::h3::Connection::with_transport(&mut conn, &h3_config)
                    .unwrap();

            let mut path = String::from(url.path());

            if let Some(query) = url.query() {
                path.push('?');
                path.push_str(query);
            }

            let mut req = vec![
                quiche::h3::Header::new(":method", args.get_str("--method")),
                quiche::h3::Header::new(":scheme", url.scheme()),
                quiche::h3::Header::new(":authority", url.host_str().unwrap()),
                quiche::h3::Header::new(":path", &path),
                quiche::h3::Header::new("user-agent", "quiche"),
            ];

            // Add custom headers to the request.
            for header in &req_headers {
                let header_split: Vec<&str> = header.splitn(2, ": ").collect();
                req.push(quiche::h3::Header::new(
                    header_split[0],
                    header_split[1],
                ));
            }

            info!("sending HTTP request {:?}", req);

            let body = if args.get_bool("--body") {
                std::fs::read(args.get_str("--body")).ok()
            } else {
                None
            };

            if body.is_some() {
                req.push(quiche::h3::Header::new(
                    "content-length",
                    &body.as_ref().unwrap().len().to_string(),
                ));
            }

            let s = match h3_conn.send_request(&mut conn, &req, body.is_none()) {
                Ok(stream_id) => stream_id,

                Err(e) => {
                    error!("failed to send request {:?}", e);
                    break;
                },
            };

            if let Some(body) = body {
                if let Err(e) = h3_conn.send_body(&mut conn, s, &body, true) {
                    error!("failed to send request body {:?}", e);
                    break;
                }
            }

            http3_conn = Some(h3_conn);
        }

        if let Some(http3_conn) = &mut http3_conn {
            // Process HTTP/3 events.
            loop {
                match http3_conn.poll(&mut conn) {
                    Ok((stream_id, quiche::h3::Event::Headers(headers))) => {
                        info!(
                            "got response headers {:?} on stream id {}",
                            headers, stream_id
                        );
                    },

                    Ok((stream_id, quiche::h3::Event::Data)) => {
                        if let Ok(read) =
                            http3_conn.recv_body(&mut conn, stream_id, &mut buf)
                        {
                            debug!(
                                "got {} bytes of response data on stream {}",
                                read, stream_id
                            );

                            print!("{}", unsafe {
                                std::str::from_utf8_unchecked(&buf[..read])
                            });
                        }
                    },

                    Ok((_stream_id, quiche::h3::Event::Finished)) => {
                        info!(
                            "response received in {:?}, closing...",
                            req_start.elapsed()
                        );

                        match conn.close(true, 0x00, b"kthxbye") {
                            // Already closed.
                            Ok(_) | Err(quiche::Error::Done) => (),

                            Err(e) => panic!("error closing conn: {:?}", e),
                        }

                        break;
                    },

                    Err(quiche::h3::Error::Done) => {
                        break;
                    },

                    Err(e) => {
                        error!("HTTP/3 processing failed: {:?}", e);

                        break;
                    },
                }
            }
        }

        // Generate outgoing QUIC packets and send them on the UDP socket, until
        // quiche reports that there are no more packets to be sent.
        loop {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("done writing");
                    break;
                },

                Err(e) => {
                    error!("send failed: {:?}", e);
                    conn.close(false, 0x1, b"fail").ok();
                    break;
                },
            };

            if let Err(e) = socket.send(&out[..write]) {
                if e.kind() == std::io::ErrorKind::WouldBlock {
                    debug!("send() would block");
                    break;
                }

                panic!("send() failed: {:?}", e);
            }

            debug!("written {}", write);
        }

        if conn.is_closed() {
            info!("connection closed, {:?}", conn.stats());
            break;
        }
    }
}
<commit_msg>http3-client: panic on custom header error<commit_after>// Copyright (C) 2019, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate log;

use std::net::ToSocketAddrs;

use ring::rand::*;

const MAX_DATAGRAM_SIZE: usize = 1350;

const USAGE: &str = "Usage:
  http3-client [options] URL
  http3-client -h | --help

Options:
  --method METHOD          Use the given HTTP request method [default: GET].
  --body FILE              Send the given file as request body.
  --max-data BYTES         Connection-wide flow control limit [default: 10000000].
  --max-stream-data BYTES  Per-stream flow control limit [default: 1000000].
  --wire-version VERSION   The version number to send to the server [default: babababa].
  --no-verify              Don't verify server's certificate.
  --no-grease              Don't send GREASE.
  -H --header HEADER ...   Add a request header.
  -h --help                Show this screen.
";

fn main() {
    let mut buf = [0; 65535];
    let mut out = [0; MAX_DATAGRAM_SIZE];

    env_logger::builder()
        .default_format_timestamp_nanos(true)
        .init();

    let args = docopt::Docopt::new(USAGE)
        .and_then(|dopt| dopt.parse())
        .unwrap_or_else(|e| e.exit());

    let max_data = args.get_str("--max-data");
    let max_data = u64::from_str_radix(max_data, 10).unwrap();

    let max_stream_data = args.get_str("--max-stream-data");
    let max_stream_data = u64::from_str_radix(max_stream_data, 10).unwrap();

    let version = args.get_str("--wire-version");
    let version = u32::from_str_radix(version, 16).unwrap();

    let url = url::Url::parse(args.get_str("URL")).unwrap();

    // Request headers (can be multiple).
    let req_headers = args.get_vec("--header");

    // Setup the event loop.
    let poll = mio::Poll::new().unwrap();
    let mut events = mio::Events::with_capacity(1024);

    // Resolve server address.
    let peer_addr = url.to_socket_addrs().unwrap().next().unwrap();
    info!("connecting to {:}", peer_addr);

    // Bind to INADDR_ANY or IN6ADDR_ANY depending on the IP family of the
    // server address. This is needed on macOS and BSD variants that don't
    // support binding to IN6ADDR_ANY for both v4 and v6.
    let bind_addr = match peer_addr {
        std::net::SocketAddr::V4(_) => "0.0.0.0:0",
        std::net::SocketAddr::V6(_) => "[::]:0",
    };

    // Create the UDP socket backing the QUIC connection, and register it with
    // the event loop.
    let socket = std::net::UdpSocket::bind(bind_addr).unwrap();
    socket.connect(peer_addr).unwrap();

    let socket = mio::net::UdpSocket::from_socket(socket).unwrap();
    poll.register(
        &socket,
        mio::Token(0),
        mio::Ready::readable(),
        mio::PollOpt::edge(),
    )
    .unwrap();

    // Create the configuration for the QUIC connection.
    let mut config = quiche::Config::new(version).unwrap();

    config.verify_peer(true);

    config
        .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
        .unwrap();

    config.set_idle_timeout(5000);
    config.set_max_packet_size(MAX_DATAGRAM_SIZE as u64);
    config.set_initial_max_data(max_data);
    config.set_initial_max_stream_data_bidi_local(max_stream_data);
    config.set_initial_max_stream_data_bidi_remote(max_stream_data);
    config.set_initial_max_stream_data_uni(max_stream_data);
    config.set_initial_max_streams_bidi(100);
    config.set_initial_max_streams_uni(100);
    config.set_disable_migration(true);

    let mut http3_conn = None;

    if args.get_bool("--no-verify") {
        config.verify_peer(false);
    }

    if args.get_bool("--no-grease") {
        config.grease(false);
    }

    if std::env::var_os("SSLKEYLOGFILE").is_some() {
        config.log_keys();
    }

    // Generate a random source connection ID for the connection.
    let mut scid = [0; quiche::MAX_CONN_ID_LEN];
    SystemRandom::new().fill(&mut scid[..]).unwrap();

    // Create a QUIC connection and initiate handshake.
    let mut conn = quiche::connect(url.domain(), &scid, &mut config).unwrap();

    let write = match conn.send(&mut out) {
        Ok(v) => v,

        Err(e) => panic!("initial send failed: {:?}", e),
    };

    while let Err(e) = socket.send(&out[..write]) {
        if e.kind() == std::io::ErrorKind::WouldBlock {
            debug!("send() would block");
            continue;
        }

        panic!("send() failed: {:?}", e);
    }

    debug!("written {}", write);

    let req_start = std::time::Instant::now();

    loop {
        poll.poll(&mut events, conn.timeout()).unwrap();

        // Read incoming UDP packets from the socket and feed them to quiche,
        // until there are no more packets to read.
        'read: loop {
            // If the event loop reported no events, it means that the timeout
            // has expired, so handle it without attempting to read packets. We
            // will then proceed with the send loop.
            if events.is_empty() {
                debug!("timed out");

                conn.on_timeout();

                break 'read;
            }

            let len = match socket.recv(&mut buf) {
                Ok(v) => v,

                Err(e) => {
                    // There are no more UDP packets to read, so end the read
                    // loop.
                    if e.kind() == std::io::ErrorKind::WouldBlock {
                        debug!("recv() would block");
                        break 'read;
                    }

                    panic!("recv() failed: {:?}", e);
                },
            };

            debug!("got {} bytes", len);

            // Process potentially coalesced packets.
            let read = match conn.recv(&mut buf[..len]) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("done reading");
                    break;
                },

                Err(e) => {
                    error!("recv failed: {:?}", e);
                    break 'read;
                },
            };

            debug!("processed {} bytes", read);
        }

        if conn.is_closed() {
            info!("connection closed, {:?}", conn.stats());
            break;
        }

        // Create a new HTTP/3 connection and end an HTTP request as soon as
        // the QUIC connection is established.
        if conn.is_established() && http3_conn.is_none() {
            let h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();

            let mut h3_conn =
                quiche::h3::Connection::with_transport(&mut conn, &h3_config)
                    .unwrap();

            let mut path = String::from(url.path());

            if let Some(query) = url.query() {
                path.push('?');
                path.push_str(query);
            }

            let mut req = vec![
                quiche::h3::Header::new(":method", args.get_str("--method")),
                quiche::h3::Header::new(":scheme", url.scheme()),
                quiche::h3::Header::new(":authority", url.host_str().unwrap()),
                quiche::h3::Header::new(":path", &path),
                quiche::h3::Header::new("user-agent", "quiche"),
            ];

            // Add custom headers to the request.
            for header in &req_headers {
                let header_split: Vec<&str> = header.splitn(2, ": ").collect();
                if header_split.len() != 2 {
                    panic!("malformed header provided - \"{}\"", header);
                }

                req.push(quiche::h3::Header::new(
                    header_split[0],
                    header_split[1],
                ));
            }

            info!("sending HTTP request {:?}", req);

            let body = if args.get_bool("--body") {
                std::fs::read(args.get_str("--body")).ok()
            } else {
                None
            };

            if body.is_some() {
                req.push(quiche::h3::Header::new(
                    "content-length",
                    &body.as_ref().unwrap().len().to_string(),
                ));
            }

            let s = match h3_conn.send_request(&mut conn, &req, body.is_none()) {
                Ok(stream_id) => stream_id,

                Err(e) => {
                    error!("failed to send request {:?}", e);
                    break;
                },
            };

            if let Some(body) = body {
                if let Err(e) = h3_conn.send_body(&mut conn, s, &body, true) {
                    error!("failed to send request body {:?}", e);
                    break;
                }
            }

            http3_conn = Some(h3_conn);
        }

        if let Some(http3_conn) = &mut http3_conn {
            // Process HTTP/3 events.
            loop {
                match http3_conn.poll(&mut conn) {
                    Ok((stream_id, quiche::h3::Event::Headers(headers))) => {
                        info!(
                            "got response headers {:?} on stream id {}",
                            headers, stream_id
                        );
                    },

                    Ok((stream_id, quiche::h3::Event::Data)) => {
                        if let Ok(read) =
                            http3_conn.recv_body(&mut conn, stream_id, &mut buf)
                        {
                            debug!(
                                "got {} bytes of response data on stream {}",
                                read, stream_id
                            );

                            print!("{}", unsafe {
                                std::str::from_utf8_unchecked(&buf[..read])
                            });
                        }
                    },

                    Ok((_stream_id, quiche::h3::Event::Finished)) => {
                        info!(
                            "response received in {:?}, closing...",
                            req_start.elapsed()
                        );

                        match conn.close(true, 0x00, b"kthxbye") {
                            // Already closed.
                            Ok(_) | Err(quiche::Error::Done) => (),

                            Err(e) => panic!("error closing conn: {:?}", e),
                        }

                        break;
                    },

                    Err(quiche::h3::Error::Done) => {
                        break;
                    },

                    Err(e) => {
                        error!("HTTP/3 processing failed: {:?}", e);

                        break;
                    },
                }
            }
        }

        // Generate outgoing QUIC packets and send them on the UDP socket, until
        // quiche reports that there are no more packets to be sent.
        loop {
            let write = match conn.send(&mut out) {
                Ok(v) => v,

                Err(quiche::Error::Done) => {
                    debug!("done writing");
                    break;
                },

                Err(e) => {
                    error!("send failed: {:?}", e);
                    conn.close(false, 0x1, b"fail").ok();
                    break;
                },
            };

            if let Err(e) = socket.send(&out[..write]) {
                if e.kind() == std::io::ErrorKind::WouldBlock {
                    debug!("send() would block");
                    break;
                }

                panic!("send() failed: {:?}", e);
            }

            debug!("written {}", write);
        }

        if conn.is_closed() {
            info!("connection closed, {:?}", conn.stats());
            break;
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::ops::{DerefMut, Deref};

use toml::Value;

use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagtag::tag::Tag;
use libimagtag::tagable::Tagable;
use libimagtag::result::Result as TagResult;

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let mut lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.err().unwrap()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();

                {
                    let mut header = entry.get_header_mut();
                    let setres = header.set("note", Value::Table(BTreeMap::new()));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.err().unwrap()))));
                    }

                    let setres = header.set("note.name", Value::String(name));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.err().unwrap()))));
                    }
                }

                *entry.get_content_mut() = text;
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.deref_mut().get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let mut header = self.entry.deref().get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.deref_mut().get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.deref().get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

    pub fn all_notes(store: &Store) -> Result<NoteIterator> {
        store.retrieve_for_module("notes")
            .map(|iter| NoteIterator::new(store, iter))
            .map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.deref().get_tags()
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> TagResult<()> {
        self.entry.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: &Tag) -> TagResult<bool> {
        self.entry.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &Vec<Tag>) -> TagResult<bool> {
        self.entry.deref().has_tags(ts)
    }

}

trait FromStoreId {
    fn from_storeid<'a>(&'a Store, StoreId) -> Result<Note<'a>>;
}

impl<'a> FromStoreId for Note<'a> {

    fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Note<'b>> {
        debug!("Loading note from storeid: '{:?}'", id);
        match store.retrieve(id) {
            Err(e)    => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
            Ok(entry) => Ok(Note { entry: entry }),
        }
    }

}

pub struct NoteIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> NoteIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> {
        NoteIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for NoteIterator<'a> {
    type Item = Result<Note<'a>>;

    fn next(&mut self) -> Option<Result<Note<'a>>> {
        self.iditer
            .next()
            .map(|id| Note::from_storeid(self.store, id))
    }

}

<commit_msg>lib: Remove unneeded "mut" keywords<commit_after>use std::collections::BTreeMap;
use std::ops::{DerefMut, Deref};

use toml::Value;

use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagtag::tag::Tag;
use libimagtag::tagable::Tagable;
use libimagtag::result::Result as TagResult;

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.err().unwrap()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();

                {
                    let mut header = entry.get_header_mut();
                    let setres = header.set("note", Value::Table(BTreeMap::new()));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.err().unwrap()))));
                    }

                    let setres = header.set("note.name", Value::String(name));
                    if setres.is_err() {
                        let kind = NEK::StoreWriteError;
                        return Err(NE::new(kind, Some(Box::new(setres.err().unwrap()))));
                    }
                }

                *entry.get_content_mut() = text;
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.deref_mut().get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let header = self.entry.deref().get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.deref_mut().get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.deref().get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

    pub fn all_notes(store: &Store) -> Result<NoteIterator> {
        store.retrieve_for_module("notes")
            .map(|iter| NoteIterator::new(store, iter))
            .map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.deref().get_tags()
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> TagResult<()> {
        self.entry.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: &Tag) -> TagResult<bool> {
        self.entry.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &Vec<Tag>) -> TagResult<bool> {
        self.entry.deref().has_tags(ts)
    }

}

trait FromStoreId {
    fn from_storeid<'a>(&'a Store, StoreId) -> Result<Note<'a>>;
}

impl<'a> FromStoreId for Note<'a> {

    fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Note<'b>> {
        debug!("Loading note from storeid: '{:?}'", id);
        match store.retrieve(id) {
            Err(e)    => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
            Ok(entry) => Ok(Note { entry: entry }),
        }
    }

}

pub struct NoteIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> NoteIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> {
        NoteIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for NoteIterator<'a> {
    type Item = Result<Note<'a>>;

    fn next(&mut self) -> Option<Result<Note<'a>>> {
        self.iditer
            .next()
            .map(|id| Note::from_storeid(self.store, id))
    }

}

<|endoftext|>


<commit_before>//! Metrics SDK API
use crate::metrics::{AsyncRunner, Descriptor, Measurement, Number, Result};
use crate::{Context, KeyValue};
use std::any::Any;
use std::fmt;
use std::sync::Arc;

/// The interface an SDK must implement to supply a Meter implementation.
pub trait MeterCore: fmt::Debug {
    /// Atomically record a batch of measurements.
    fn record_batch_with_context(
        &self,
        cx: &Context,
        labels: &[KeyValue],
        measurements: Vec<Measurement>,
    );

    /// Create a new synchronous instrument implementation.
    fn new_sync_instrument(
        &self,
        descriptor: Descriptor,
    ) -> Result<Arc<dyn SyncInstrumentCore + Send + Sync>>;

    /// Create a new asynchronous instrument implementation.
    fn new_async_instrument(
        &self,
        descriptor: Descriptor,
        runner: AsyncRunner,
    ) -> Result<Arc<dyn AsyncInstrumentCore + Send + Sync>>;
}

/// A common interface for synchronous and asynchronous instruments.
pub trait InstrumentCore: fmt::Debug {
    /// Description of the instrument's descriptor
    fn descriptor(&self) -> &Descriptor;
}

/// The implementation-level interface to a generic synchronous instrument
/// (e.g., ValueRecorder and Counter instruments).
pub trait SyncInstrumentCore: InstrumentCore + Send + Sync {
    /// Creates an implementation-level bound instrument, binding a label set
    /// with this instrument implementation.
    fn bind(&self, labels: &'_ [KeyValue]) -> Arc<dyn SyncBoundInstrumentCore + Send + Sync>;

    /// Capture a single synchronous metric event.
    fn record_one(&self, number: Number, labels: &'_ [KeyValue]);

    /// Returns self as any
    fn as_any(&self) -> &dyn Any;
}

/// The implementation-level interface to a generic synchronous bound instrument
pub trait SyncBoundInstrumentCore: fmt::Debug + Send + Sync {
    /// Capture a single synchronous metric event.
    fn record_one(&self, number: Number);
}

/// An implementation-level interface to an asynchronous instrument (e.g.,
/// Observer instruments).
pub trait AsyncInstrumentCore: InstrumentCore {
    /// The underlying type as `Any` to support downcasting.
    fn as_any(&self) -> &dyn Any;
}
<commit_msg>Adds Send + Sync to Async instruments (metrics) (#422)<commit_after>//! Metrics SDK API
use crate::metrics::{AsyncRunner, Descriptor, Measurement, Number, Result};
use crate::{Context, KeyValue};
use std::any::Any;
use std::fmt;
use std::sync::Arc;

/// The interface an SDK must implement to supply a Meter implementation.
pub trait MeterCore: fmt::Debug {
    /// Atomically record a batch of measurements.
    fn record_batch_with_context(
        &self,
        cx: &Context,
        labels: &[KeyValue],
        measurements: Vec<Measurement>,
    );

    /// Create a new synchronous instrument implementation.
    fn new_sync_instrument(
        &self,
        descriptor: Descriptor,
    ) -> Result<Arc<dyn SyncInstrumentCore + Send + Sync>>;

    /// Create a new asynchronous instrument implementation.
    fn new_async_instrument(
        &self,
        descriptor: Descriptor,
        runner: AsyncRunner,
    ) -> Result<Arc<dyn AsyncInstrumentCore + Send + Sync>>;
}

/// A common interface for synchronous and asynchronous instruments.
pub trait InstrumentCore: fmt::Debug {
    /// Description of the instrument's descriptor
    fn descriptor(&self) -> &Descriptor;
}

/// The implementation-level interface to a generic synchronous instrument
/// (e.g., ValueRecorder and Counter instruments).
pub trait SyncInstrumentCore: InstrumentCore + Send + Sync {
    /// Creates an implementation-level bound instrument, binding a label set
    /// with this instrument implementation.
    fn bind(&self, labels: &'_ [KeyValue]) -> Arc<dyn SyncBoundInstrumentCore + Send + Sync>;

    /// Capture a single synchronous metric event.
    fn record_one(&self, number: Number, labels: &'_ [KeyValue]);

    /// Returns self as any
    fn as_any(&self) -> &dyn Any;
}

/// The implementation-level interface to a generic synchronous bound instrument
pub trait SyncBoundInstrumentCore: fmt::Debug + Send + Sync {
    /// Capture a single synchronous metric event.
    fn record_one(&self, number: Number);
}

/// An implementation-level interface to an asynchronous instrument (e.g.,
/// Observer instruments).
pub trait AsyncInstrumentCore: InstrumentCore + Send + Sync {
    /// The underlying type as `Any` to support downcasting.
    fn as_any(&self) -> &dyn Any;
}
<|endoftext|>


<commit_before>//! Things pertaining to the RFC 7230 `token` grammar rule.
//!
//! RFC 7230 grammar:
//!
//! ```abnf
//! token          = 1*tchar
//!
//! tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
//!                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
//!                / DIGIT / ALPHA
//!                ; any VCHAR, except delimiters
//! ```
//!
//! Possibly of interest is that RFC 2616 actually defined things the other way
//! round, with the primary definition being that of what is now labelled the
//! delimiters but which was at that time known as *separators*:
//!
//! ```bnf
//! [REMEMBER THIS RULE IS OBSOLETE!]
//! separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
//!           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
//!           | "}" | SP | HT
//! ```

use std::fmt;
use std::str;

/// tchar: a token character; any VCHAR, except delimiters.
#[inline]
pub fn is_tchar(o: u8) -> bool {
    o == b'!' || o == b'#' || o == b'$' || o == b'%' || o == b'&' || o == b'\'' ||
    o == b'*' || o == b'+' || o == b'-' || o == b'.' || o == b'^' || o == b'_' ||
    o == b'`' || o == b'|' || o == b'~' || (o >= b'0' && o <= b'9') ||
    (o >= b'A' && o <= b'Z') || (o >= b'a' && o <= b'z')
}

/// A type representing an RFC 7230 `token`.
///
/// This permits strict character set control in a way that a simple `Vec<u8>`
/// or `String` would not.
///
/// This may be either owned, corresponding to `String`/`Vec<u8>`, or a slice,
/// corresponding to `&str`/`&[u8]`.
#[deriving(Clone, Hash)]
pub enum Token<'a> {
    /// A token backed by a vector (`Vec<u8>`).
    #[doc(hidden)]
    Owned {
        #[doc(hidden)]
        pub _bytes: Vec<u8>,
    },
    /// A token backed by a slice (`&[u8]`).
    #[doc(hidden)]
    Slice {
        #[doc(hidden)]
        pub _bytes: &'a [u8],
    },
}

impl<'a> fmt::Show for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Owned { ref _bytes } => f.write(_bytes.as_slice()),
            Slice { ref _bytes } => f.write(*_bytes),
        }
    }
}

impl<'a> PartialOrd for Token<'a> {
    #[inline]
    fn partial_cmp(&self, other: &Token<'a>) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}

impl<'a> Ord for Token<'a> {
    #[inline]
    fn cmp(&self, other: &Token<'a>) -> Ordering {
        self.as_bytes().cmp(other.as_bytes())
    }
}

impl<'a> PartialEq for Token<'a> {
    #[inline]
    fn eq(&self, other: &Token<'a>) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl<'a> Eq for Token<'a> { }

impl<'a> Token<'a> {
    /// The number of bytes in the token.
    #[inline]
    pub fn len(&self) -> uint {
        self.as_bytes().len()
    }

    /// Whether the token is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Token<'static> {
    /// Create a `Token` from a sequence of bytes.
    ///
    /// Returns `Err` with the original vector if not every byte in the vector
    /// is an RFC 7230 `tchar`.
    #[inline]
    pub fn from_vec(vec: Vec<u8>) -> Result<Token<'static>, Vec<u8>> {
        if vec.iter().all(|&c| is_tchar(c)) {
            Ok(Owned { _bytes: vec })
        } else {
            Err(vec)
        }
    }

    /// Create a `Token` from a sequence of bytes, without checking it.
    ///
    /// Be very careful calling this.
    #[inline]
    pub unsafe fn from_vec_nocheck(vec: Vec<u8>) -> Token<'static> {
        Owned { _bytes: vec }
    }
}

impl<'a> Token<'a> {
    /// Create a `Token` from a sequence of bytes.
    ///
    /// Returns `None` if not every byte in the slice is a RFC 7230 `tchar`.
    pub fn from_slice(slice: &[u8]) -> Option<Token> {
        if slice.iter().all(|&c| is_tchar(c)) {
            Some(Slice { _bytes: slice })
        } else {
            None
        }
    }

    /// Create a `Token` from a sequence of bytes, without checking it.
    ///
    /// Be very careful calling this.
    pub unsafe fn from_slice_nocheck(slice: &[u8]) -> Token {
        Slice { _bytes: slice }
    }

    /// Make a copy of the token, based around a slice of `self`.
    ///
    /// This is practically a free operation.
    #[inline]
    pub fn slice(&self) -> Token {
        Slice { _bytes: self.as_bytes() }
    }

    /// Change a slice token into an owned token.
    ///
    /// An owned token will be unchanged.
    #[inline]
    pub fn into_owned(self) -> Token<'static> {
        match self {
            Owned { _bytes } => Owned { _bytes: _bytes },
            Slice { _bytes } => Owned { _bytes: _bytes.to_vec() },
        }
    }

    /// Get a string slice of the contents of the token.
    #[inline]
    pub fn as_str(&self) -> &str {
        // `token` is a subset of ASCII, so this cannot produce invalid data.
        unsafe {
            str::raw::from_utf8(self.as_bytes())
        }
    }

    /// Get a slice of the bytes in the token.
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        match *self {
            Owned { ref _bytes } => _bytes.as_slice(),
            Slice { ref _bytes } => _bytes.as_slice(),
        }
    }
}
<commit_msg>Implement Deref<str> for Token.<commit_after>//! Things pertaining to the RFC 7230 `token` grammar rule.
//!
//! RFC 7230 grammar:
//!
//! ```abnf
//! token          = 1*tchar
//!
//! tchar          = "!" / "#" / "$" / "%" / "&" / "'" / "*"
//!                / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
//!                / DIGIT / ALPHA
//!                ; any VCHAR, except delimiters
//! ```
//!
//! Possibly of interest is that RFC 2616 actually defined things the other way
//! round, with the primary definition being that of what is now labelled the
//! delimiters but which was at that time known as *separators*:
//!
//! ```bnf
//! [REMEMBER THIS RULE IS OBSOLETE!]
//! separators: "(" | ")" | "<" | ">" | "@" | "," | ";" | ":"
//!           | "\" | <"> | "/" | "[" | "]" | "?" | "=" | "{"
//!           | "}" | SP | HT
//! ```

use std::fmt;
use std::str;

/// tchar: a token character; any VCHAR, except delimiters.
#[inline]
pub fn is_tchar(o: u8) -> bool {
    o == b'!' || o == b'#' || o == b'$' || o == b'%' || o == b'&' || o == b'\'' ||
    o == b'*' || o == b'+' || o == b'-' || o == b'.' || o == b'^' || o == b'_' ||
    o == b'`' || o == b'|' || o == b'~' || (o >= b'0' && o <= b'9') ||
    (o >= b'A' && o <= b'Z') || (o >= b'a' && o <= b'z')
}

/// A type representing an RFC 7230 `token`.
///
/// This permits strict character set control in a way that a simple `Vec<u8>`
/// or `String` would not.
///
/// This may be either owned, corresponding to `String`/`Vec<u8>`, or a slice,
/// corresponding to `&str`/`&[u8]`.
#[deriving(Clone, Hash)]
pub enum Token<'a> {
    /// A token backed by a vector (`Vec<u8>`).
    #[doc(hidden)]
    Owned {
        #[doc(hidden)]
        pub _bytes: Vec<u8>,
    },
    /// A token backed by a slice (`&[u8]`).
    #[doc(hidden)]
    Slice {
        #[doc(hidden)]
        pub _bytes: &'a [u8],
    },
}

impl<'a> fmt::Show for Token<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Owned { ref _bytes } => f.write(_bytes.as_slice()),
            Slice { ref _bytes } => f.write(*_bytes),
        }
    }
}

impl<'a> PartialOrd for Token<'a> {
    #[inline]
    fn partial_cmp(&self, other: &Token<'a>) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}

impl<'a> Ord for Token<'a> {
    #[inline]
    fn cmp(&self, other: &Token<'a>) -> Ordering {
        self.as_bytes().cmp(other.as_bytes())
    }
}

impl<'a> PartialEq for Token<'a> {
    #[inline]
    fn eq(&self, other: &Token<'a>) -> bool {
        self.as_bytes() == other.as_bytes()
    }
}

impl<'a> Eq for Token<'a> { }

impl<'a> Token<'a> {
    /// The number of bytes in the token.
    #[inline]
    pub fn len(&self) -> uint {
        self.as_bytes().len()
    }

    /// Whether the token is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

impl Token<'static> {
    /// Create a `Token` from a sequence of bytes.
    ///
    /// Returns `Err` with the original vector if not every byte in the vector
    /// is an RFC 7230 `tchar`.
    #[inline]
    pub fn from_vec(vec: Vec<u8>) -> Result<Token<'static>, Vec<u8>> {
        if vec.iter().all(|&c| is_tchar(c)) {
            Ok(Owned { _bytes: vec })
        } else {
            Err(vec)
        }
    }

    /// Create a `Token` from a sequence of bytes, without checking it.
    ///
    /// Be very careful calling this.
    #[inline]
    pub unsafe fn from_vec_nocheck(vec: Vec<u8>) -> Token<'static> {
        Owned { _bytes: vec }
    }
}

impl<'a> Token<'a> {
    /// Create a `Token` from a sequence of bytes.
    ///
    /// Returns `None` if not every byte in the slice is a RFC 7230 `tchar`.
    pub fn from_slice(slice: &[u8]) -> Option<Token> {
        if slice.iter().all(|&c| is_tchar(c)) {
            Some(Slice { _bytes: slice })
        } else {
            None
        }
    }

    /// Create a `Token` from a sequence of bytes, without checking it.
    ///
    /// Be very careful calling this.
    pub unsafe fn from_slice_nocheck(slice: &[u8]) -> Token {
        Slice { _bytes: slice }
    }

    /// Make a copy of the token, based around a slice of `self`.
    ///
    /// This is practically a free operation.
    #[inline]
    pub fn slice(&self) -> Token {
        Slice { _bytes: self.as_bytes() }
    }

    /// Change a slice token into an owned token.
    ///
    /// An owned token will be unchanged.
    #[inline]
    pub fn into_owned(self) -> Token<'static> {
        match self {
            Owned { _bytes } => Owned { _bytes: _bytes },
            Slice { _bytes } => Owned { _bytes: _bytes.to_vec() },
        }
    }

    /// Get a string slice of the contents of the token.
    #[inline]
    pub fn as_str(&self) -> &str {
        // `token` is a subset of ASCII, so this cannot produce invalid data.
        unsafe {
            str::raw::from_utf8(self.as_bytes())
        }
    }

    /// Get a slice of the bytes in the token.
    #[inline]
    pub fn as_bytes(&self) -> &[u8] {
        match *self {
            Owned { ref _bytes } => _bytes.as_slice(),
            Slice { ref _bytes } => _bytes.as_slice(),
        }
    }
}

impl<'a> Deref<str> for Token<'a> {
    fn deref(&self) -> &str {
        self.as_str()
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over the input areas of this window and its children.
    ///
    /// Used for the fast path of the check in `matching`.
    input_bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    ///
    /// You need to provide a `contains_point` function which checks if the point (in surface-local
    /// coordinates) is within the input region of the given `SurfaceAttributes`.
    fn matching<F>(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
        contains_point: F,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))>
    where
        F: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
    {
        if !self.input_bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if contains_point(attributes, surface_local_point) {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update<F>(&mut self, ctoken: CompositorToken<R>, get_size: F)
    where
        F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    // The input region is intersected with the surface size, so the surface size
                    // can serve as an approximation for the input bounding box.
                    if let Some((w, h)) = get_size(attributes) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }
                        // update the bounding box
                        if x < min_x {
                            min_x = x;
                        }
                        if y < min_y {
                            min_y = y;
                        }
                        if x + w > max_x {
                            max_x = x + w;
                        }
                        if y + h > max_y {
                            max_y = y + w;
                        }
                        TraversalAction::DoChildren((x, y))
                    } else {
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.input_bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }
}

pub struct WindowMap<R, F, G> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
    /// A function returning the surface size.
    get_size: F,
    /// A function that checks if the point is in the surface's input region.
    contains_point: G,
}

impl<R, F, G> WindowMap<R, F, G>
where
    F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    G: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>, get_size: F, contains_point: G) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
            get_size,
            contains_point,
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            input_bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken, &self.get_size);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken, &self.get_size);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }
}
<commit_msg>anvil.window_map: add Kind::equals<commit_after>use std::cell::RefCell;

use smithay::{
    reexports::wayland_server::protocol::wl_surface,
    utils::Rectangle,
    wayland::{
        compositor::{roles::Role, CompositorToken, SubsurfaceRole, SurfaceAttributes, TraversalAction},
        shell::{
            legacy::{ShellSurface, ShellSurfaceRole},
            xdg::{ToplevelSurface, XdgSurfaceRole},
        },
    },
};

pub enum Kind<R> {
    Xdg(ToplevelSurface<R>),
    Wl(ShellSurface<R>),
}

impl<R> Kind<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn alive(&self) -> bool {
        match *self {
            Kind::Xdg(ref t) => t.alive(),
            Kind::Wl(ref t) => t.alive(),
        }
    }
    pub fn get_surface(&self) -> Option<&wl_surface::WlSurface> {
        match *self {
            Kind::Xdg(ref t) => t.get_surface(),
            Kind::Wl(ref t) => t.get_surface(),
        }
    }

    /// Do this handle and the other one actually refer to the same toplevel surface?
    pub fn equals(&self, other: &Self) -> bool {
        match (self, other) {
            (Kind::Xdg(a), Kind::Xdg(b)) => a.equals(b),
            (Kind::Wl(a), Kind::Wl(b)) => a.equals(b),
            _ => false,
        }
    }
}

struct Window<R> {
    location: (i32, i32),
    /// A bounding box over the input areas of this window and its children.
    ///
    /// Used for the fast path of the check in `matching`.
    input_bbox: Rectangle,
    toplevel: Kind<R>,
}

impl<R> Window<R>
where
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    /// Finds the topmost surface under this point if any and returns it together with the location of this
    /// surface.
    ///
    /// You need to provide a `contains_point` function which checks if the point (in surface-local
    /// coordinates) is within the input region of the given `SurfaceAttributes`.
    fn matching<F>(
        &self,
        point: (f64, f64),
        ctoken: CompositorToken<R>,
        contains_point: F,
    ) -> Option<(wl_surface::WlSurface, (f64, f64))>
    where
        F: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
    {
        if !self.input_bbox.contains((point.0 as i32, point.1 as i32)) {
            return None;
        }
        // need to check more carefully
        let found = RefCell::new(None);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                self.location,
                |wl_surface, attributes, role, &(mut x, mut y)| {
                    if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                        x += subdata.location.0;
                        y += subdata.location.1;
                    }

                    let surface_local_point = (point.0 - x as f64, point.1 - y as f64);
                    if contains_point(attributes, surface_local_point) {
                        *found.borrow_mut() = Some((wl_surface.clone(), (x as f64, y as f64)));
                    }

                    TraversalAction::DoChildren((x, y))
                },
                |_, _, _, _| {},
                |_, _, _, _| {
                    // only continue if the point is not found
                    found.borrow().is_none()
                },
            );
        }
        found.into_inner()
    }

    fn self_update<F>(&mut self, ctoken: CompositorToken<R>, get_size: F)
    where
        F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    {
        let (base_x, base_y) = self.location;
        let (mut min_x, mut min_y, mut max_x, mut max_y) = (base_x, base_y, base_x, base_y);
        if let Some(wl_surface) = self.toplevel.get_surface() {
            ctoken.with_surface_tree_downward(
                wl_surface,
                (base_x, base_y),
                |_, attributes, role, &(mut x, mut y)| {
                    // The input region is intersected with the surface size, so the surface size
                    // can serve as an approximation for the input bounding box.
                    if let Some((w, h)) = get_size(attributes) {
                        if let Ok(subdata) = Role::<SubsurfaceRole>::data(role) {
                            x += subdata.location.0;
                            y += subdata.location.1;
                        }
                        // update the bounding box
                        if x < min_x {
                            min_x = x;
                        }
                        if y < min_y {
                            min_y = y;
                        }
                        if x + w > max_x {
                            max_x = x + w;
                        }
                        if y + h > max_y {
                            max_y = y + w;
                        }
                        TraversalAction::DoChildren((x, y))
                    } else {
                        TraversalAction::SkipChildren
                    }
                },
                |_, _, _, _| {},
                |_, _, _, _| true,
            );
        }
        self.input_bbox = Rectangle {
            x: min_x,
            y: min_y,
            width: max_x - min_x,
            height: max_y - min_y,
        };
    }
}

pub struct WindowMap<R, F, G> {
    ctoken: CompositorToken<R>,
    windows: Vec<Window<R>>,
    /// A function returning the surface size.
    get_size: F,
    /// A function that checks if the point is in the surface's input region.
    contains_point: G,
}

impl<R, F, G> WindowMap<R, F, G>
where
    F: Fn(&SurfaceAttributes) -> Option<(i32, i32)>,
    G: Fn(&SurfaceAttributes, (f64, f64)) -> bool,
    R: Role<SubsurfaceRole> + Role<XdgSurfaceRole> + Role<ShellSurfaceRole> + 'static,
{
    pub fn new(ctoken: CompositorToken<R>, get_size: F, contains_point: G) -> Self {
        WindowMap {
            ctoken,
            windows: Vec::new(),
            get_size,
            contains_point,
        }
    }

    pub fn insert(&mut self, toplevel: Kind<R>, location: (i32, i32)) {
        let mut window = Window {
            location,
            input_bbox: Rectangle::default(),
            toplevel,
        };
        window.self_update(self.ctoken, &self.get_size);
        self.windows.insert(0, window);
    }

    pub fn get_surface_under(&self, point: (f64, f64)) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        for w in &self.windows {
            if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
                return Some(surface);
            }
        }
        None
    }

    pub fn get_surface_and_bring_to_top(
        &mut self,
        point: (f64, f64),
    ) -> Option<(wl_surface::WlSurface, (f64, f64))> {
        let mut found = None;
        for (i, w) in self.windows.iter().enumerate() {
            if let Some(surface) = w.matching(point, self.ctoken, &self.contains_point) {
                found = Some((i, surface));
                break;
            }
        }
        if let Some((i, surface)) = found {
            let winner = self.windows.remove(i);
            self.windows.insert(0, winner);
            Some(surface)
        } else {
            None
        }
    }

    pub fn with_windows_from_bottom_to_top<Func>(&self, mut f: Func)
    where
        Func: FnMut(&Kind<R>, (i32, i32)),
    {
        for w in self.windows.iter().rev() {
            f(&w.toplevel, w.location)
        }
    }

    pub fn refresh(&mut self) {
        self.windows.retain(|w| w.toplevel.alive());
        for w in &mut self.windows {
            w.self_update(self.ctoken, &self.get_size);
        }
    }

    pub fn clear(&mut self) {
        self.windows.clear();
    }
}
<|endoftext|>


<commit_before>use tokio;
use pretty_env_logger;
use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use std::fs::File;

use a2::{
    Client,
    Endpoint,
    NotificationBuilder,
    NotificationOptions,
    PlainNotificationBuilder,
};

use futures::{
    future::lazy,
    Future,
};

// An example client connectiong to APNs with a JWT token
fn main() {
    pretty_env_logger::init();

    let mut key_file = String::new();
    let mut team_id = String::new();
    let mut key_id = String::new();
    let mut device_token = String::new();
    let mut message = String::from("Ch-check it out!");
    let mut sandbox = false;
    let mut topic: Option<String> = None;

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("APNs token-based push");
        ap.refer(&mut key_file)
            .add_option(&["-p", "--pkcs8"], Store, "Private key PKCS8");
        ap.refer(&mut team_id)
            .add_option(&["-t", "--team_id"], Store, "APNs team ID");
        ap.refer(&mut key_id)
            .add_option(&["-k", "--key_id"], Store, "APNs key ID");
        ap.refer(&mut device_token).add_option(
            &["-d", "--device_token"],
            Store,
            "APNs device token",
        );
        ap.refer(&mut message)
            .add_option(&["-m", "--message"], Store, "Notification message");
        ap.refer(&mut sandbox).add_option(
            &["-s", "--sandbox"],
            StoreTrue,
            "Use the development APNs servers",
        );
        ap.refer(&mut topic)
            .add_option(&["-o", "--topic"], StoreOption, "APNS topic");
        ap.parse_args_or_exit();
    }

    // Read the private key from disk
    let mut private_key = File::open(key_file).unwrap();

    // Which service to call, test or production?
    let endpoint = if sandbox {
        Endpoint::Sandbox
    } else {
        Endpoint::Production
    };

    // Connecting to APNs
    let client = Client::token(
        &mut private_key,
        key_id.as_ref(),
        team_id.as_ref(),
        endpoint,
    ).unwrap();

    let options = NotificationOptions {
        apns_topic: topic.as_ref().map(|s| &**s),
        ..Default::default()
    };

    // Notification payload
    let mut builder = PlainNotificationBuilder::new(message.as_ref());
    builder.set_sound("default");
    builder.set_badge(1u32);

    let payload = builder.build(device_token.as_ref(), options);
    let sending = client.send(payload);

    // Send the notification, parse response
    tokio::run(lazy(move || {
        sending
            .map(|response| {
                println!("Sent: {:?}", response);
            })
            .map_err(|error| {
                println!("Error: {:?}", error);
            })
    }));
}
<commit_msg>Fix token_client example not building due to unresolvable `as_ref()`.<commit_after>use tokio;
use pretty_env_logger;
use argparse::{ArgumentParser, Store, StoreOption, StoreTrue};
use std::fs::File;

use a2::{
    Client,
    Endpoint,
    NotificationBuilder,
    NotificationOptions,
    PlainNotificationBuilder,
};

use futures::{
    future::lazy,
    Future,
};

// An example client connectiong to APNs with a JWT token
fn main() {
    pretty_env_logger::init();

    let mut key_file = String::new();
    let mut team_id = String::new();
    let mut key_id = String::new();
    let mut device_token = String::new();
    let mut message = String::from("Ch-check it out!");
    let mut sandbox = false;
    let mut topic: Option<String> = None;

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("APNs token-based push");
        ap.refer(&mut key_file)
            .add_option(&["-p", "--pkcs8"], Store, "Private key PKCS8");
        ap.refer(&mut team_id)
            .add_option(&["-t", "--team_id"], Store, "APNs team ID");
        ap.refer(&mut key_id)
            .add_option(&["-k", "--key_id"], Store, "APNs key ID");
        ap.refer(&mut device_token).add_option(
            &["-d", "--device_token"],
            Store,
            "APNs device token",
        );
        ap.refer(&mut message)
            .add_option(&["-m", "--message"], Store, "Notification message");
        ap.refer(&mut sandbox).add_option(
            &["-s", "--sandbox"],
            StoreTrue,
            "Use the development APNs servers",
        );
        ap.refer(&mut topic)
            .add_option(&["-o", "--topic"], StoreOption, "APNS topic");
        ap.parse_args_or_exit();
    }

    // Read the private key from disk
    let mut private_key = File::open(key_file).unwrap();

    // Which service to call, test or production?
    let endpoint = if sandbox {
        Endpoint::Sandbox
    } else {
        Endpoint::Production
    };

    // Connecting to APNs
    let client = Client::token(&mut private_key, key_id, team_id, endpoint).unwrap();

    let options = NotificationOptions {
        apns_topic: topic.as_ref().map(|s| &**s),
        ..Default::default()
    };

    // Notification payload
    let mut builder = PlainNotificationBuilder::new(message.as_ref());
    builder.set_sound("default");
    builder.set_badge(1u32);

    let payload = builder.build(device_token.as_ref(), options);
    let sending = client.send(payload);

    // Send the notification, parse response
    tokio::run(lazy(move || {
        sending
            .map(|response| {
                println!("Sent: {:?}", response);
            })
            .map_err(|error| {
                println!("Error: {:?}", error);
            })
    }));
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! impl_query_id {
    ($name: ident) => {
        impl $crate::query_builder::QueryId for $name {
            type QueryId = Self;

            fn has_static_query_id() -> bool {
                true
            }
        }
    };

    ($name: ident<$($ty_param: ident),+>) => {
        #[allow(non_camel_case_types)]
        impl<$($ty_param),*> $crate::query_builder::QueryId for $name<$($ty_param),*> where
            $($ty_param: $crate::query_builder::QueryId),*
        {
            type QueryId = $name<$($ty_param::QueryId),*>;

            fn has_static_query_id() -> bool {
                $($ty_param::has_static_query_id() &&)* true
            }
        }
    };

    (noop: $name: ident) => {
        impl $crate::query_builder::QueryId for $name {
            type QueryId = ();

            fn has_static_query_id() -> bool {
                false
            }
        }
    };

    (noop: $name: ident<$($ty_param: ident),+>) => {
        #[allow(non_camel_case_types)]
        impl<$($ty_param),*> $crate::query_builder::QueryId for $name<$($ty_param),*> {
            type QueryId = ();

            fn has_static_query_id() -> bool {
                false
            }
        }
    }
}
<commit_msg>Hide `impl_query_id` from docs<commit_after>#[macro_export]
#[doc(hidden)]
macro_rules! impl_query_id {
    ($name: ident) => {
        impl $crate::query_builder::QueryId for $name {
            type QueryId = Self;

            fn has_static_query_id() -> bool {
                true
            }
        }
    };

    ($name: ident<$($ty_param: ident),+>) => {
        #[allow(non_camel_case_types)]
        impl<$($ty_param),*> $crate::query_builder::QueryId for $name<$($ty_param),*> where
            $($ty_param: $crate::query_builder::QueryId),*
        {
            type QueryId = $name<$($ty_param::QueryId),*>;

            fn has_static_query_id() -> bool {
                $($ty_param::has_static_query_id() &&)* true
            }
        }
    };

    (noop: $name: ident) => {
        impl $crate::query_builder::QueryId for $name {
            type QueryId = ();

            fn has_static_query_id() -> bool {
                false
            }
        }
    };

    (noop: $name: ident<$($ty_param: ident),+>) => {
        #[allow(non_camel_case_types)]
        impl<$($ty_param),*> $crate::query_builder::QueryId for $name<$($ty_param),*> {
            type QueryId = ();

            fn has_static_query_id() -> bool {
                false
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate wiringpi;
use wiringpi::*;
extern crate joy;
extern crate ctrlc;
#[macro_use]
extern crate lazy_static;

mod tracelib;
use tracelib::*;

use std::thread;
use std::time::Duration;
use std::process;

fn pass() {
    thread::sleep(Duration::from_millis(0));
}

fn scale_deadband(x: f32) -> f32 {
    if x.abs() < globals::DEADBAND { 0f32 } else { x }
}

fn main() {
    /// blink rsl while running
    /// automatically ended when main thread exits
    thread::spawn(move || {
        let light = globals::PI.output_pin(tracelib::globals::RSL_PIN);
        loop {
            light.digital_write(pin::Value::High);
            thread::sleep(Duration::from_millis(600));
            light.digital_write(pin::Value::Low);
            thread::sleep(Duration::from_millis(600));
        }
    });

    let mut stick = joy::Device::open("/dev/input/js0\0".as_bytes()).unwrap();

    ctrlc::set_handler(move || {
        println!("message: Exited on user request");
        println!("Exiting...");
        globals::PI.output_pin(tracelib::globals::RSL_PIN).digital_write(pin::Value::Low);
        process::exit(0);
    }).expect("Error setting ctrl-c handler!");

    let mut stick1 = 0f32;
    let mut stick2 = 0f32;

    let mut trace = rrb3::RaspiRobot::new(9f32, 6f32, 2i8);

    //thread::sleep(Duration::from_secs(2));

    loop {
        for ev in &mut stick {
            match ev {
                joy::Event::Axis(a, pos) => {
                    // position from -32767 to 32767
                    match a {
                        1 => stick1 = {
                            let percent = pos as f32 / 32767 as f32;
                            //println!("Axis {}: {} {}",  a, pos, percent);
                            -percent
                        },
                        4 => stick2 = {
                            let percent = pos as f32 / 32767 as f32;
                            //println!("Axis {}: {} {}",  a, pos, percent);
                            -percent
                        },
                        _ => pass(),
                    };
                },
                joy::Event::Button(b, state) => {
                    //if state { println!("Button {} pressed!", b); } else { println!("Button {} released!", b) }
                    match b {
                        /*8 => {
                            println!("Exit called by start button!");
                            println!("Exiting...");
                            process::exit(0);
                        },*/
                        _ => pass(),
                    };
                },
            }
        }
        trace.tank_drive(scale_deadband(stick1), scale_deadband(stick2));
    }
}
<commit_msg>Tank drive apparently actually works. Implemented in a way that makes sense. #2<commit_after>extern crate wiringpi;
use wiringpi::*;
extern crate joy;
extern crate ctrlc;
#[macro_use]
extern crate lazy_static;

mod tracelib;
use tracelib::*;

use std::thread;
use std::time::Duration;
use std::process;

fn pass() {
    thread::sleep(Duration::from_millis(0));
}

fn scale_deadband(x: f32) -> f32 {
    if x.abs() < globals::DEADBAND { 0f32 } else { x }
}

fn main() {
    /// blink rsl while running
    /// automatically ended when main thread exits
    thread::spawn(move || {
        let light = globals::PI.output_pin(tracelib::globals::RSL_PIN);
        loop {
            light.digital_write(pin::Value::High);
            thread::sleep(Duration::from_millis(600));
            light.digital_write(pin::Value::Low);
            thread::sleep(Duration::from_millis(600));
        }
    });

    let mut stick = joy::Device::open("/dev/input/js0\0".as_bytes()).unwrap();

    ctrlc::set_handler(move || {
        println!("message: Exited on user request");
        println!("Exiting...");
        globals::PI.output_pin(tracelib::globals::RSL_PIN).digital_write(pin::Value::Low);
        process::exit(0);
    }).expect("Error setting ctrl-c handler!");

    let mut stick1 = 0f32;
    let mut stick2 = 0f32;
    let mut stick3 = 0f32;
    let mut tank = false;

    let mut trace = rrb3::RaspiRobot::new(9f32, 6f32, 2i8);

    //thread::sleep(Duration::from_secs(2));

    loop {
        for ev in &mut stick {
            match ev {
                joy::Event::Axis(a, pos) => {
                    // position from -32767 to 32767
                    match a {
                        1 => stick1 = {
                            let percent = pos as f32 / 32767 as f32;
                            //println!("Axis {}: {} {}",  a, pos, percent);
                            -percent
                        },
                        3 => stick3 = {
                            let percent = pos as f32 / 32767 as f32;
                            //println!("Axis {}: {} {}",  a, pos, percent);
                            -percent
                        },
                        4 => stick2 = {
                            let percent = pos as f32 / 32767 as f32;
                            //println!("Axis {}: {} {}",  a, pos, percent);
                            -percent
                        },
                        _ => pass(),
                    };
                },
                joy::Event::Button(b, state) => {
                    //if state { println!("Button {} pressed!", b); } else { println!("Button {} released!", b) }
                    match b {
                        /*8 => {
                            println!("Exit called by start button!");
                            println!("Exiting...");
                            process::exit(0);
                        },*/
                        7 => {
                            if state {
                                tank = !tank;
                                println!("Switched modes!");
                            }
                        },
                        _ => pass(),
                    };
                },
            }
        }
        if tank {
            trace.tank_drive(scale_deadband(stick1), scale_deadband(stick2));
        } else {
            trace.arcade_drive(scale_deadband(stick1), scale_deadband(stick3));
        }

    }
}
<|endoftext|>