<commit_before>//! A module providing IRC connections for use by `IrcServer`s.
use std::fs::File;
use std::fmt;
use std::io::Read;

use encoding::EncoderTrap;
use encoding::label::encoding_from_whatwg_label;
use futures::{Async, Poll, Future, Sink, StartSend, Stream};
use native_tls::{Certificate, TlsConnector, Identity};
use tokio_codec::Decoder;
use tokio::net::{TcpStream, ConnectFuture};
use tokio_mockstream::MockStream;
use tokio_tls::{self, TlsStream};

use error;
use client::data::Config;
use client::transport::{IrcTransport, LogView, Logged};
use proto::{IrcCodec, Message};

/// An IRC connection used internally by `IrcServer`.
pub enum Connection {
    #[doc(hidden)]
    Unsecured(IrcTransport<TcpStream>),
    #[doc(hidden)]
    Secured(IrcTransport<TlsStream<TcpStream>>),
    #[doc(hidden)]
    Mock(Logged<MockStream>),
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match *self {
                Connection::Unsecured(_) => "Connection::Unsecured(...)",
                Connection::Secured(_) => "Connection::Secured(...)",
                Connection::Mock(_) => "Connection::Mock(...)",
            }
        )
    }
}

/// A convenient type alias representing the `TlsStream` future.
type TlsFuture = Box<Future<Error = error::IrcError, Item = TlsStream<TcpStream>> + Send>;

/// A future representing an eventual `Connection`.
pub enum ConnectionFuture {
    #[doc(hidden)]
    Unsecured(Config, ConnectFuture),
    #[doc(hidden)]
    Secured(Config, TlsFuture),
    #[doc(hidden)]
    Mock(Config),
}

impl fmt::Debug for ConnectionFuture {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}({:?}, ...)",
            match *self {
                ConnectionFuture::Unsecured(_, _) => "ConnectionFuture::Unsecured",
                ConnectionFuture::Secured(_, _) => "ConnectionFuture::Secured",
                ConnectionFuture::Mock(_) => "ConnectionFuture::Mock",
            },
            match *self {
                ConnectionFuture::Unsecured(ref cfg, _) |
                ConnectionFuture::Secured(ref cfg, _) |
                ConnectionFuture::Mock(ref cfg) => cfg,
            }
        )
    }
}

impl Future for ConnectionFuture {
    type Item = Connection;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            ConnectionFuture::Unsecured(ref config, ref mut inner) => {
                let stream = try_ready!(inner.poll());
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Unsecured(transport)))
            }
            ConnectionFuture::Secured(ref config, ref mut inner) => {
                let stream = try_ready!(inner.poll());
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Secured(transport)))
            }
            ConnectionFuture::Mock(ref config) => {
                let enc: error::Result<_> = encoding_from_whatwg_label(
                    config.encoding()
                ).ok_or_else(|| error::IrcError::UnknownCodec {
                    codec: config.encoding().to_owned(),
                });
                let encoding = enc?;
                let init_str = config.mock_initial_value();
                let initial: error::Result<_> = {
                    encoding.encode(init_str, EncoderTrap::Replace).map_err(|data| {
                        error::IrcError::CodecFailed {
                            codec: encoding.name(),
                            data: data.into_owned(),
                        }
                    })
                };

                let stream = MockStream::new(&initial?);
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Mock(Logged::wrap(transport))))
            }
        }
    }
}

impl Connection {
    /// Creates a new `Connection` using the specified `Config`
    pub fn new(config: Config) -> error::Result<ConnectionFuture> {
        if config.use_mock_connection() {
            Ok(ConnectionFuture::Mock(config))
        } else if config.use_ssl() {
            let domain = format!("{}", config.server()?);
            info!("Connecting via SSL to {}.", domain);
            let mut builder = TlsConnector::builder();
            if let Some(cert_path) = config.cert_path() {
                let mut file = File::open(cert_path)?;
                let mut cert_data = vec![];
                file.read_to_end(&mut cert_data)?;
                let cert = Certificate::from_der(&cert_data)?;
                builder.add_root_certificate(cert);
                info!("Added {} to trusted certificates.", cert_path);
            }
            if let Some(client_cert_path) = config.client_cert_path() {
                let client_cert_pass = config.client_cert_pass();
                let mut file = File::open(client_cert_path)?;
                let mut client_cert_data = vec![];
                file.read_to_end(&mut client_cert_data)?;
                let pkcs12_archive = Identity::from_pkcs12(&client_cert_data, &client_cert_pass)?;
                builder.identity(pkcs12_archive);
                info!("Using {} for client certificate authentication.", client_cert_path);
            }
            let connector: tokio_tls::TlsConnector = builder.build()?.into();
            let stream = Box::new(TcpStream::connect(&config.socket_addr()?).map_err(|e| {
                let res: error::IrcError = e.into();
                res
            }).and_then(move |socket| {
                connector.connect(&domain, socket).map_err(
                    |e| e.into(),
                )
            }));
            Ok(ConnectionFuture::Secured(config, stream))
        } else {
            info!("Connecting to {}.", config.server()?);
            let addr = config.socket_addr()?;
            Ok(ConnectionFuture::Unsecured(
                config,
                TcpStream::connect(&addr),
            ))
        }
    }

    /// Gets a view of the internal logging if and only if this connection is using a mock stream.
    /// Otherwise, this will always return `None`. This is used for unit testing.
    pub fn log_view(&self) -> Option<LogView> {
        match *self {
            Connection::Mock(ref inner) => Some(inner.view()),
            _ => None,
        }
    }
}

impl Stream for Connection {
    type Item = Message;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll(),
            Connection::Secured(ref mut inner) => inner.poll(),
            Connection::Mock(ref mut inner) => inner.poll(),
        }
    }
}

impl Sink for Connection {
    type SinkItem = Message;
    type SinkError = error::IrcError;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.start_send(item),
            Connection::Secured(ref mut inner) => inner.start_send(item),
            Connection::Mock(ref mut inner) => inner.start_send(item),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll_complete(),
            Connection::Secured(ref mut inner) => inner.poll_complete(),
            Connection::Mock(ref mut inner) => inner.poll_complete(),
        }
    }
}
<commit_msg>Use tokio::net::tcp::ConnectFuture instead of deprecated re-export.<commit_after>//! A module providing IRC connections for use by `IrcServer`s.
use std::fs::File;
use std::fmt;
use std::io::Read;

use encoding::EncoderTrap;
use encoding::label::encoding_from_whatwg_label;
use futures::{Async, Poll, Future, Sink, StartSend, Stream};
use native_tls::{Certificate, TlsConnector, Identity};
use tokio_codec::Decoder;
use tokio::net::{TcpStream};
use tokio::net::tcp::ConnectFuture;
use tokio_mockstream::MockStream;
use tokio_tls::{self, TlsStream};

use error;
use client::data::Config;
use client::transport::{IrcTransport, LogView, Logged};
use proto::{IrcCodec, Message};

/// An IRC connection used internally by `IrcServer`.
pub enum Connection {
    #[doc(hidden)]
    Unsecured(IrcTransport<TcpStream>),
    #[doc(hidden)]
    Secured(IrcTransport<TlsStream<TcpStream>>),
    #[doc(hidden)]
    Mock(Logged<MockStream>),
}

impl fmt::Debug for Connection {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match *self {
                Connection::Unsecured(_) => "Connection::Unsecured(...)",
                Connection::Secured(_) => "Connection::Secured(...)",
                Connection::Mock(_) => "Connection::Mock(...)",
            }
        )
    }
}

/// A convenient type alias representing the `TlsStream` future.
type TlsFuture = Box<Future<Error = error::IrcError, Item = TlsStream<TcpStream>> + Send>;

/// A future representing an eventual `Connection`.
pub enum ConnectionFuture {
    #[doc(hidden)]
    Unsecured(Config, ConnectFuture),
    #[doc(hidden)]
    Secured(Config, TlsFuture),
    #[doc(hidden)]
    Mock(Config),
}

impl fmt::Debug for ConnectionFuture {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}({:?}, ...)",
            match *self {
                ConnectionFuture::Unsecured(_, _) => "ConnectionFuture::Unsecured",
                ConnectionFuture::Secured(_, _) => "ConnectionFuture::Secured",
                ConnectionFuture::Mock(_) => "ConnectionFuture::Mock",
            },
            match *self {
                ConnectionFuture::Unsecured(ref cfg, _) |
                ConnectionFuture::Secured(ref cfg, _) |
                ConnectionFuture::Mock(ref cfg) => cfg,
            }
        )
    }
}

impl Future for ConnectionFuture {
    type Item = Connection;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match *self {
            ConnectionFuture::Unsecured(ref config, ref mut inner) => {
                let stream = try_ready!(inner.poll());
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Unsecured(transport)))
            }
            ConnectionFuture::Secured(ref config, ref mut inner) => {
                let stream = try_ready!(inner.poll());
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Secured(transport)))
            }
            ConnectionFuture::Mock(ref config) => {
                let enc: error::Result<_> = encoding_from_whatwg_label(
                    config.encoding()
                ).ok_or_else(|| error::IrcError::UnknownCodec {
                    codec: config.encoding().to_owned(),
                });
                let encoding = enc?;
                let init_str = config.mock_initial_value();
                let initial: error::Result<_> = {
                    encoding.encode(init_str, EncoderTrap::Replace).map_err(|data| {
                        error::IrcError::CodecFailed {
                            codec: encoding.name(),
                            data: data.into_owned(),
                        }
                    })
                };

                let stream = MockStream::new(&initial?);
                let framed = IrcCodec::new(config.encoding())?.framed(stream);
                let transport = IrcTransport::new(&config, framed);

                Ok(Async::Ready(Connection::Mock(Logged::wrap(transport))))
            }
        }
    }
}

impl Connection {
    /// Creates a new `Connection` using the specified `Config`
    pub fn new(config: Config) -> error::Result<ConnectionFuture> {
        if config.use_mock_connection() {
            Ok(ConnectionFuture::Mock(config))
        } else if config.use_ssl() {
            let domain = format!("{}", config.server()?);
            info!("Connecting via SSL to {}.", domain);
            let mut builder = TlsConnector::builder();
            if let Some(cert_path) = config.cert_path() {
                let mut file = File::open(cert_path)?;
                let mut cert_data = vec![];
                file.read_to_end(&mut cert_data)?;
                let cert = Certificate::from_der(&cert_data)?;
                builder.add_root_certificate(cert);
                info!("Added {} to trusted certificates.", cert_path);
            }
            if let Some(client_cert_path) = config.client_cert_path() {
                let client_cert_pass = config.client_cert_pass();
                let mut file = File::open(client_cert_path)?;
                let mut client_cert_data = vec![];
                file.read_to_end(&mut client_cert_data)?;
                let pkcs12_archive = Identity::from_pkcs12(&client_cert_data, &client_cert_pass)?;
                builder.identity(pkcs12_archive);
                info!("Using {} for client certificate authentication.", client_cert_path);
            }
            let connector: tokio_tls::TlsConnector = builder.build()?.into();
            let stream = Box::new(TcpStream::connect(&config.socket_addr()?).map_err(|e| {
                let res: error::IrcError = e.into();
                res
            }).and_then(move |socket| {
                connector.connect(&domain, socket).map_err(
                    |e| e.into(),
                )
            }));
            Ok(ConnectionFuture::Secured(config, stream))
        } else {
            info!("Connecting to {}.", config.server()?);
            let addr = config.socket_addr()?;
            Ok(ConnectionFuture::Unsecured(
                config,
                TcpStream::connect(&addr),
            ))
        }
    }

    /// Gets a view of the internal logging if and only if this connection is using a mock stream.
    /// Otherwise, this will always return `None`. This is used for unit testing.
    pub fn log_view(&self) -> Option<LogView> {
        match *self {
            Connection::Mock(ref inner) => Some(inner.view()),
            _ => None,
        }
    }
}

impl Stream for Connection {
    type Item = Message;
    type Error = error::IrcError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll(),
            Connection::Secured(ref mut inner) => inner.poll(),
            Connection::Mock(ref mut inner) => inner.poll(),
        }
    }
}

impl Sink for Connection {
    type SinkItem = Message;
    type SinkError = error::IrcError;

    fn start_send(&mut self, item: Self::SinkItem) -> StartSend<Self::SinkItem, Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.start_send(item),
            Connection::Secured(ref mut inner) => inner.start_send(item),
            Connection::Mock(ref mut inner) => inner.start_send(item),
        }
    }

    fn poll_complete(&mut self) -> Poll<(), Self::SinkError> {
        match *self {
            Connection::Unsecured(ref mut inner) => inner.poll_complete(),
            Connection::Secured(ref mut inner) => inner.poll_complete(),
            Connection::Mock(ref mut inner) => inner.poll_complete(),
        }
    }
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// 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.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// 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 OWNER 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.

// ignore-pretty very bad with line comments
// ignore-android doesn't terminate?

#![feature(slicing_syntax)]

use std::iter::range_step;
use std::io::{stdin, stdout, File};

static LINE_LEN: uint = 60;

fn make_complements() -> [u8, ..256] {
    let transforms = [
        ('A', 'T'), ('C', 'G'), ('G', 'C'), ('T', 'A'),
        ('U', 'A'), ('M', 'K'), ('R', 'Y'), ('W', 'W'),
        ('S', 'S'), ('Y', 'R'), ('K', 'M'), ('V', 'B'),
        ('H', 'D'), ('D', 'H'), ('B', 'V'), ('N', 'N'),
        ('\n', '\n')];
    let mut complements: [u8, ..256] = [0, ..256];
    for (i, c) in complements.iter_mut().enumerate() {
        *c = i as u8;
    }
    let lower = 'A' as u8 - 'a' as u8;
    for &(from, to) in transforms.iter() {
        complements[from as uint] = to as u8;
        complements[(from as u8 - lower) as uint] = to as u8;
    }
    complements
}

fn main() {
    let complements = make_complements();
    let data = if std::os::getenv("RUST_BENCH").is_some() {
        File::open(&Path::new("shootout-k-nucleotide.data")).read_to_end()
    } else {
        stdin().read_to_end()
    };
    let mut data = data.unwrap();

    for seq in data.as_mut_slice().split_mut(|c| *c == '>' as u8) {
        // skip header and last \n
        let begin = match seq.iter().position(|c| *c == '\n' as u8) {
            None => continue,
            Some(c) => c
        };
        let len = seq.len();
        let seq = seq[mut begin+1..len-1];

        // arrange line breaks
        let len = seq.len();
        let off = LINE_LEN - len % (LINE_LEN + 1);
        for i in range_step(LINE_LEN, len, LINE_LEN + 1) {
            for j in std::iter::count(i, -1).take(off) {
                seq[j] = seq[j - 1];
            }
            seq[i - off] = '\n' as u8;
        }

        // reverse complement, as
        //    seq.reverse(); for c in seq.iter_mut() {*c = complements[*c]}
        // but faster:
        for (front, back) in TwoSideIterator::new(seq) {
            let tmp = complements[*front as uint];
            *front = complements[*back as uint];
            *back = tmp;
        }
        if seq.len() % 2 == 1 {
            let middle = &mut seq[seq.len() / 2];
            *middle = complements[*middle as uint];
        }
    }

    stdout().write(data.as_slice()).unwrap();
}

pub struct TwoSideIterator<'a, T: 'a> {
    last: uint,
    nb: uint,
    cur: uint,
    slice: &'a mut [T]
}
impl<'a, T> TwoSideIterator<'a, T> {
    pub fn new(s: &'a mut [T]) -> TwoSideIterator<'a, T> {
        TwoSideIterator {
            last: s.len() - 1,
            nb: s.len() / 2,
            cur: 0,
            slice: s
        }
    }
}
impl<'a, T> Iterator<(&'a mut T, &'a mut T)> for TwoSideIterator<'a, T> {
    fn next(&mut self) -> Option<(&'a mut T, &'a mut T)> {
        if self.cur >= self.nb { return None; }
        let res = unsafe {
            (std::mem::transmute(self.slice.unsafe_mut(self.cur)),
             std::mem::transmute(self.slice.unsafe_mut(self.last - self.cur)))
        };
        self.cur += 1;
        Some(res)
    }
}
<commit_msg>shootout-reverse-complement: reimplement TwoSideIter using pointers<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers

// Copyright (c) 2013-2014 The Rust Project Developers
//
// 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.
//
// - Neither the name of "The Computer Language Benchmarks Game" nor
//   the name of "The Computer Language Shootout Benchmarks" nor the
//   names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior
//   written permission.
//
// 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 OWNER 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.

// ignore-pretty very bad with line comments
// ignore-android doesn't terminate?

#![feature(slicing_syntax)]

use std::iter::range_step;
use std::io::{stdin, stdout, File};

static LINE_LEN: uint = 60;

fn make_complements() -> [u8, ..256] {
    let transforms = [
        ('A', 'T'), ('C', 'G'), ('G', 'C'), ('T', 'A'),
        ('U', 'A'), ('M', 'K'), ('R', 'Y'), ('W', 'W'),
        ('S', 'S'), ('Y', 'R'), ('K', 'M'), ('V', 'B'),
        ('H', 'D'), ('D', 'H'), ('B', 'V'), ('N', 'N'),
        ('\n', '\n')];
    let mut complements: [u8, ..256] = [0, ..256];
    for (i, c) in complements.iter_mut().enumerate() {
        *c = i as u8;
    }
    let lower = 'A' as u8 - 'a' as u8;
    for &(from, to) in transforms.iter() {
        complements[from as uint] = to as u8;
        complements[(from as u8 - lower) as uint] = to as u8;
    }
    complements
}

fn main() {
    let complements = make_complements();
    let data = if std::os::getenv("RUST_BENCH").is_some() {
        File::open(&Path::new("shootout-k-nucleotide.data")).read_to_end()
    } else {
        stdin().read_to_end()
    };
    let mut data = data.unwrap();

    for seq in data.as_mut_slice().split_mut(|c| *c == '>' as u8) {
        // skip header and last \n
        let begin = match seq.iter().position(|c| *c == '\n' as u8) {
            None => continue,
            Some(c) => c
        };
        let len = seq.len();
        let seq = seq[mut begin+1..len-1];

        // arrange line breaks
        let len = seq.len();
        let off = LINE_LEN - len % (LINE_LEN + 1);
        for i in range_step(LINE_LEN, len, LINE_LEN + 1) {
            for j in std::iter::count(i, -1).take(off) {
                seq[j] = seq[j - 1];
            }
            seq[i - off] = '\n' as u8;
        }

        // reverse complement, as
        //    seq.reverse(); for c in seq.iter_mut() { *c = complements[*c] }
        // but faster:
        for (front, back) in two_side_iter(seq) {
            let tmp = complements[*front as uint];
            *front = complements[*back as uint];
            *back = tmp;
        }
        if seq.len() % 2 == 1 {
            let middle = &mut seq[seq.len() / 2];
            *middle = complements[*middle as uint];
        }
    }

    stdout().write(data.as_slice()).unwrap();
}

pub struct TwoSideIter<'a, T: 'a> {
    first: *mut T,
    last: *mut T,
    marker: std::kinds::marker::ContravariantLifetime<'a>,
    marker2: std::kinds::marker::NoCopy
}

pub fn two_side_iter<'a, T>(slice: &'a mut [T]) -> TwoSideIter<'a, T> {
    let len = slice.len();
    let first = slice.as_mut_ptr();
    let last = if len == 0 {
        first
    } else {
        unsafe { first.offset(len as int - 1) }
    };

    TwoSideIter {
        first: first,
        last: last,
        marker: std::kinds::marker::ContravariantLifetime,
        marker2: std::kinds::marker::NoCopy
    }
}

impl<'a, T> Iterator<(&'a mut T, &'a mut T)> for TwoSideIter<'a, T> {
    fn next(&mut self) -> Option<(&'a mut T, &'a mut T)> {
        if self.first < self.last {
            let result = unsafe { (&mut *self.first, &mut *self.last) };
            self.first = unsafe { self.first.offset(1) };
            self.last = unsafe { self.last.offset(-1) };
            Some(result)
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>//! FIXME: write short doc here

use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::{AtomTextEdit, TextEdit};

use crate::ide_db::line_index::{LineCol, LineIndex, Utf16Char};

#[derive(Debug, Clone)]
enum Step {
    Newline(TextUnit),
    Utf16Char(TextRange),
}

#[derive(Debug)]
struct LineIndexStepIter<'a> {
    line_index: &'a LineIndex,
    next_newline_idx: usize,
    utf16_chars: Option<(TextUnit, std::slice::Iter<'a, Utf16Char>)>,
}

impl<'a> LineIndexStepIter<'a> {
    fn from(line_index: &LineIndex) -> LineIndexStepIter {
        let mut x = LineIndexStepIter { line_index, next_newline_idx: 0, utf16_chars: None };
        // skip first newline since it's not real
        x.next();
        x
    }
}

impl<'a> Iterator for LineIndexStepIter<'a> {
    type Item = Step;
    fn next(&mut self) -> Option<Step> {
        self.utf16_chars
            .as_mut()
            .and_then(|(newline, x)| {
                let x = x.next()?;
                Some(Step::Utf16Char(TextRange::from_to(*newline + x.start, *newline + x.end)))
            })
            .or_else(|| {
                let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?;
                self.utf16_chars = self
                    .line_index
                    .utf16_lines
                    .get(&(self.next_newline_idx as u32))
                    .map(|x| (next_newline, x.iter()));
                self.next_newline_idx += 1;
                Some(Step::Newline(next_newline))
            })
    }
}

#[derive(Debug)]
struct OffsetStepIter<'a> {
    text: &'a str,
    offset: TextUnit,
}

impl<'a> Iterator for OffsetStepIter<'a> {
    type Item = Step;
    fn next(&mut self) -> Option<Step> {
        let (next, next_offset) = self
            .text
            .char_indices()
            .filter_map(|(i, c)| {
                if c == '\n' {
                    let next_offset = self.offset + TextUnit::from_usize(i + 1);
                    let next = Step::Newline(next_offset);
                    Some((next, next_offset))
                } else {
                    let char_len = TextUnit::of_char(c);
                    if char_len.to_usize() > 1 {
                        let start = self.offset + TextUnit::from_usize(i);
                        let end = start + char_len;
                        let next = Step::Utf16Char(TextRange::from_to(start, end));
                        let next_offset = end;
                        Some((next, next_offset))
                    } else {
                        None
                    }
                }
            })
            .next()?;
        let next_idx = (next_offset - self.offset).to_usize();
        self.text = &self.text[next_idx..];
        self.offset = next_offset;
        Some(next)
    }
}

#[derive(Debug)]
enum NextSteps<'a> {
    Use,
    ReplaceMany(OffsetStepIter<'a>),
    AddMany(OffsetStepIter<'a>),
}

#[derive(Debug)]
struct TranslatedEdit<'a> {
    delete: TextRange,
    insert: &'a str,
    diff: i64,
}

struct Edits<'a> {
    edits: &'a [AtomTextEdit],
    current: Option<TranslatedEdit<'a>>,
    acc_diff: i64,
}

impl<'a> Edits<'a> {
    fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> {
        let mut x = Edits { edits: text_edit.as_atoms(), current: None, acc_diff: 0 };
        x.advance_edit();
        x
    }
    fn advance_edit(&mut self) {
        self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff);
        match self.edits.split_first() {
            Some((next, rest)) => {
                let delete = self.translate_range(next.delete);
                let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64;
                self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff });
                self.edits = rest;
            }
            None => {
                self.current = None;
            }
        }
    }

    fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> {
        let cur = self.current.as_ref()?;
        let res = Some(OffsetStepIter { offset: cur.delete.start(), text: &cur.insert });
        self.advance_edit();
        res
    }

    fn next_steps(&mut self, step: &Step) -> NextSteps {
        let step_pos = match *step {
            Step::Newline(n) => n,
            Step::Utf16Char(r) => r.end(),
        };
        match &mut self.current {
            Some(edit) => {
                if step_pos <= edit.delete.start() {
                    NextSteps::Use
                } else if step_pos <= edit.delete.end() {
                    let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
                    // empty slice to avoid returning steps again
                    edit.insert = &edit.insert[edit.insert.len()..];
                    NextSteps::ReplaceMany(iter)
                } else {
                    let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
                    // empty slice to avoid returning steps again
                    edit.insert = &edit.insert[edit.insert.len()..];
                    self.advance_edit();
                    NextSteps::AddMany(iter)
                }
            }
            None => NextSteps::Use,
        }
    }

    fn translate_range(&self, range: TextRange) -> TextRange {
        if self.acc_diff == 0 {
            range
        } else {
            let start = self.translate(range.start());
            let end = self.translate(range.end());
            TextRange::from_to(start, end)
        }
    }

    fn translate(&self, x: TextUnit) -> TextUnit {
        if self.acc_diff == 0 {
            x
        } else {
            TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32)
        }
    }

    fn translate_step(&self, x: &Step) -> Step {
        if self.acc_diff == 0 {
            x.clone()
        } else {
            match *x {
                Step::Newline(n) => Step::Newline(self.translate(n)),
                Step::Utf16Char(r) => Step::Utf16Char(self.translate_range(r)),
            }
        }
    }
}

#[derive(Debug)]
struct RunningLineCol {
    line: u32,
    last_newline: TextUnit,
    col_adjust: TextUnit,
}

impl RunningLineCol {
    fn new() -> RunningLineCol {
        RunningLineCol { line: 0, last_newline: TextUnit::from(0), col_adjust: TextUnit::from(0) }
    }

    fn to_line_col(&self, offset: TextUnit) -> LineCol {
        LineCol {
            line: self.line,
            col_utf16: ((offset - self.last_newline) - self.col_adjust).into(),
        }
    }

    fn add_line(&mut self, newline: TextUnit) {
        self.line += 1;
        self.last_newline = newline;
        self.col_adjust = TextUnit::from(0);
    }

    fn adjust_col(&mut self, range: TextRange) {
        self.col_adjust += range.len() - TextUnit::from(1);
    }
}

pub fn translate_offset_with_edit(
    line_index: &LineIndex,
    offset: TextUnit,
    text_edit: &TextEdit,
) -> LineCol {
    let mut state = Edits::from_text_edit(&text_edit);

    let mut res = RunningLineCol::new();

    macro_rules! test_step {
        ($x:ident) => {
            match &$x {
                Step::Newline(n) => {
                    if offset < *n {
                        return res.to_line_col(offset);
                    } else {
                        res.add_line(*n);
                    }
                }
                Step::Utf16Char(x) => {
                    if offset < x.end() {
                        // if the offset is inside a multibyte char it's invalid
                        // clamp it to the start of the char
                        let clamp = offset.min(x.start());
                        return res.to_line_col(clamp);
                    } else {
                        res.adjust_col(*x);
                    }
                }
            }
        };
    }

    for orig_step in LineIndexStepIter::from(line_index) {
        loop {
            let translated_step = state.translate_step(&orig_step);
            match state.next_steps(&translated_step) {
                NextSteps::Use => {
                    test_step!(translated_step);
                    break;
                }
                NextSteps::ReplaceMany(ns) => {
                    for n in ns {
                        test_step!(n);
                    }
                    break;
                }
                NextSteps::AddMany(ns) => {
                    for n in ns {
                        test_step!(n);
                    }
                }
            }
        }
    }

    loop {
        match state.next_inserted_steps() {
            None => break,
            Some(ns) => {
                for n in ns {
                    test_step!(n);
                }
            }
        }
    }

    res.to_line_col(offset)
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::line_index;
    use proptest::{prelude::*, proptest};
    use ra_text_edit::test_utils::{arb_offset, arb_text_with_edit};
    use ra_text_edit::TextEdit;

    #[derive(Debug)]
    struct ArbTextWithEditAndOffset {
        text: String,
        edit: TextEdit,
        edited_text: String,
        offset: TextUnit,
    }

    fn arb_text_with_edit_and_offset() -> BoxedStrategy<ArbTextWithEditAndOffset> {
        arb_text_with_edit()
            .prop_flat_map(|x| {
                let edited_text = x.edit.apply(&x.text);
                let arb_offset = arb_offset(&edited_text);
                (Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| {
                    ArbTextWithEditAndOffset { text: x.text, edit: x.edit, edited_text, offset }
                })
            })
            .boxed()
    }

    proptest! {
        #[test]
        fn test_translate_offset_with_edit(x in arb_text_with_edit_and_offset()) {
            let expected = line_index::to_line_col(&x.edited_text, x.offset);
            let line_index = LineIndex::new(&x.text);
            let actual = translate_offset_with_edit(&line_index, x.offset, &x.edit);

            assert_eq!(actual, expected);
        }
    }
}
<commit_msg>Fix test imports<commit_after>//! FIXME: write short doc here

use ra_syntax::{TextRange, TextUnit};
use ra_text_edit::{AtomTextEdit, TextEdit};

use crate::ide_db::line_index::{LineCol, LineIndex, Utf16Char};

#[derive(Debug, Clone)]
enum Step {
    Newline(TextUnit),
    Utf16Char(TextRange),
}

#[derive(Debug)]
struct LineIndexStepIter<'a> {
    line_index: &'a LineIndex,
    next_newline_idx: usize,
    utf16_chars: Option<(TextUnit, std::slice::Iter<'a, Utf16Char>)>,
}

impl<'a> LineIndexStepIter<'a> {
    fn from(line_index: &LineIndex) -> LineIndexStepIter {
        let mut x = LineIndexStepIter { line_index, next_newline_idx: 0, utf16_chars: None };
        // skip first newline since it's not real
        x.next();
        x
    }
}

impl<'a> Iterator for LineIndexStepIter<'a> {
    type Item = Step;
    fn next(&mut self) -> Option<Step> {
        self.utf16_chars
            .as_mut()
            .and_then(|(newline, x)| {
                let x = x.next()?;
                Some(Step::Utf16Char(TextRange::from_to(*newline + x.start, *newline + x.end)))
            })
            .or_else(|| {
                let next_newline = *self.line_index.newlines.get(self.next_newline_idx)?;
                self.utf16_chars = self
                    .line_index
                    .utf16_lines
                    .get(&(self.next_newline_idx as u32))
                    .map(|x| (next_newline, x.iter()));
                self.next_newline_idx += 1;
                Some(Step::Newline(next_newline))
            })
    }
}

#[derive(Debug)]
struct OffsetStepIter<'a> {
    text: &'a str,
    offset: TextUnit,
}

impl<'a> Iterator for OffsetStepIter<'a> {
    type Item = Step;
    fn next(&mut self) -> Option<Step> {
        let (next, next_offset) = self
            .text
            .char_indices()
            .filter_map(|(i, c)| {
                if c == '\n' {
                    let next_offset = self.offset + TextUnit::from_usize(i + 1);
                    let next = Step::Newline(next_offset);
                    Some((next, next_offset))
                } else {
                    let char_len = TextUnit::of_char(c);
                    if char_len.to_usize() > 1 {
                        let start = self.offset + TextUnit::from_usize(i);
                        let end = start + char_len;
                        let next = Step::Utf16Char(TextRange::from_to(start, end));
                        let next_offset = end;
                        Some((next, next_offset))
                    } else {
                        None
                    }
                }
            })
            .next()?;
        let next_idx = (next_offset - self.offset).to_usize();
        self.text = &self.text[next_idx..];
        self.offset = next_offset;
        Some(next)
    }
}

#[derive(Debug)]
enum NextSteps<'a> {
    Use,
    ReplaceMany(OffsetStepIter<'a>),
    AddMany(OffsetStepIter<'a>),
}

#[derive(Debug)]
struct TranslatedEdit<'a> {
    delete: TextRange,
    insert: &'a str,
    diff: i64,
}

struct Edits<'a> {
    edits: &'a [AtomTextEdit],
    current: Option<TranslatedEdit<'a>>,
    acc_diff: i64,
}

impl<'a> Edits<'a> {
    fn from_text_edit(text_edit: &'a TextEdit) -> Edits<'a> {
        let mut x = Edits { edits: text_edit.as_atoms(), current: None, acc_diff: 0 };
        x.advance_edit();
        x
    }
    fn advance_edit(&mut self) {
        self.acc_diff += self.current.as_ref().map_or(0, |x| x.diff);
        match self.edits.split_first() {
            Some((next, rest)) => {
                let delete = self.translate_range(next.delete);
                let diff = next.insert.len() as i64 - next.delete.len().to_usize() as i64;
                self.current = Some(TranslatedEdit { delete, insert: &next.insert, diff });
                self.edits = rest;
            }
            None => {
                self.current = None;
            }
        }
    }

    fn next_inserted_steps(&mut self) -> Option<OffsetStepIter<'a>> {
        let cur = self.current.as_ref()?;
        let res = Some(OffsetStepIter { offset: cur.delete.start(), text: &cur.insert });
        self.advance_edit();
        res
    }

    fn next_steps(&mut self, step: &Step) -> NextSteps {
        let step_pos = match *step {
            Step::Newline(n) => n,
            Step::Utf16Char(r) => r.end(),
        };
        match &mut self.current {
            Some(edit) => {
                if step_pos <= edit.delete.start() {
                    NextSteps::Use
                } else if step_pos <= edit.delete.end() {
                    let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
                    // empty slice to avoid returning steps again
                    edit.insert = &edit.insert[edit.insert.len()..];
                    NextSteps::ReplaceMany(iter)
                } else {
                    let iter = OffsetStepIter { offset: edit.delete.start(), text: &edit.insert };
                    // empty slice to avoid returning steps again
                    edit.insert = &edit.insert[edit.insert.len()..];
                    self.advance_edit();
                    NextSteps::AddMany(iter)
                }
            }
            None => NextSteps::Use,
        }
    }

    fn translate_range(&self, range: TextRange) -> TextRange {
        if self.acc_diff == 0 {
            range
        } else {
            let start = self.translate(range.start());
            let end = self.translate(range.end());
            TextRange::from_to(start, end)
        }
    }

    fn translate(&self, x: TextUnit) -> TextUnit {
        if self.acc_diff == 0 {
            x
        } else {
            TextUnit::from((x.to_usize() as i64 + self.acc_diff) as u32)
        }
    }

    fn translate_step(&self, x: &Step) -> Step {
        if self.acc_diff == 0 {
            x.clone()
        } else {
            match *x {
                Step::Newline(n) => Step::Newline(self.translate(n)),
                Step::Utf16Char(r) => Step::Utf16Char(self.translate_range(r)),
            }
        }
    }
}

#[derive(Debug)]
struct RunningLineCol {
    line: u32,
    last_newline: TextUnit,
    col_adjust: TextUnit,
}

impl RunningLineCol {
    fn new() -> RunningLineCol {
        RunningLineCol { line: 0, last_newline: TextUnit::from(0), col_adjust: TextUnit::from(0) }
    }

    fn to_line_col(&self, offset: TextUnit) -> LineCol {
        LineCol {
            line: self.line,
            col_utf16: ((offset - self.last_newline) - self.col_adjust).into(),
        }
    }

    fn add_line(&mut self, newline: TextUnit) {
        self.line += 1;
        self.last_newline = newline;
        self.col_adjust = TextUnit::from(0);
    }

    fn adjust_col(&mut self, range: TextRange) {
        self.col_adjust += range.len() - TextUnit::from(1);
    }
}

pub fn translate_offset_with_edit(
    line_index: &LineIndex,
    offset: TextUnit,
    text_edit: &TextEdit,
) -> LineCol {
    let mut state = Edits::from_text_edit(&text_edit);

    let mut res = RunningLineCol::new();

    macro_rules! test_step {
        ($x:ident) => {
            match &$x {
                Step::Newline(n) => {
                    if offset < *n {
                        return res.to_line_col(offset);
                    } else {
                        res.add_line(*n);
                    }
                }
                Step::Utf16Char(x) => {
                    if offset < x.end() {
                        // if the offset is inside a multibyte char it's invalid
                        // clamp it to the start of the char
                        let clamp = offset.min(x.start());
                        return res.to_line_col(clamp);
                    } else {
                        res.adjust_col(*x);
                    }
                }
            }
        };
    }

    for orig_step in LineIndexStepIter::from(line_index) {
        loop {
            let translated_step = state.translate_step(&orig_step);
            match state.next_steps(&translated_step) {
                NextSteps::Use => {
                    test_step!(translated_step);
                    break;
                }
                NextSteps::ReplaceMany(ns) => {
                    for n in ns {
                        test_step!(n);
                    }
                    break;
                }
                NextSteps::AddMany(ns) => {
                    for n in ns {
                        test_step!(n);
                    }
                }
            }
        }
    }

    loop {
        match state.next_inserted_steps() {
            None => break,
            Some(ns) => {
                for n in ns {
                    test_step!(n);
                }
            }
        }
    }

    res.to_line_col(offset)
}

#[cfg(test)]
mod test {
    use proptest::{prelude::*, proptest};
    use ra_text_edit::test_utils::{arb_offset, arb_text_with_edit};
    use ra_text_edit::TextEdit;

    use crate::ide_db::line_index;

    use super::*;

    #[derive(Debug)]
    struct ArbTextWithEditAndOffset {
        text: String,
        edit: TextEdit,
        edited_text: String,
        offset: TextUnit,
    }

    fn arb_text_with_edit_and_offset() -> BoxedStrategy<ArbTextWithEditAndOffset> {
        arb_text_with_edit()
            .prop_flat_map(|x| {
                let edited_text = x.edit.apply(&x.text);
                let arb_offset = arb_offset(&edited_text);
                (Just(x), Just(edited_text), arb_offset).prop_map(|(x, edited_text, offset)| {
                    ArbTextWithEditAndOffset { text: x.text, edit: x.edit, edited_text, offset }
                })
            })
            .boxed()
    }

    proptest! {
        #[test]
        fn test_translate_offset_with_edit(x in arb_text_with_edit_and_offset()) {
            let expected = line_index::to_line_col(&x.edited_text, x.offset);
            let line_index = LineIndex::new(&x.text);
            let actual = translate_offset_with_edit(&line_index, x.offset, &x.edit);

            assert_eq!(actual, expected);
        }
    }
}
<|endoftext|>


<commit_before>//! Implementation of event enum and event content enum macros.

use std::fmt;

use proc_macro2::Span;
use quote::{format_ident, IdentFragment};
use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync)
    }

    pub fn is_sync(self) -> bool {
        matches!(self, Self::Sync | Self::RedactedSync)
    }

    pub fn to_redacted(self) -> Self {
        match self {
            EventKindVariation::Full => EventKindVariation::Redacted,
            EventKindVariation::Sync => EventKindVariation::RedactedSync,
            _ => panic!("No redacted form of {:?}", self),
        }
    }

    pub fn to_sync(self) -> Self {
        match self {
            EventKindVariation::Full => EventKindVariation::Sync,
            EventKindVariation::Redacted => EventKindVariation::RedactedSync,
            _ => panic!("No sync form of {:?}", self),
        }
    }

    pub fn to_full(self) -> Self {
        match self {
            EventKindVariation::Sync => EventKindVariation::Full,
            EventKindVariation::RedactedSync => EventKindVariation::Redacted,
            _ => panic!("No full form of {:?}", self),
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKind {
    GlobalAccountData,
    RoomAccountData,
    Ephemeral,
    MessageLike,
    State,
    ToDevice,
    RoomRedaction,
    Presence,
    HierarchySpaceChild,
    Decrypted,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::GlobalAccountData => write!(f, "GlobalAccountDataEvent"),
            EventKind::RoomAccountData => write!(f, "RoomAccountDataEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::MessageLike => write!(f, "MessageLikeEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::RoomRedaction => write!(f, "RoomRedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
            EventKind::HierarchySpaceChild => write!(f, "HierarchySpaceChildEvent"),
            EventKind::Decrypted => unreachable!(),
        }
    }
}

impl IdentFragment for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl IdentFragment for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }

    fn span(&self) -> Option<Span> {
        Some(Span::call_site())
    }
}

impl EventKind {
    pub fn is_account_data(self) -> bool {
        matches!(self, Self::GlobalAccountData | Self::RoomAccountData)
    }

    pub fn try_to_event_ident(self, var: EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        match (self, var) {
            (_, V::Full)
            | (Self::MessageLike | Self::RoomRedaction | Self::State | Self::Ephemeral, V::Sync)
            | (
                Self::MessageLike | Self::RoomRedaction | Self::State,
                V::Redacted | V::RedactedSync,
            )
            | (Self::State, V::Stripped | V::Initial) => Some(format_ident!("{}{}", var, self)),
            _ => None,
        }
    }

    pub fn to_event_ident(self, var: EventKindVariation) -> Ident {
        self.try_to_event_ident(var).unwrap_or_else(|| {
            panic!("({:?}, {:?}) is not a valid event kind / variation combination", self, var);
        })
    }

    pub fn to_event_enum_ident(self, var: EventKindVariation) -> Ident {
        format_ident!("Any{}", self.to_event_ident(var))
    }

    pub fn to_event_type_enum(self) -> Ident {
        format_ident!("{}Type", self)
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(self) -> Ident {
        format_ident!("Any{}Content", self)
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "GlobalAccountData" => EventKind::GlobalAccountData,
            "RoomAccountData" => EventKind::RoomAccountData,
            "EphemeralRoom" => EventKind::Ephemeral,
            "MessageLike" => EventKind::MessageLike,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new_spanned(
                    ident,
                    format!(
                        "valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, \
                        MessageLike, State, ToDevice found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "GlobalAccountDataEvent" => Some((EventKind::GlobalAccountData, EventKindVariation::Full)),
        "RoomAccountDataEvent" => Some((EventKind::RoomAccountData, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Full)),
        "SyncMessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Sync)),
        "RedactedMessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Redacted)),
        "RedactedSyncMessageLikeEvent" => {
            Some((EventKind::MessageLike, EventKindVariation::RedactedSync))
        }
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "HierarchySpaceChildEvent" => {
            Some((EventKind::HierarchySpaceChild, EventKindVariation::Stripped))
        }
        "RoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Full)),
        "SyncRoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Sync)),
        "RedactedRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::Redacted))
        }
        "RedactedSyncRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::RedactedSync))
        }
        "DecryptedOlmV1Event" | "DecryptedMegolmV1Event" => {
            Some((EventKind::Decrypted, EventKindVariation::Full))
        }
        _ => None,
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumDecl {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The event kind.
    pub kind: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "kind". There needs to be a corresponding
    /// variant in `ruma_common::events::EventType` for this event (converted to a valid Rust-style
    /// type name by stripping `m.`, replacing the remaining dots by underscores and then
    /// converting from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    pub(crate) enums: Vec<EventEnumDecl>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let mut enums = vec![];
        while !input.is_empty() {
            let attrs = input.call(Attribute::parse_outer)?;

            let _: Token![enum] = input.parse()?;
            let kind: EventKind = input.parse()?;

            let content;
            braced!(content in input);
            let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
            let events = events.into_iter().collect();
            enums.push(EventEnumDecl { attrs, kind, events });
        }
        Ok(EventEnumInput { enums })
    }
}
<commit_msg>events: Remove unnecessary IdentFragment::span implementations<commit_after>//! Implementation of event enum and event content enum macros.

use std::fmt;

use quote::{format_ident, IdentFragment};
use syn::{
    braced,
    parse::{self, Parse, ParseStream},
    Attribute, Ident, LitStr, Token,
};

/// Custom keywords for the `event_enum!` macro
mod kw {
    syn::custom_keyword!(kind);
    syn::custom_keyword!(events);
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKindVariation {
    Full,
    Sync,
    Stripped,
    Initial,
    Redacted,
    RedactedSync,
}

impl fmt::Display for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKindVariation::Full => write!(f, ""),
            EventKindVariation::Sync => write!(f, "Sync"),
            EventKindVariation::Stripped => write!(f, "Stripped"),
            EventKindVariation::Initial => write!(f, "Initial"),
            EventKindVariation::Redacted => write!(f, "Redacted"),
            EventKindVariation::RedactedSync => write!(f, "RedactedSync"),
        }
    }
}

impl EventKindVariation {
    pub fn is_redacted(self) -> bool {
        matches!(self, Self::Redacted | Self::RedactedSync)
    }

    pub fn is_sync(self) -> bool {
        matches!(self, Self::Sync | Self::RedactedSync)
    }

    pub fn to_redacted(self) -> Self {
        match self {
            EventKindVariation::Full => EventKindVariation::Redacted,
            EventKindVariation::Sync => EventKindVariation::RedactedSync,
            _ => panic!("No redacted form of {:?}", self),
        }
    }

    pub fn to_sync(self) -> Self {
        match self {
            EventKindVariation::Full => EventKindVariation::Sync,
            EventKindVariation::Redacted => EventKindVariation::RedactedSync,
            _ => panic!("No sync form of {:?}", self),
        }
    }

    pub fn to_full(self) -> Self {
        match self {
            EventKindVariation::Sync => EventKindVariation::Full,
            EventKindVariation::RedactedSync => EventKindVariation::Redacted,
            _ => panic!("No full form of {:?}", self),
        }
    }
}

// If the variants of this enum change `to_event_path` needs to be updated as well.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum EventKind {
    GlobalAccountData,
    RoomAccountData,
    Ephemeral,
    MessageLike,
    State,
    ToDevice,
    RoomRedaction,
    Presence,
    HierarchySpaceChild,
    Decrypted,
}

impl fmt::Display for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            EventKind::GlobalAccountData => write!(f, "GlobalAccountDataEvent"),
            EventKind::RoomAccountData => write!(f, "RoomAccountDataEvent"),
            EventKind::Ephemeral => write!(f, "EphemeralRoomEvent"),
            EventKind::MessageLike => write!(f, "MessageLikeEvent"),
            EventKind::State => write!(f, "StateEvent"),
            EventKind::ToDevice => write!(f, "ToDeviceEvent"),
            EventKind::RoomRedaction => write!(f, "RoomRedactionEvent"),
            EventKind::Presence => write!(f, "PresenceEvent"),
            EventKind::HierarchySpaceChild => write!(f, "HierarchySpaceChildEvent"),
            EventKind::Decrypted => unreachable!(),
        }
    }
}

impl IdentFragment for EventKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl IdentFragment for EventKindVariation {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}

impl EventKind {
    pub fn is_account_data(self) -> bool {
        matches!(self, Self::GlobalAccountData | Self::RoomAccountData)
    }

    pub fn try_to_event_ident(self, var: EventKindVariation) -> Option<Ident> {
        use EventKindVariation as V;

        match (self, var) {
            (_, V::Full)
            | (Self::MessageLike | Self::RoomRedaction | Self::State | Self::Ephemeral, V::Sync)
            | (
                Self::MessageLike | Self::RoomRedaction | Self::State,
                V::Redacted | V::RedactedSync,
            )
            | (Self::State, V::Stripped | V::Initial) => Some(format_ident!("{}{}", var, self)),
            _ => None,
        }
    }

    pub fn to_event_ident(self, var: EventKindVariation) -> Ident {
        self.try_to_event_ident(var).unwrap_or_else(|| {
            panic!("({:?}, {:?}) is not a valid event kind / variation combination", self, var);
        })
    }

    pub fn to_event_enum_ident(self, var: EventKindVariation) -> Ident {
        format_ident!("Any{}", self.to_event_ident(var))
    }

    pub fn to_event_type_enum(self) -> Ident {
        format_ident!("{}Type", self)
    }

    /// `Any[kind]EventContent`
    pub fn to_content_enum(self) -> Ident {
        format_ident!("Any{}Content", self)
    }
}

impl Parse for EventKind {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        let ident: Ident = input.parse()?;
        Ok(match ident.to_string().as_str() {
            "GlobalAccountData" => EventKind::GlobalAccountData,
            "RoomAccountData" => EventKind::RoomAccountData,
            "EphemeralRoom" => EventKind::Ephemeral,
            "MessageLike" => EventKind::MessageLike,
            "State" => EventKind::State,
            "ToDevice" => EventKind::ToDevice,
            id => {
                return Err(syn::Error::new_spanned(
                    ident,
                    format!(
                        "valid event kinds are GlobalAccountData, RoomAccountData, EphemeralRoom, \
                        MessageLike, State, ToDevice found `{}`",
                        id
                    ),
                ));
            }
        })
    }
}

// This function is only used in the `Event` derive macro expansion code.
/// Validates the given `ident` is a valid event struct name and returns a tuple of enums
/// representing the name.
pub fn to_kind_variation(ident: &Ident) -> Option<(EventKind, EventKindVariation)> {
    let ident_str = ident.to_string();
    match ident_str.as_str() {
        "GlobalAccountDataEvent" => Some((EventKind::GlobalAccountData, EventKindVariation::Full)),
        "RoomAccountDataEvent" => Some((EventKind::RoomAccountData, EventKindVariation::Full)),
        "EphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Full)),
        "SyncEphemeralRoomEvent" => Some((EventKind::Ephemeral, EventKindVariation::Sync)),
        "MessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Full)),
        "SyncMessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Sync)),
        "RedactedMessageLikeEvent" => Some((EventKind::MessageLike, EventKindVariation::Redacted)),
        "RedactedSyncMessageLikeEvent" => {
            Some((EventKind::MessageLike, EventKindVariation::RedactedSync))
        }
        "StateEvent" => Some((EventKind::State, EventKindVariation::Full)),
        "SyncStateEvent" => Some((EventKind::State, EventKindVariation::Sync)),
        "StrippedStateEvent" => Some((EventKind::State, EventKindVariation::Stripped)),
        "InitialStateEvent" => Some((EventKind::State, EventKindVariation::Initial)),
        "RedactedStateEvent" => Some((EventKind::State, EventKindVariation::Redacted)),
        "RedactedSyncStateEvent" => Some((EventKind::State, EventKindVariation::RedactedSync)),
        "ToDeviceEvent" => Some((EventKind::ToDevice, EventKindVariation::Full)),
        "PresenceEvent" => Some((EventKind::Presence, EventKindVariation::Full)),
        "HierarchySpaceChildEvent" => {
            Some((EventKind::HierarchySpaceChild, EventKindVariation::Stripped))
        }
        "RoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Full)),
        "SyncRoomRedactionEvent" => Some((EventKind::RoomRedaction, EventKindVariation::Sync)),
        "RedactedRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::Redacted))
        }
        "RedactedSyncRoomRedactionEvent" => {
            Some((EventKind::RoomRedaction, EventKindVariation::RedactedSync))
        }
        "DecryptedOlmV1Event" | "DecryptedMegolmV1Event" => {
            Some((EventKind::Decrypted, EventKindVariation::Full))
        }
        _ => None,
    }
}

pub struct EventEnumEntry {
    pub attrs: Vec<Attribute>,
    pub ev_type: LitStr,
}

impl Parse for EventEnumEntry {
    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
        Ok(Self { attrs: input.call(Attribute::parse_outer)?, ev_type: input.parse()? })
    }
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumDecl {
    /// Outer attributes on the field, such as a docstring.
    pub attrs: Vec<Attribute>,

    /// The event kind.
    pub kind: EventKind,

    /// An array of valid matrix event types.
    ///
    /// This will generate the variants of the event type "kind". There needs to be a corresponding
    /// variant in `ruma_common::events::EventType` for this event (converted to a valid Rust-style
    /// type name by stripping `m.`, replacing the remaining dots by underscores and then
    /// converting from snake_case to CamelCase).
    pub events: Vec<EventEnumEntry>,
}

/// The entire `event_enum!` macro structure directly as it appears in the source code.
pub struct EventEnumInput {
    pub(crate) enums: Vec<EventEnumDecl>,
}

impl Parse for EventEnumInput {
    fn parse(input: ParseStream<'_>) -> parse::Result<Self> {
        let mut enums = vec![];
        while !input.is_empty() {
            let attrs = input.call(Attribute::parse_outer)?;

            let _: Token![enum] = input.parse()?;
            let kind: EventKind = input.parse()?;

            let content;
            braced!(content in input);
            let events = content.parse_terminated::<_, Token![,]>(EventEnumEntry::parse)?;
            let events = events.into_iter().collect();
            enums.push(EventEnumDecl { attrs, kind, events });
        }
        Ok(EventEnumInput { enums })
    }
}
<|endoftext|>


<commit_before>//! Functions used for adding labels to the sounding plot
use app::AppContext;
use config;

use coords::ScreenCoords;

use cairo::{Context, Matrix, FontExtents, FontFace, FontSlant, FontWeight};

// Set up the font matrix, and set the font, etc.
pub fn prepare_to_label(cr: &Context, ac: &AppContext) {

    // Configure the font.
    let font_face = FontFace::toy_create(config::FONT_NAME, FontSlant::Normal, FontWeight::Bold);
    cr.set_font_face(font_face);

    set_font_size(config::LARGE_FONT_SIZE, cr, ac);
}

// Set the font size by reseting the font matrix
fn set_font_size(size_in_pnts: f64, cr: &Context, ac: &AppContext) {
    let dpi = match ac.get_dpi() {
        None => 72.0,
        Some(value) => value,
    };

    let font_size = size_in_pnts / 72.0 * dpi;
    let (font_size, _) = ac.convert_device_to_screen((font_size, 0.0));

    // Flip the y-coordinate so it displays the font right side up
    cr.set_font_matrix(Matrix {
        xx: 1.0 * font_size,
        yx: 0.0,
        xy: 0.0,
        yy: -1.0 * font_size, // Reflect it to be right side up!
        x0: 0.0,
        y0: 0.0,
    });
}

// Label the pressure, temperatures, etc lines.
pub fn draw_background_labels(cr: &Context, ac: &AppContext) {

    // Get min/max screen coordinate values
    let (lower_left_screen, upper_right_screen) = ac.bounding_box_in_screen_coords();
    let (mut screen_x_min, _screen_y_min) = lower_left_screen;
    let (screen_x_max, screen_y_max) = upper_right_screen;

    // Get coordinates to keep labels from flowing off the chart.
    let (xmin, _ymin) = ac.convert_xy_to_screen((0.0, 0.0));
    let (_, mut screen_max_p) = ac.convert_screen_to_tp((0.0, 0.0));
    if screen_max_p > config::MAXP {
        screen_max_p = config::MAXP;
    }
    if xmin > screen_x_min {
        screen_x_min = xmin;
    }

    // Label isobars
    let mut max_p_label_right_edge: f64 = 0.0; // Used for checking overlap later with T
    let mut last_label_y = ::std::f64::MIN; // Used for checking overlap between pressure labels
    let mut rgba = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, 1.0);
    for &p in config::ISOBARS.into_iter() {
        // Make the label text
        let label = format!("{}", p);

        // Calculate position of lower left edge for label
        let (_, mut screen_y) = ac.convert_tp_to_screen((0.0, p));
        screen_y += 0.005 * screen_y_max; // Lift off the pressure line slightly

        // Check for vertical overlap.
        let label_extents = cr.text_extents(&label);
        let (label_width, label_height) = (label_extents.width, label_extents.height);
        if screen_y < label_height + last_label_y {
            continue;
        }
        last_label_y = screen_y;

        // Update right edge for checking with T later.
        if label_width > max_p_label_right_edge {
            max_p_label_right_edge = label_width;
        }

        // Draw the label
        cr.move_to(screen_x_min + 0.01 * screen_x_max, screen_y);
        cr.show_text(&label);
    }
    // This is width, add position of left edge to get right edge
    max_p_label_right_edge += screen_x_min + 0.01 * screen_x_max;

    // Label isotherms
    rgba = config::ISOTHERM_RGBA;
    let (mut last_label_x_max, mut last_label_x_min) = (0.0, 0.0);
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, 1.0);
    for &t in config::ISOTHERMS.into_iter() {
        // Make the label text
        let label = format!("{}", t);

        // Calculate position for lower left edge of label
        let (mut screen_x, mut screen_y) = ac.convert_tp_to_screen((t, screen_max_p));
        screen_y += 0.008 * screen_y_max;
        screen_x += 0.008 * screen_y_max;

        // Check for overlap with pressure labels
        if screen_x < max_p_label_right_edge {
            continue;
        }

        // Check for overlap with other T labels
        let extents_width = cr.text_extents(&label).width;
        let (x_min, x_max) = (screen_x, screen_x + extents_width);
        if (x_min > last_label_x_min && x_min < last_label_x_max) ||
            (x_max > last_label_x_min && x_max < last_label_x_max)
        {
            continue;
        }

        last_label_x_min = x_min - 0.008 * screen_x_max;
        last_label_x_max = x_max + 0.008 * screen_x_max;

        // Draw the label
        cr.move_to(screen_x, screen_y);
        cr.show_text(&label);
    }
}

// Add a description box
pub fn draw_legend(cr: &Context, ac: &AppContext) {
    if !ac.plottable() {
        return;
    }

    let upper_left = ac.convert_device_to_screen((5.0, 5.0));
    let font_extents = cr.font_extents();

    let (source_name, valid_time, location) = build_label_strings(ac);

    let (box_width, box_height) =
        calculate_legend_box_size(cr, &font_extents, &source_name, &valid_time, &location);

    draw_legend_rectangle(cr, &upper_left, box_width, box_height);

    draw_legend_text(
        cr,
        &upper_left,
        &font_extents,
        &source_name,
        &valid_time,
        &location,
    );

}

fn build_label_strings(ac: &AppContext) -> (Option<String>, Option<String>, Option<String>) {

    let source_name: Option<String> = ac.get_source_name();
    let mut valid_time: Option<String> = None;
    let mut location: Option<String> = None;
    if let Some(snd) = ac.get_sounding_for_display() {
        // Build the valid time part
        if let Some(vt) = snd.valid_time {
            use chrono::{Datelike, Timelike};
            valid_time = Some(format!(
                "Valid: {:02}/{:02}/{:04} {:02}Z",
                vt.month(),
                vt.day(),
                vt.year(),
                vt.hour()
            ));
        }

        // Build location part.
        if snd.lat.as_option().is_some() || snd.lon.as_option().is_some() ||
            snd.elevation.as_option().is_some()
        {
            location = Some("".to_owned());
            if let Some(ref mut loc) = location {
                if let Some(lat) = snd.lat.as_option() {
                    loc.push_str(&format!("{:.2}", lat));
                }
                if let Some(lon) = snd.lon.as_option() {
                    loc.push_str(&format!(", {:.2}", lon));
                }
                if let Some(el) = snd.elevation.as_option() {
                    loc.push_str(&format!(", {:.0}m ({:.0}ft)", el, el * 3.28084));
                }
            }
        }
    }

    (source_name, valid_time, location)
}

fn calculate_legend_box_size(
    cr: &Context,
    font_extents: &FontExtents,
    source_name: &Option<String>,
    valid_time: &Option<String>,
    location: &Option<String>,
) -> (f64, f64) {

    let mut box_width: f64 = 0.0;
    let mut box_height: f64 = 0.0;

    if let &Some(ref src) = source_name {
        let extents = cr.text_extents(src);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
    }

    if let &Some(ref vt) = valid_time {
        let extents = cr.text_extents(vt);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
        // Add line spacing if previous line was there.
        if source_name.is_some() {
            box_height += font_extents.height - extents.height;
        }
    }

    if let &Some(ref loc) = location {
        let extents = cr.text_extents(loc);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
        // Add line spacing if previous line was there.
        if valid_time.is_some() {
            box_height += font_extents.height - extents.height;
        }
    }

    // Add room for the last line's descent
    box_height += font_extents.descent;

    // Add padding last
    box_height += 2.0 * config::DEFAULT_PADDING;
    box_width += 2.0 * config::DEFAULT_PADDING;

    (box_width, box_height)
}

fn draw_legend_rectangle(cr: &Context, upper_left: &ScreenCoords, width: f64, height: f64) {
    cr.rectangle(upper_left.0, upper_left.1 - height, width, height);

    let rgb = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgb.0, rgb.1, rgb.2, rgb.3);
    cr.set_line_width(cr.device_to_user_distance(3.0, 0.0).0);
    cr.stroke_preserve();
    let rgb = config::BACKGROUND_RGB;
    cr.set_source_rgb(rgb.0, rgb.1, rgb.2);
    cr.fill();
}

fn draw_legend_text(
    cr: &Context,
    upper_left: &ScreenCoords,
    font_extents: &FontExtents,
    source_name: &Option<String>,
    valid_time: &Option<String>,
    location: &Option<String>,
) {
    let rgb = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgb.0, rgb.1, rgb.2, rgb.3);

    // Remember how many lines we have drawn so far for setting position of the next line.
    let mut num_lines_drawn = 0;

    // Get into the initial position
    cr.move_to(
        upper_left.0 + config::DEFAULT_PADDING,
        upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent,
    );

    if let &Some(ref src) = source_name {
        cr.show_text(src);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
    if let &Some(ref vt) = valid_time {
        cr.show_text(vt);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
    if let &Some(ref loc) = location {
        cr.show_text(loc);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
}
<commit_msg>Refactor for shorter functions.<commit_after>//! Functions used for adding labels to the sounding plot
use app::AppContext;
use config;

use coords::ScreenCoords;

use cairo::{Context, Matrix, FontExtents, FontFace, FontSlant, FontWeight};

//
// TODO: Labeling is clunky. Rewrite this module to make a list of labels and rectangles. If a
// rectangle overlaps another label, it does not get added to the list. Make high priority labels
// first. Fill the rectangles with the background color and then draw the labels.
//

// Set up the font matrix, and set the font, etc.
pub fn prepare_to_label(cr: &Context, ac: &AppContext) {

    // Configure the font.
    let font_face = FontFace::toy_create(config::FONT_NAME, FontSlant::Normal, FontWeight::Bold);
    cr.set_font_face(font_face);

    set_font_size(config::LARGE_FONT_SIZE, cr, ac);
}

// Set the font size by reseting the font matrix
fn set_font_size(size_in_pnts: f64, cr: &Context, ac: &AppContext) {
    let dpi = match ac.get_dpi() {
        None => 72.0,
        Some(value) => value,
    };

    let font_size = size_in_pnts / 72.0 * dpi;
    let (font_size, _) = ac.convert_device_to_screen((font_size, 0.0));

    // Flip the y-coordinate so it displays the font right side up
    cr.set_font_matrix(Matrix {
        xx: 1.0 * font_size,
        yx: 0.0,
        xy: 0.0,
        yy: -1.0 * font_size, // Reflect it to be right side up!
        x0: 0.0,
        y0: 0.0,
    });
}

// Label the pressure, temperatures, etc lines.
pub fn draw_background_labels(cr: &Context, ac: &AppContext) {

    let (screen_x_min, screen_x_max, screen_max_p, screen_y_max) = calculate_label_boundaries(ac);

    // Used for checking overlap later with T
    let max_p_label_right_edge: f64 =
        label_isobars(cr, ac, screen_x_min, screen_x_max, screen_y_max);

    label_isotherms(
        cr,
        ac,
        screen_x_max,
        screen_y_max,
        screen_max_p,
        max_p_label_right_edge,
    );
}

fn calculate_label_boundaries(ac: &AppContext) -> (f64, f64, f64, f64) {

    // Get min/max screen coordinate values
    let (lower_left_screen, upper_right_screen) = ac.bounding_box_in_screen_coords();
    let (mut screen_x_min, _screen_y_min) = lower_left_screen;
    let (screen_x_max, screen_y_max) = upper_right_screen;

    // Get coordinates to keep labels from flowing off the chart.
    let (xmin, _ymin) = ac.convert_xy_to_screen((0.0, 0.0));
    let (_, mut screen_max_p) = ac.convert_screen_to_tp((0.0, 0.0));
    if screen_max_p > config::MAXP {
        screen_max_p = config::MAXP;
    }
    if xmin > screen_x_min {
        screen_x_min = xmin;
    }

    (screen_x_min, screen_x_max, screen_max_p, screen_y_max)
}

fn label_isobars(
    cr: &Context,
    ac: &AppContext,
    screen_x_min: f64,
    screen_x_max: f64,
    screen_y_max: f64,
) -> f64 {

    // Setup label colors
    let rgba = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, 1.0);

    // For checking label overlap.
    let mut max_p_label_right_edge: f64 = 0.0; // Used for checking overlap later with T
    let mut last_label_y = ::std::f64::MIN; // Used for checking overlap between pressure labels

    for &p in config::ISOBARS.into_iter() {
        // Make the label text
        let label = format!("{}", p);

        // Calculate position of lower left edge for label
        let (_, mut screen_y) = ac.convert_tp_to_screen((0.0, p));
        screen_y += 0.005 * screen_y_max; // Lift off the pressure line slightly

        // Check for vertical overlap.
        let label_extents = cr.text_extents(&label);
        let (label_width, label_height) = (label_extents.width, label_extents.height);
        if screen_y < label_height + last_label_y {
            continue;
        }
        last_label_y = screen_y;

        // Update right edge for checking with T later.
        if label_width > max_p_label_right_edge {
            max_p_label_right_edge = label_width;
        }

        // Draw the label
        cr.move_to(screen_x_min + 0.01 * screen_x_max, screen_y);
        cr.show_text(&label);
    }
    // This is width, add position of left edge to get right edge
    max_p_label_right_edge += screen_x_min + 0.01 * screen_x_max;

    // Use this to make sure temperatures don't overlap
    max_p_label_right_edge
}

fn label_isotherms(
    cr: &Context,
    ac: &AppContext,
    screen_x_max: f64,
    screen_y_max: f64,
    screen_max_p: f64,
    max_p_label_right_edge: f64,
) {
    // Label isotherms
    let rgba = config::ISOTHERM_RGBA;
    let (mut last_label_x_max, mut last_label_x_min) = (0.0, 0.0);
    cr.set_source_rgba(rgba.0, rgba.1, rgba.2, 1.0);
    for &t in config::ISOTHERMS.into_iter() {
        // Make the label text
        let label = format!("{}", t);

        // Calculate position for lower left edge of label
        let (mut screen_x, mut screen_y) = ac.convert_tp_to_screen((t, screen_max_p));
        screen_y += 0.008 * screen_y_max;
        screen_x += 0.008 * screen_y_max;

        // Check for overlap with pressure labels
        if screen_x < max_p_label_right_edge {
            continue;
        }

        // Check for overlap with other T labels
        let extents_width = cr.text_extents(&label).width;
        let (x_min, x_max) = (screen_x, screen_x + extents_width);
        if (x_min > last_label_x_min && x_min < last_label_x_max) ||
            (x_max > last_label_x_min && x_max < last_label_x_max)
        {
            continue;
        }

        last_label_x_min = x_min - 0.008 * screen_x_max;
        last_label_x_max = x_max + 0.008 * screen_x_max;

        // Draw the label
        cr.move_to(screen_x, screen_y);
        cr.show_text(&label);
    }
}

// Add a description box
pub fn draw_legend(cr: &Context, ac: &AppContext) {
    if !ac.plottable() {
        return;
    }

    let upper_left = ac.convert_device_to_screen((5.0, 5.0));
    let font_extents = cr.font_extents();

    let (source_name, valid_time, location) = build_label_strings(ac);

    let (box_width, box_height) =
        calculate_legend_box_size(cr, &font_extents, &source_name, &valid_time, &location);

    draw_legend_rectangle(cr, &upper_left, box_width, box_height);

    draw_legend_text(
        cr,
        &upper_left,
        &font_extents,
        &source_name,
        &valid_time,
        &location,
    );

}

fn build_label_strings(ac: &AppContext) -> (Option<String>, Option<String>, Option<String>) {

    let source_name: Option<String> = ac.get_source_name();
    let mut valid_time: Option<String> = None;
    let mut location: Option<String> = None;
    if let Some(snd) = ac.get_sounding_for_display() {
        // Build the valid time part
        if let Some(vt) = snd.valid_time {
            use chrono::{Datelike, Timelike};
            valid_time = Some(format!(
                "Valid: {:02}/{:02}/{:04} {:02}Z",
                vt.month(),
                vt.day(),
                vt.year(),
                vt.hour()
            ));
        }

        // Build location part.
        if snd.lat.as_option().is_some() || snd.lon.as_option().is_some() ||
            snd.elevation.as_option().is_some()
        {
            location = Some("".to_owned());
            if let Some(ref mut loc) = location {
                if let Some(lat) = snd.lat.as_option() {
                    loc.push_str(&format!("{:.2}", lat));
                }
                if let Some(lon) = snd.lon.as_option() {
                    loc.push_str(&format!(", {:.2}", lon));
                }
                if let Some(el) = snd.elevation.as_option() {
                    loc.push_str(&format!(", {:.0}m ({:.0}ft)", el, el * 3.28084));
                }
            }
        }
    }

    (source_name, valid_time, location)
}

fn calculate_legend_box_size(
    cr: &Context,
    font_extents: &FontExtents,
    source_name: &Option<String>,
    valid_time: &Option<String>,
    location: &Option<String>,
) -> (f64, f64) {

    let mut box_width: f64 = 0.0;
    let mut box_height: f64 = 0.0;

    if let &Some(ref src) = source_name {
        let extents = cr.text_extents(src);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
    }

    if let &Some(ref vt) = valid_time {
        let extents = cr.text_extents(vt);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
        // Add line spacing if previous line was there.
        if source_name.is_some() {
            box_height += font_extents.height - extents.height;
        }
    }

    if let &Some(ref loc) = location {
        let extents = cr.text_extents(loc);
        if extents.width > box_width {
            box_width = extents.width;
        }
        box_height += extents.height;
        // Add line spacing if previous line was there.
        if valid_time.is_some() {
            box_height += font_extents.height - extents.height;
        }
    }

    // Add room for the last line's descent
    box_height += font_extents.descent;

    // Add padding last
    box_height += 2.0 * config::DEFAULT_PADDING;
    box_width += 2.0 * config::DEFAULT_PADDING;

    (box_width, box_height)
}

fn draw_legend_rectangle(cr: &Context, upper_left: &ScreenCoords, width: f64, height: f64) {
    cr.rectangle(upper_left.0, upper_left.1 - height, width, height);

    let rgb = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgb.0, rgb.1, rgb.2, rgb.3);
    cr.set_line_width(cr.device_to_user_distance(3.0, 0.0).0);
    cr.stroke_preserve();
    let rgb = config::BACKGROUND_RGB;
    cr.set_source_rgb(rgb.0, rgb.1, rgb.2);
    cr.fill();
}

fn draw_legend_text(
    cr: &Context,
    upper_left: &ScreenCoords,
    font_extents: &FontExtents,
    source_name: &Option<String>,
    valid_time: &Option<String>,
    location: &Option<String>,
) {
    let rgb = config::ISOBAR_RGBA;
    cr.set_source_rgba(rgb.0, rgb.1, rgb.2, rgb.3);

    // Remember how many lines we have drawn so far for setting position of the next line.
    let mut num_lines_drawn = 0;

    // Get into the initial position
    cr.move_to(
        upper_left.0 + config::DEFAULT_PADDING,
        upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent,
    );

    if let &Some(ref src) = source_name {
        cr.show_text(src);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
    if let &Some(ref vt) = valid_time {
        cr.show_text(vt);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
    if let &Some(ref loc) = location {
        cr.show_text(loc);
        num_lines_drawn += 1;
        cr.move_to(
            upper_left.0 + config::DEFAULT_PADDING,
            upper_left.1 - config::DEFAULT_PADDING - font_extents.ascent -
                num_lines_drawn as f64 * font_extents.height,
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use super::table::Table;

pub struct Database {
    tables: HashMap<String, Table>
}<commit_msg>new DB<commit_after>use std::collections::HashMap;
use super::table::Table;

pub struct Database {
    tables: HashMap<String, Table>
}

impl Database {
    fn new() -> Database {
        Database{
            tables: HashMap::new()
        }
    }
}<|endoftext|>


<commit_before>use lazy_static::lazy_static;
use regex::Regex;

// These lists contain the targets known to rustup, and used to build
// the PartialTargetTriple.

static LIST_ARCHS: &[&str] = &[
    "i386",
    "i586",
    "i686",
    "x86_64",
    "arm",
    "armv7",
    "armv7s",
    "aarch64",
    "mips",
    "mipsel",
    "mips64",
    "mips64el",
    "powerpc",
    "powerpc64",
    "powerpc64le",
    "riscv64gc",
    "s390x",
];
static LIST_OSES: &[&str] = &[
    "pc-windows",
    "unknown-linux",
    "apple-darwin",
    "unknown-netbsd",
    "apple-ios",
    "linux",
    "rumprun-netbsd",
    "unknown-freebsd",
    "unknown-illumos",
];
static LIST_ENVS: &[&str] = &[
    "gnu",
    "msvc",
    "gnueabi",
    "gnueabihf",
    "gnuabi64",
    "androideabi",
    "android",
    "musl",
];

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartialTargetTriple {
    pub arch: Option<String>,
    pub os: Option<String>,
    pub env: Option<String>,
}

impl PartialTargetTriple {
    pub fn new(name: &str) -> Option<Self> {
        if name.is_empty() {
            return Some(Self {
                arch: None,
                os: None,
                env: None,
            });
        }

        // Prepending `-` makes this next regex easier since
        // we can count  on all triple components being
        // delineated by it.
        let name = format!("-{}", name);
        lazy_static! {
            static ref PATTERN: String = format!(
                r"^(?:-({}))?(?:-({}))?(?:-({}))?$",
                LIST_ARCHS.join("|"),
                LIST_OSES.join("|"),
                LIST_ENVS.join("|")
            );
            static ref RE: Regex = Regex::new(&PATTERN).unwrap();
        }
        RE.captures(&name).map(|c| {
            fn fn_map(s: &str) -> Option<String> {
                if s.is_empty() {
                    None
                } else {
                    Some(s.to_owned())
                }
            }

            Self {
                arch: c.get(1).map(|s| s.as_str()).and_then(fn_map),
                os: c.get(2).map(|s| s.as_str()).and_then(fn_map),
                env: c.get(3).map(|s| s.as_str()).and_then(fn_map),
            }
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_partial_target_triple_new() {
        let success_cases = vec![
            ("", (None, None, None)),
            ("i386", (Some("i386"), None, None)),
            ("pc-windows", (None, Some("pc-windows"), None)),
            ("gnu", (None, None, Some("gnu"))),
            ("i386-gnu", (Some("i386"), None, Some("gnu"))),
            ("pc-windows-gnu", (None, Some("pc-windows"), Some("gnu"))),
            ("i386-pc-windows", (Some("i386"), Some("pc-windows"), None)),
            (
                "i386-pc-windows-gnu",
                (Some("i386"), Some("pc-windows"), Some("gnu")),
            ),
        ];

        for (input, (arch, os, env)) in success_cases {
            let partial_target_triple = PartialTargetTriple::new(input);
            assert!(
                partial_target_triple.is_some(),
                "expected `{}` to create some partial target triple; got None",
                input
            );

            let expected = PartialTargetTriple {
                arch: arch.map(String::from),
                os: os.map(String::from),
                env: env.map(String::from),
            };

            assert_eq!(
                partial_target_triple.unwrap(),
                expected,
                "input: `{}`",
                input
            );
        }

        let failure_cases = vec![
            "anything",
            "any-other-thing",
            "-",
            "--",
            "i386-",
            "i386-pc-",
            "i386-pc-windows-",
            "-pc-windows",
            "i386-pc-windows-anything",
            "0000-00-00-",
            "00000-000-000",
        ];

        for input in failure_cases {
            let partial_target_triple = PartialTargetTriple::new(input);
            assert!(
                partial_target_triple.is_none(),
                "expected `{}` to be `None`, was: `{:?}`",
                input,
                partial_target_triple
            );
        }
    }
}
<commit_msg>Add gnux32 to LIST_ENVS<commit_after>use lazy_static::lazy_static;
use regex::Regex;

// These lists contain the targets known to rustup, and used to build
// the PartialTargetTriple.

static LIST_ARCHS: &[&str] = &[
    "i386",
    "i586",
    "i686",
    "x86_64",
    "arm",
    "armv7",
    "armv7s",
    "aarch64",
    "mips",
    "mipsel",
    "mips64",
    "mips64el",
    "powerpc",
    "powerpc64",
    "powerpc64le",
    "riscv64gc",
    "s390x",
];
static LIST_OSES: &[&str] = &[
    "pc-windows",
    "unknown-linux",
    "apple-darwin",
    "unknown-netbsd",
    "apple-ios",
    "linux",
    "rumprun-netbsd",
    "unknown-freebsd",
    "unknown-illumos",
];
static LIST_ENVS: &[&str] = &[
    "gnu",
    "gnux32",
    "msvc",
    "gnueabi",
    "gnueabihf",
    "gnuabi64",
    "androideabi",
    "android",
    "musl",
];

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PartialTargetTriple {
    pub arch: Option<String>,
    pub os: Option<String>,
    pub env: Option<String>,
}

impl PartialTargetTriple {
    pub fn new(name: &str) -> Option<Self> {
        if name.is_empty() {
            return Some(Self {
                arch: None,
                os: None,
                env: None,
            });
        }

        // Prepending `-` makes this next regex easier since
        // we can count  on all triple components being
        // delineated by it.
        let name = format!("-{}", name);
        lazy_static! {
            static ref PATTERN: String = format!(
                r"^(?:-({}))?(?:-({}))?(?:-({}))?$",
                LIST_ARCHS.join("|"),
                LIST_OSES.join("|"),
                LIST_ENVS.join("|")
            );
            static ref RE: Regex = Regex::new(&PATTERN).unwrap();
        }
        RE.captures(&name).map(|c| {
            fn fn_map(s: &str) -> Option<String> {
                if s.is_empty() {
                    None
                } else {
                    Some(s.to_owned())
                }
            }

            Self {
                arch: c.get(1).map(|s| s.as_str()).and_then(fn_map),
                os: c.get(2).map(|s| s.as_str()).and_then(fn_map),
                env: c.get(3).map(|s| s.as_str()).and_then(fn_map),
            }
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_partial_target_triple_new() {
        let success_cases = vec![
            ("", (None, None, None)),
            ("i386", (Some("i386"), None, None)),
            ("pc-windows", (None, Some("pc-windows"), None)),
            ("gnu", (None, None, Some("gnu"))),
            ("i386-gnu", (Some("i386"), None, Some("gnu"))),
            ("pc-windows-gnu", (None, Some("pc-windows"), Some("gnu"))),
            ("i386-pc-windows", (Some("i386"), Some("pc-windows"), None)),
            (
                "i386-pc-windows-gnu",
                (Some("i386"), Some("pc-windows"), Some("gnu")),
            ),
        ];

        for (input, (arch, os, env)) in success_cases {
            let partial_target_triple = PartialTargetTriple::new(input);
            assert!(
                partial_target_triple.is_some(),
                "expected `{}` to create some partial target triple; got None",
                input
            );

            let expected = PartialTargetTriple {
                arch: arch.map(String::from),
                os: os.map(String::from),
                env: env.map(String::from),
            };

            assert_eq!(
                partial_target_triple.unwrap(),
                expected,
                "input: `{}`",
                input
            );
        }

        let failure_cases = vec![
            "anything",
            "any-other-thing",
            "-",
            "--",
            "i386-",
            "i386-pc-",
            "i386-pc-windows-",
            "-pc-windows",
            "i386-pc-windows-anything",
            "0000-00-00-",
            "00000-000-000",
        ];

        for input in failure_cases {
            let partial_target_triple = PartialTargetTriple::new(input);
            assert!(
                partial_target_triple.is_none(),
                "expected `{}` to be `None`, was: `{:?}`",
                input,
                partial_target_triple
            );
        }
    }
}
<|endoftext|>