<commit_before>//! A collection of updates of the form `(T, i64)`.

/// A collection of updates of the form `(T, i64)`.
///
/// A `ChangeBatch` accumulates updates of the form `(T, i64)`, where it is capable of consolidating
/// the representation and removing elements whose `i64` field accumulates to zero.
///
/// The implementation is designed to be as lazy as possible, simply appending to a list of updates
/// until they are required. This means that several seemingly simple operations may be expensive, in
/// that they may provoke a compaction. I've tried to prevent exposing methods that allow surprisingly
/// expensive operations; all operations should take an amortized constant or logarithmic time.
#[derive(Clone, Debug)]
pub struct ChangeBatch<T> {
    // A list of updates to which we append.
    updates: Vec<(T, i64)>,
    // The length of the prefix of `self.updates` known to be compact.
    clean: usize,
}

impl<T:Ord> ChangeBatch<T> {

    /// Allocates a new empty `ChangeBatch`.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new();
    /// assert!(batch.is_empty());
    ///```
    pub fn new() -> ChangeBatch<T> {
        ChangeBatch {
            updates: Vec::new(),
            clean: 0
        }
    }

    /// Allocates a new `ChangeBatch` with a single entry.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// assert!(!batch.is_empty());
    ///```
    pub fn new_from(key: T, val: i64) -> ChangeBatch<T> {
        let mut result = ChangeBatch::new();
        result.update(key, val);
        result
    }

    /// Adds a new update, for `item` with `value`.
    ///
    /// This could be optimized to perform compaction when the number of "dirty" elements exceeds
    /// half the length of the list, which would keep the total footprint within reasonable bounds
    /// even under an arbitrary number of updates. This has a cost, and it isn't clear whether it
    /// is worth paying without some experimentation.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new();
    /// batch.update(17, 1);
    /// assert!(!batch.is_empty());
    ///```
    #[inline]
    pub fn update(&mut self, item: T, value: i64) {
        self.updates.push((item, value));
    }

    /// Performs a sequence of updates described by `iterator`.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.extend(vec![(17, -1)].into_iter());
    /// assert!(batch.is_empty());
    ///```
    #[inline]
    pub fn extend<I: Iterator<Item=(T, i64)>>(&mut self, iterator: I) {
        for (key, val) in iterator {
            self.update(key, val);
        }
    }

    /// Extracts the `Vec<(T, i64)>` from the map, consuming it.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let batch = ChangeBatch::<usize>::new_from(17, 1);
    /// assert_eq!(batch.into_inner(), vec![(17, 1)]);
    ///```
    pub fn into_inner(mut self) -> Vec<(T, i64)> {
        self.compact();
        self.updates
    }

    /// Iterates over the contents of the map.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// {   // scope allows borrow of `batch` to drop.
    ///     let mut iter = batch.iter();
    ///     assert_eq!(iter.next(), Some(&(17, 1)));
    ///     assert_eq!(iter.next(), None);
    /// }
    /// assert!(!batch.is_empty());
    ///```
    pub fn iter(&mut self) -> ::std::slice::Iter<(T, i64)> {
        self.compact();
        self.updates.iter()
    }

    /// Drains the set of updates.
    ///
    /// This operation first compacts the set of updates so that the drained results
    /// have at most one occurence of each item.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// {   // scope allows borrow of `batch` to drop.
    ///     let mut iter = batch.drain();
    ///     assert_eq!(iter.next(), Some((17, 1)));
    ///     assert_eq!(iter.next(), None);
    /// }
    /// assert!(batch.is_empty());
    ///```
    pub fn drain(&mut self) -> ::std::vec::Drain<(T, i64)> {
        self.compact();
        self.clean = 0;
        self.updates.drain(..)
    }

    /// Clears the map.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.clear();
    /// assert!(batch.is_empty());
    ///```
    pub fn clear(&mut self) {
        self.updates.clear();
        self.clean = 0;
    }

    /// True iff all keys have value zero.
    ///
    /// This method requires mutable access to `self` because it may need to compact the representation
    /// to determine if the batch of updates is indeed empty. We could also implement a weaker form of
    /// `is_empty` which just checks the length of `self.updates`, and which could confirm the absence of
    /// any updates, but could report false negatives if there are updates which would cancel.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.update(17, -1);
    /// assert!(batch.is_empty());
    ///```
    pub fn is_empty(&mut self) -> bool {
        if self.clean > self.updates.len() / 2 {
            false
        }
        else {
            self.compact();
            self.updates.is_empty()
        }
    }

    /// Drains `self` into `other`.
    ///
    /// This method has similar a effect to calling `other.extend(self.drain())`, but has the
    /// opportunity to optimize this to a `::std::mem::swap(self, other)` when `other` is empty.
    /// As many uses of this method are to propagate updates, this optimization can be quite
    /// handy.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch1 = ChangeBatch::<usize>::new_from(17, 1);
    /// let mut batch2 = ChangeBatch::new();
    /// batch1.drain_into(&mut batch2);
    /// assert!(batch1.is_empty());
    /// assert!(!batch2.is_empty());
    ///```
    pub fn drain_into(&mut self, other: &mut ChangeBatch<T>) where T: Clone {
        if other.updates.len() == 0 {
            ::std::mem::swap(self, other);
        }
        else {
            other.extend(self.updates.drain(..));
        }
    }

    /// Compact the internal representation.
    ///
    /// This method sort `self.updates` and consolidates elements with equal item, discarding
    /// any whose accumulation is zero. It is optimized to only do this if the number of dirty
    /// elements is non-zero.
    #[inline]
    fn compact(&mut self) {
        if self.clean < self.updates.len() && self.updates.len() > 1 {
            self.updates.sort_by(|x,y| x.0.cmp(&y.0));
            for i in 0 .. self.updates.len() - 1 {
                if self.updates[i].0 == self.updates[i+1].0 {
                    self.updates[i+1].1 += self.updates[i].1;
                    self.updates[i].1 = 0;
                }
            }
            self.updates.retain(|x| x.1 != 0);
        }
        self.clean = self.updates.len();
    }
}
<commit_msg>clear .clean in drain_into<commit_after>//! A collection of updates of the form `(T, i64)`.

/// A collection of updates of the form `(T, i64)`.
///
/// A `ChangeBatch` accumulates updates of the form `(T, i64)`, where it is capable of consolidating
/// the representation and removing elements whose `i64` field accumulates to zero.
///
/// The implementation is designed to be as lazy as possible, simply appending to a list of updates
/// until they are required. This means that several seemingly simple operations may be expensive, in
/// that they may provoke a compaction. I've tried to prevent exposing methods that allow surprisingly
/// expensive operations; all operations should take an amortized constant or logarithmic time.
#[derive(Clone, Debug)]
pub struct ChangeBatch<T> {
    // A list of updates to which we append.
    updates: Vec<(T, i64)>,
    // The length of the prefix of `self.updates` known to be compact.
    clean: usize,
}

impl<T:Ord> ChangeBatch<T> {

    /// Allocates a new empty `ChangeBatch`.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new();
    /// assert!(batch.is_empty());
    ///```
    pub fn new() -> ChangeBatch<T> {
        ChangeBatch {
            updates: Vec::new(),
            clean: 0
        }
    }

    /// Allocates a new `ChangeBatch` with a single entry.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// assert!(!batch.is_empty());
    ///```
    pub fn new_from(key: T, val: i64) -> ChangeBatch<T> {
        let mut result = ChangeBatch::new();
        result.update(key, val);
        result
    }

    /// Adds a new update, for `item` with `value`.
    ///
    /// This could be optimized to perform compaction when the number of "dirty" elements exceeds
    /// half the length of the list, which would keep the total footprint within reasonable bounds
    /// even under an arbitrary number of updates. This has a cost, and it isn't clear whether it
    /// is worth paying without some experimentation.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new();
    /// batch.update(17, 1);
    /// assert!(!batch.is_empty());
    ///```
    #[inline]
    pub fn update(&mut self, item: T, value: i64) {
        self.updates.push((item, value));
    }

    /// Performs a sequence of updates described by `iterator`.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.extend(vec![(17, -1)].into_iter());
    /// assert!(batch.is_empty());
    ///```
    #[inline]
    pub fn extend<I: Iterator<Item=(T, i64)>>(&mut self, iterator: I) {
        for (key, val) in iterator {
            self.update(key, val);
        }
    }

    /// Extracts the `Vec<(T, i64)>` from the map, consuming it.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let batch = ChangeBatch::<usize>::new_from(17, 1);
    /// assert_eq!(batch.into_inner(), vec![(17, 1)]);
    ///```
    pub fn into_inner(mut self) -> Vec<(T, i64)> {
        self.compact();
        self.updates
    }

    /// Iterates over the contents of the map.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// {   // scope allows borrow of `batch` to drop.
    ///     let mut iter = batch.iter();
    ///     assert_eq!(iter.next(), Some(&(17, 1)));
    ///     assert_eq!(iter.next(), None);
    /// }
    /// assert!(!batch.is_empty());
    ///```
    pub fn iter(&mut self) -> ::std::slice::Iter<(T, i64)> {
        self.compact();
        self.updates.iter()
    }

    /// Drains the set of updates.
    ///
    /// This operation first compacts the set of updates so that the drained results
    /// have at most one occurence of each item.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// {   // scope allows borrow of `batch` to drop.
    ///     let mut iter = batch.drain();
    ///     assert_eq!(iter.next(), Some((17, 1)));
    ///     assert_eq!(iter.next(), None);
    /// }
    /// assert!(batch.is_empty());
    ///```
    pub fn drain(&mut self) -> ::std::vec::Drain<(T, i64)> {
        self.compact();
        self.clean = 0;
        self.updates.drain(..)
    }

    /// Clears the map.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.clear();
    /// assert!(batch.is_empty());
    ///```
    pub fn clear(&mut self) {
        self.updates.clear();
        self.clean = 0;
    }

    /// True iff all keys have value zero.
    ///
    /// This method requires mutable access to `self` because it may need to compact the representation
    /// to determine if the batch of updates is indeed empty. We could also implement a weaker form of
    /// `is_empty` which just checks the length of `self.updates`, and which could confirm the absence of
    /// any updates, but could report false negatives if there are updates which would cancel.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch = ChangeBatch::<usize>::new_from(17, 1);
    /// batch.update(17, -1);
    /// assert!(batch.is_empty());
    ///```
    pub fn is_empty(&mut self) -> bool {
        if self.clean > self.updates.len() / 2 {
            false
        }
        else {
            self.compact();
            self.updates.is_empty()
        }
    }

    /// Drains `self` into `other`.
    ///
    /// This method has similar a effect to calling `other.extend(self.drain())`, but has the
    /// opportunity to optimize this to a `::std::mem::swap(self, other)` when `other` is empty.
    /// As many uses of this method are to propagate updates, this optimization can be quite
    /// handy.
    ///
    /// #Examples
    ///
    ///```
    /// use timely::progress::ChangeBatch;
    ///
    /// let mut batch1 = ChangeBatch::<usize>::new_from(17, 1);
    /// let mut batch2 = ChangeBatch::new();
    /// batch1.drain_into(&mut batch2);
    /// assert!(batch1.is_empty());
    /// assert!(!batch2.is_empty());
    ///```
    pub fn drain_into(&mut self, other: &mut ChangeBatch<T>) where T: Clone {
        if other.updates.len() == 0 {
            ::std::mem::swap(self, other);
        }
        else {
            other.extend(self.updates.drain(..));
            self.clean = 0;
        }
    }

    /// Compact the internal representation.
    ///
    /// This method sort `self.updates` and consolidates elements with equal item, discarding
    /// any whose accumulation is zero. It is optimized to only do this if the number of dirty
    /// elements is non-zero.
    #[inline]
    fn compact(&mut self) {
        if self.clean < self.updates.len() && self.updates.len() > 1 {
            self.updates.sort_by(|x,y| x.0.cmp(&y.0));
            for i in 0 .. self.updates.len() - 1 {
                if self.updates[i].0 == self.updates[i+1].0 {
                    self.updates[i+1].1 += self.updates[i].1;
                    self.updates[i].1 = 0;
                }
            }
            self.updates.retain(|x| x.1 != 0);
        }
        self.clean = self.updates.len();
    }
}
<|endoftext|>


<commit_before>use std::cmp;
use std::io::Read;
use std::io::Write;

use bufstream::BufStream;

use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Set;

use super::conversions::as_number;
use super::conversions::as_string;
use super::errors::TcpTransportError;
use super::stats::TransportStats;
use super::typedefs::TcpTransportResult;

pub struct TcpTransport<T: Read + Write> {
    stream: BufStream<T>,

    pub line_buffer: Vec<u8>,
    pub line_cursor: usize,
    pub line_break_pos: usize,

    key_maxlen: u64,

    stats: TransportStats,
}

impl<T: Read + Write> TcpTransport<T> {
    pub fn new(stream: T) -> TcpTransport<T> {
        TcpTransport {
            key_maxlen: 250, // memcached standard

            // Used to read the first line of a command, which includes a
            // keyword, a key, flags and a bytecount. We don't expect it to be
            // much longer than the key itself. If it is we panic...
            line_buffer: vec![0; 250 + 100],
            line_cursor: 0,
            line_break_pos: 0,

            stats: TransportStats::new(),
            stream: BufStream::new(stream),
        }
    }

    pub fn with_key_maxlen(&mut self,
                           key_maxlen: u64)
                           -> &mut TcpTransport<T> {
        self.key_maxlen = key_maxlen;
        self
    }

    pub fn get_max_line_len(&self) -> usize {
        // This needs to be the length of the longest command line, not
        // including data values for which the length is given upfront
        self.key_maxlen as usize + 100
    }

    pub fn get_stats_clone(&self) -> TransportStats {
        self.stats.clone()
    }

    pub fn get_stream(&self) -> &T {
        self.stream.get_ref()
    }

    // Basic bytes manipulation and reading from the stream

    pub fn read_byte(&mut self) -> TcpTransportResult<u8> {
        let mut bytes = [0; 1];

        match self.stream.read(&mut bytes) {
            Ok(1) => {
                // Update stats
                self.stats.bytes_read += 1;

                Ok(bytes[0])
            }
            _ => Err(TcpTransportError::StreamReadError),
        }
    }

    pub fn read_bytes(&mut self, len: u64) -> TcpTransportResult<Vec<u8>> {
        let mut bytes = vec![0; len as usize];

        match self.stream.read(&mut bytes[..]) {
            Ok(n) => {
                // Update stats
                self.stats.bytes_read += n as u64;

                Ok(bytes)
            }
            _ => Err(TcpTransportError::StreamReadError),
        }
    }

    pub fn preread_line(&mut self) -> TcpTransportResult<()> {
        let mut cursor = 0;

        // We keep reading one byte at a time into line_buffer, looking for
        // a line terminator \r\n. The underlying stream is buffered.
        loop {
            // Make sure we don't go over bounds
            if cursor >= self.line_buffer.len() {
                panic!("Line too long to be read");
            }

            let rv = self.stream.read(&mut self.line_buffer[cursor..cursor+1]);

            // If there was an error or if there was nothing to read we bail
            if rv.is_err() || rv.unwrap() == 0 {
                return Err(TcpTransportError::StreamReadError);
            }

            // We found \r
            if self.line_buffer[cursor] == 13 {
                // Read one more, hoping it's \n
                cursor += 1;
                let rv = self.stream.read(&mut self.line_buffer[cursor..cursor+1]);

                // If there was an error or if there was nothing to read we bail
                if rv.is_err() || rv.unwrap() == 0 {
                    return Err(TcpTransportError::StreamReadError);
                }

                // Woops, it's not \n, we bail
                if self.line_buffer[cursor] != 10 {
                    return Err(TcpTransportError::StreamReadError);
                }

                break;
            }

            cursor += 1;
        }

        self.line_cursor = 0;
        self.line_break_pos = cursor - 1;  // point it at \r, not \n

        Ok(())
    }

    pub fn line_is_empty(&self) -> bool {
        // If the cursor precedes the line break then there are still bytes to
        // read from the line, otherwise it's empty
        self.line_cursor >= self.line_break_pos
    }

    pub fn line_remove_first_char(&mut self) -> TcpTransportResult<()> {
        match !self.line_is_empty() {
            true => {
                self.line_cursor += 1;
                Ok(())
            }
            false => Err(TcpTransportError::LineReadError),
        }
    }

    pub fn line_parse_word(&mut self) -> TcpTransportResult<&[u8]> {
        // If the very first char is a space then our caller is out of sync
        if self.line_buffer[self.line_cursor] == 32 {
            return Err(TcpTransportError::StreamReadError);
        }

        let mut space_idx = 0;
        let mut found = false;

        for i in self.line_cursor + 1..self.line_break_pos {
            // We found a space
            if self.line_buffer[i] == 32 {
                space_idx = i;
                found = true;
                break;
            }
        }

        // If we didn't find a space then the whole line is a word
        // TODO test for this
        if !found {
            space_idx = self.line_break_pos;
        }

        // Advance the cursor, we've now "consumed" the word we found
        let word = &self.line_buffer[self.line_cursor..space_idx];
        self.line_cursor = space_idx;

        Ok(word)
    }

    // Writing to the stream

    pub fn flush_writes(&mut self) -> TcpTransportResult<()> {
        match self.stream.flush() {
            Ok(_) => Ok(()),
            Err(_) => Err(TcpTransportError::StreamWriteError),
        }
    }

    pub fn write_bytes(&mut self,
                       bytes: &Vec<u8>)
                       -> TcpTransportResult<usize> {
        match self.stream.write(bytes) {
            Ok(cnt_written) => {
                // Update stats
                self.stats.bytes_written += cnt_written as u64;

                Ok(cnt_written)
            }
            Err(_) => Err(TcpTransportError::StreamWriteError),
        }
    }

    pub fn write_string(&mut self, string: &str) -> TcpTransportResult<usize> {
        let bytes = string.to_string().into_bytes();
        Ok(try!(self.write_bytes(&bytes)))
    }

    // Parse individual commands

    pub fn parse_cmd_get(&mut self) -> TcpTransportResult<Cmd> {
        // remove the space after the keyword
        try!(self.line_remove_first_char());

        // parse the key
        let key_str = {
            let key = try!(self.line_parse_word());
            try!(as_string(key))
        };

        // We expect to find the end of the line now
        if self.line_is_empty() {
            Ok(Cmd::Get(Get { key: key_str }))
        } else {
            Err(TcpTransportError::CommandParseError)
        }
    }

    pub fn parse_cmd_set(&mut self) -> TcpTransportResult<Cmd> {
        // remove the space after the keyword
        try!(self.line_remove_first_char());

        // parse the key + remove trailing space
        let key_str = {
            let key = try!(self.line_parse_word());
            try!(as_string(key))
        };
        try!(self.line_remove_first_char());

        // parse the flags + remove trailing space
        let flags_num = {
            let flags = try!(self.line_parse_word());
            try!(as_number::<u16>(flags))
        };
        try!(self.line_remove_first_char());

        // parse the exptime + remove trailing space
        let exptime_num = {
            let exptime = try!(self.line_parse_word());
            try!(as_number::<u32>(exptime))
        };
        try!(self.line_remove_first_char());

        // parse the bytelen
        let bytelen_num = {
            let bytelen = try!(self.line_parse_word());
            try!(as_number::<u64>(bytelen))
        };

        // We know the byte length, so now read the value
        let value = try!(self.read_bytes(bytelen_num));

        // Read the line termination marker and verify it
        let newline = try!(self.read_bytes(2));
        if !newline.starts_with(&[13, 10]) {
            return Err(TcpTransportError::CommandParseError);
        }

        // We got all the values we expected and there is nothing left
        return Ok(Cmd::Set(Set {
            key: key_str,
            exptime: exptime_num,
            data: value,
        }));
    }

    // High level functions

    pub fn read_cmd(&mut self) -> TcpTransportResult<Cmd> {
        // read the first line
        try!(self.preread_line());

        let keyword_str = {
            let keyword = try!(self.line_parse_word());
            try!(as_string(keyword))
        };

        if keyword_str == "get" {
            return self.parse_cmd_get();
        } else if keyword_str == "set" {
            return self.parse_cmd_set();
        } else if keyword_str == "stats" {
            return Ok(Cmd::Stats);
        }

        Err(TcpTransportError::InvalidCmd)
    }

    pub fn write_resp(&mut self, resp: &Resp) -> TcpTransportResult<()> {
        match *resp {
            Resp::Error => {
                try!(self.write_string("ERROR\r\n"));
            }
            Resp::Stats(ref stats) => {
                for stat in stats {
                    try!(self.write_string("STAT "));
                    try!(self.write_string(&stat.key));
                    try!(self.write_string(" "));
                    try!(self.write_string(&stat.value));
                    try!(self.write_string("\r\n"));
                }
                try!(self.write_string("END\r\n"));
            }
            Resp::Stored => {
                try!(self.write_string("STORED\r\n"));
            }
            Resp::Value(ref value) => {
                try!(self.write_string("VALUE ")); // keyword
                try!(self.write_string(&value.key)); // key
                try!(self.write_string(" 0 ")); // flags
                try!(self.write_string(&value.data.len().to_string())); // bytelen
                try!(self.write_string(&"\r\n".to_string())); // newline
                try!(self.write_bytes(&value.data)); // data block
                try!(self.write_string(&"\r\n".to_string())); // newline
            }
            _ => {
                return Err(TcpTransportError::StreamWriteError);
            }
        }

        // Make sure all bytes were actually sent
        self.flush_writes()
    }
}
<commit_msg>kill old comment<commit_after>use std::cmp;
use std::io::Read;
use std::io::Write;

use bufstream::BufStream;

use protocol::cmd::Cmd;
use protocol::cmd::Get;
use protocol::cmd::Resp;
use protocol::cmd::Set;

use super::conversions::as_number;
use super::conversions::as_string;
use super::errors::TcpTransportError;
use super::stats::TransportStats;
use super::typedefs::TcpTransportResult;

pub struct TcpTransport<T: Read + Write> {
    stream: BufStream<T>,

    pub line_buffer: Vec<u8>,
    pub line_cursor: usize,
    pub line_break_pos: usize,

    key_maxlen: u64,

    stats: TransportStats,
}

impl<T: Read + Write> TcpTransport<T> {
    pub fn new(stream: T) -> TcpTransport<T> {
        TcpTransport {
            key_maxlen: 250, // memcached standard

            // Used to read the first line of a command, which includes a
            // keyword, a key, flags and a bytecount. We don't expect it to be
            // much longer than the key itself. If it is we panic...
            line_buffer: vec![0; 250 + 100],
            line_cursor: 0,
            line_break_pos: 0,

            stats: TransportStats::new(),
            stream: BufStream::new(stream),
        }
    }

    pub fn with_key_maxlen(&mut self,
                           key_maxlen: u64)
                           -> &mut TcpTransport<T> {
        self.key_maxlen = key_maxlen;
        self
    }

    pub fn get_max_line_len(&self) -> usize {
        // This needs to be the length of the longest command line, not
        // including data values for which the length is given upfront
        self.key_maxlen as usize + 100
    }

    pub fn get_stats_clone(&self) -> TransportStats {
        self.stats.clone()
    }

    pub fn get_stream(&self) -> &T {
        self.stream.get_ref()
    }

    // Basic bytes manipulation and reading from the stream

    pub fn read_byte(&mut self) -> TcpTransportResult<u8> {
        let mut bytes = [0; 1];

        match self.stream.read(&mut bytes) {
            Ok(1) => {
                // Update stats
                self.stats.bytes_read += 1;

                Ok(bytes[0])
            }
            _ => Err(TcpTransportError::StreamReadError),
        }
    }

    pub fn read_bytes(&mut self, len: u64) -> TcpTransportResult<Vec<u8>> {
        let mut bytes = vec![0; len as usize];

        match self.stream.read(&mut bytes[..]) {
            Ok(n) => {
                // Update stats
                self.stats.bytes_read += n as u64;

                Ok(bytes)
            }
            _ => Err(TcpTransportError::StreamReadError),
        }
    }

    pub fn preread_line(&mut self) -> TcpTransportResult<()> {
        let mut cursor = 0;

        // We keep reading one byte at a time into line_buffer, looking for
        // a line terminator \r\n. The underlying stream is buffered.
        loop {
            // Make sure we don't go over bounds
            if cursor >= self.line_buffer.len() {
                panic!("Line too long to be read");
            }

            let rv = self.stream.read(&mut self.line_buffer[cursor..cursor+1]);

            // If there was an error or if there was nothing to read we bail
            if rv.is_err() || rv.unwrap() == 0 {
                return Err(TcpTransportError::StreamReadError);
            }

            // We found \r
            if self.line_buffer[cursor] == 13 {
                // Read one more, hoping it's \n
                cursor += 1;
                let rv = self.stream.read(&mut self.line_buffer[cursor..cursor+1]);

                // If there was an error or if there was nothing to read we bail
                if rv.is_err() || rv.unwrap() == 0 {
                    return Err(TcpTransportError::StreamReadError);
                }

                // Woops, it's not \n, we bail
                if self.line_buffer[cursor] != 10 {
                    return Err(TcpTransportError::StreamReadError);
                }

                break;
            }

            cursor += 1;
        }

        self.line_cursor = 0;
        self.line_break_pos = cursor - 1;  // point it at \r, not \n

        Ok(())
    }

    pub fn line_is_empty(&self) -> bool {
        // If the cursor precedes the line break then there are still bytes to
        // read from the line, otherwise it's empty
        self.line_cursor >= self.line_break_pos
    }

    pub fn line_remove_first_char(&mut self) -> TcpTransportResult<()> {
        match !self.line_is_empty() {
            true => {
                self.line_cursor += 1;
                Ok(())
            }
            false => Err(TcpTransportError::LineReadError),
        }
    }

    pub fn line_parse_word(&mut self) -> TcpTransportResult<&[u8]> {
        // If the very first char is a space then our caller is out of sync
        if self.line_buffer[self.line_cursor] == 32 {
            return Err(TcpTransportError::StreamReadError);
        }

        let mut space_idx = 0;
        let mut found = false;

        for i in self.line_cursor + 1..self.line_break_pos {
            // We found a space
            if self.line_buffer[i] == 32 {
                space_idx = i;
                found = true;
                break;
            }
        }

        // If we didn't find a space then the whole line is a word
        if !found {
            space_idx = self.line_break_pos;
        }

        // Advance the cursor, we've now "consumed" the word we found
        let word = &self.line_buffer[self.line_cursor..space_idx];
        self.line_cursor = space_idx;

        Ok(word)
    }

    // Writing to the stream

    pub fn flush_writes(&mut self) -> TcpTransportResult<()> {
        match self.stream.flush() {
            Ok(_) => Ok(()),
            Err(_) => Err(TcpTransportError::StreamWriteError),
        }
    }

    pub fn write_bytes(&mut self,
                       bytes: &Vec<u8>)
                       -> TcpTransportResult<usize> {
        match self.stream.write(bytes) {
            Ok(cnt_written) => {
                // Update stats
                self.stats.bytes_written += cnt_written as u64;

                Ok(cnt_written)
            }
            Err(_) => Err(TcpTransportError::StreamWriteError),
        }
    }

    pub fn write_string(&mut self, string: &str) -> TcpTransportResult<usize> {
        let bytes = string.to_string().into_bytes();
        Ok(try!(self.write_bytes(&bytes)))
    }

    // Parse individual commands

    pub fn parse_cmd_get(&mut self) -> TcpTransportResult<Cmd> {
        // remove the space after the keyword
        try!(self.line_remove_first_char());

        // parse the key
        let key_str = {
            let key = try!(self.line_parse_word());
            try!(as_string(key))
        };

        // We expect to find the end of the line now
        if self.line_is_empty() {
            Ok(Cmd::Get(Get { key: key_str }))
        } else {
            Err(TcpTransportError::CommandParseError)
        }
    }

    pub fn parse_cmd_set(&mut self) -> TcpTransportResult<Cmd> {
        // remove the space after the keyword
        try!(self.line_remove_first_char());

        // parse the key + remove trailing space
        let key_str = {
            let key = try!(self.line_parse_word());
            try!(as_string(key))
        };
        try!(self.line_remove_first_char());

        // parse the flags + remove trailing space
        let flags_num = {
            let flags = try!(self.line_parse_word());
            try!(as_number::<u16>(flags))
        };
        try!(self.line_remove_first_char());

        // parse the exptime + remove trailing space
        let exptime_num = {
            let exptime = try!(self.line_parse_word());
            try!(as_number::<u32>(exptime))
        };
        try!(self.line_remove_first_char());

        // parse the bytelen
        let bytelen_num = {
            let bytelen = try!(self.line_parse_word());
            try!(as_number::<u64>(bytelen))
        };

        // We know the byte length, so now read the value
        let value = try!(self.read_bytes(bytelen_num));

        // Read the line termination marker and verify it
        let newline = try!(self.read_bytes(2));
        if !newline.starts_with(&[13, 10]) {
            return Err(TcpTransportError::CommandParseError);
        }

        // We got all the values we expected and there is nothing left
        return Ok(Cmd::Set(Set {
            key: key_str,
            exptime: exptime_num,
            data: value,
        }));
    }

    // High level functions

    pub fn read_cmd(&mut self) -> TcpTransportResult<Cmd> {
        // read the first line
        try!(self.preread_line());

        let keyword_str = {
            let keyword = try!(self.line_parse_word());
            try!(as_string(keyword))
        };

        if keyword_str == "get" {
            return self.parse_cmd_get();
        } else if keyword_str == "set" {
            return self.parse_cmd_set();
        } else if keyword_str == "stats" {
            return Ok(Cmd::Stats);
        }

        Err(TcpTransportError::InvalidCmd)
    }

    pub fn write_resp(&mut self, resp: &Resp) -> TcpTransportResult<()> {
        match *resp {
            Resp::Error => {
                try!(self.write_string("ERROR\r\n"));
            }
            Resp::Stats(ref stats) => {
                for stat in stats {
                    try!(self.write_string("STAT "));
                    try!(self.write_string(&stat.key));
                    try!(self.write_string(" "));
                    try!(self.write_string(&stat.value));
                    try!(self.write_string("\r\n"));
                }
                try!(self.write_string("END\r\n"));
            }
            Resp::Stored => {
                try!(self.write_string("STORED\r\n"));
            }
            Resp::Value(ref value) => {
                try!(self.write_string("VALUE ")); // keyword
                try!(self.write_string(&value.key)); // key
                try!(self.write_string(" 0 ")); // flags
                try!(self.write_string(&value.data.len().to_string())); // bytelen
                try!(self.write_string(&"\r\n".to_string())); // newline
                try!(self.write_bytes(&value.data)); // data block
                try!(self.write_string(&"\r\n".to_string())); // newline
            }
            _ => {
                return Err(TcpTransportError::StreamWriteError);
            }
        }

        // Make sure all bytes were actually sent
        self.flush_writes()
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(PartialEq)]
enum Status {
    Stable,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
        };
        fmt::Display::fmt(as_str, f)
    }
}

struct Feature {
    name: String,
    level: Status,
    since: String,
}

struct LibFeature {
    level: Status,
    since: String,
}

pub fn check(path: &Path, bad: &mut bool) {
    let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
    assert!(!features.is_empty());
    let mut lib_features = HashMap::<String, LibFeature>::new();

    let mut contents = String::new();
    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(file)).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => {
                    err("malformed stability attribute");
                    continue;
                }
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err("malformed stability attribute");
                    continue;
                }
                None => "None",
            };

            if features.iter().any(|f| f.name == feature_name) {
                err("duplicating a lang feature");
            }
            if let Some(ref s) = lib_features.get(feature_name) {
                if s.level != level {
                    err("different stability level than before");
                }
                if s.since != since {
                    err("different `since` than before");
                }
                continue;
            }
            lib_features.insert(feature_name.to_owned(),
                                LibFeature {
                                    level: level,
                                    since: since.to_owned(),
                                });
        }
    });

    if *bad {
        return;
    }

    let mut lines = Vec::new();
    for feature in features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           feature.name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn collect_lang_features(path: &Path) -> Vec<Feature> {
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Unstable,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            Some(Feature {
                name: name.to_owned(),
                level: level,
                since: since.to_owned(),
            })
        })
        .collect()
}
<commit_msg>Rollup merge of #38422 - zackmdavis:enjoy_tidy_path_error_macro_nicety, r=bluss<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy check to ensure that unstable features are all in order
//!
//! This check will ensure properties like:
//!
//! * All stability attributes look reasonably well formed
//! * The set of library features is disjoint from the set of language features
//! * Library features have at most one stability level
//! * Library features have at most one `since` value

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;

#[derive(PartialEq)]
enum Status {
    Stable,
    Unstable,
}

impl fmt::Display for Status {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let as_str = match *self {
            Status::Stable => "stable",
            Status::Unstable => "unstable",
        };
        fmt::Display::fmt(as_str, f)
    }
}

struct Feature {
    name: String,
    level: Status,
    since: String,
}

struct LibFeature {
    level: Status,
    since: String,
}

pub fn check(path: &Path, bad: &mut bool) {
    let features = collect_lang_features(&path.join("libsyntax/feature_gate.rs"));
    assert!(!features.is_empty());
    let mut lib_features = HashMap::<String, LibFeature>::new();

    let mut contents = String::new();
    super::walk(path,
                &mut |path| super::filter_dirs(path) || path.ends_with("src/test"),
                &mut |file| {
        let filename = file.file_name().unwrap().to_string_lossy();
        if !filename.ends_with(".rs") || filename == "features.rs" ||
           filename == "diagnostic_list.rs" {
            return;
        }

        contents.truncate(0);
        t!(t!(File::open(&file), &file).read_to_string(&mut contents));

        for (i, line) in contents.lines().enumerate() {
            let mut err = |msg: &str| {
                println!("{}:{}: {}", file.display(), i + 1, msg);
                *bad = true;
            };
            let level = if line.contains("[unstable(") {
                Status::Unstable
            } else if line.contains("[stable(") {
                Status::Stable
            } else {
                continue;
            };
            let feature_name = match find_attr_val(line, "feature") {
                Some(name) => name,
                None => {
                    err("malformed stability attribute");
                    continue;
                }
            };
            let since = match find_attr_val(line, "since") {
                Some(name) => name,
                None if level == Status::Stable => {
                    err("malformed stability attribute");
                    continue;
                }
                None => "None",
            };

            if features.iter().any(|f| f.name == feature_name) {
                err("duplicating a lang feature");
            }
            if let Some(ref s) = lib_features.get(feature_name) {
                if s.level != level {
                    err("different stability level than before");
                }
                if s.since != since {
                    err("different `since` than before");
                }
                continue;
            }
            lib_features.insert(feature_name.to_owned(),
                                LibFeature {
                                    level: level,
                                    since: since.to_owned(),
                                });
        }
    });

    if *bad {
        return;
    }

    let mut lines = Vec::new();
    for feature in features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           feature.name,
                           "lang",
                           feature.level,
                           feature.since));
    }
    for (name, feature) in lib_features {
        lines.push(format!("{:<32} {:<8} {:<12} {:<8}",
                           name,
                           "lib",
                           feature.level,
                           feature.since));
    }

    lines.sort();
    for line in lines {
        println!("* {}", line);
    }
}

fn find_attr_val<'a>(line: &'a str, attr: &str) -> Option<&'a str> {
    line.find(attr)
        .and_then(|i| line[i..].find('"').map(|j| i + j + 1))
        .and_then(|i| line[i..].find('"').map(|j| (i, i + j)))
        .map(|(i, j)| &line[i..j])
}

fn collect_lang_features(path: &Path) -> Vec<Feature> {
    let mut contents = String::new();
    t!(t!(File::open(path)).read_to_string(&mut contents));

    contents.lines()
        .filter_map(|line| {
            let mut parts = line.trim().split(",");
            let level = match parts.next().map(|l| l.trim().trim_left_matches('(')) {
                Some("active") => Status::Unstable,
                Some("removed") => Status::Unstable,
                Some("accepted") => Status::Stable,
                _ => return None,
            };
            let name = parts.next().unwrap().trim();
            let since = parts.next().unwrap().trim().trim_matches('"');
            Some(Feature {
                name: name.to_owned(),
                level: level,
                since: since.to_owned(),
            })
        })
        .collect()
}
<|endoftext|>


<commit_before>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    clean_words_for_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<commit_msg>Boost the publication_year in the Solr searches<commit_after>use regex::Regex;
use reqwest;
use serde_json;

use web::data::{SolrTermSummary, SolrReferenceSummary};
use web::config::Config;

pub struct Search {
    solr_url: String,
    close_synonym_boost: f32,
    distant_synonym_boost: f32,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponse {
    pub docs: Vec<SolrTermSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrTermResponseContainer {
    pub response: SolrTermResponse,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponse {
    pub docs: Vec<SolrReferenceSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrRefResponseContainer {
    pub response: SolrRefResponse,
}

impl Search {
    pub fn new(config: &Config) -> Search {
        Search {
            solr_url: config.server.solr_url.clone(),
            close_synonym_boost: config.server.close_synonym_boost,
            distant_synonym_boost: config.server.distant_synonym_boost,
        }
    }

    fn get_query_part(&self, words: &[String]) -> String {
        let mut ret = String::new();

        let words_length = words.len();

        for (i, word) in words.iter().enumerate() {
            if i == words_length - 1 {
                ret += &format!("{} {}~0.8 {}*", word, word, word);
            } else {
                ret += &format!("{} {}~0.8 ", word, word);
            }
        }

        ret
    }

    pub fn term_complete(&self, cv_name: &str, q: &str)
                         -> Result<Vec<SolrTermSummary>, String>
    {
        let mut terms_url =
            self.solr_url.to_owned() + "/terms/select?wt=json&q=";

        let termid_re_string = r"^(?P<prefix>[\w_]+):(?P<accession>\d+)$";
        let termid_re = Regex::new(termid_re_string).unwrap();

        let parent_re_string = r"^\[".to_owned() + termid_re_string + r"\]$";
        let parent_re = Regex::new(&parent_re_string).unwrap();

        let maybe_captures = parent_re.captures(cv_name);

        if let Some(captures) = maybe_captures {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += &format!("(interesting_parents:{}\\:{} OR id:{}\\:{})",
                                  prefix, accession, prefix, accession);
        } else {
            terms_url += "cv_name:";
            terms_url += cv_name;
        }

        if let Some(captures) = termid_re.captures(q) {
            let prefix = captures.name("prefix").unwrap().as_str();
            let accession = captures.name("accession").unwrap().as_str();
            terms_url += " AND id:";
            terms_url += prefix;
            terms_url += r"\:";
            terms_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            terms_url += " AND (name:(";

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    terms_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    terms_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let query_part = self.get_query_part(&clean_words);

            terms_url += &format!(") OR close_synonym_words:({})^{} OR distant_synonym_words:({})^{})",
                                  query_part, self.close_synonym_boost,
                                  query_part, self.distant_synonym_boost);
        }
        print!("Solr URL: {:?}\n", terms_url);

        match reqwest::get(&terms_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrTermResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

    pub fn ref_complete(&self, q: &str) -> Result<Vec<SolrReferenceSummary>, String> {
        let mut refs_url =
            self.solr_url.to_owned() + "/refs/select?wt=json&q=";

        let id_re_string = r"^(?:(?P<prefix>[\w_]+):)?(?P<rest>\d\d\d\d\d+)$";
        let id_re = Regex::new(id_re_string).unwrap();

        if let Some(captures) = id_re.captures(q) {
            let mut prefix =
                if let Some(prefix_capture) = captures.name("prefix") {
                    prefix_capture.as_str()
                } else {
                    "PMID"
                };
            let accession = captures.name("rest").unwrap().as_str();
            refs_url += "id:";
            refs_url += prefix;
            refs_url += r"\:";
            refs_url += accession;
        } else {
            let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
            let lower_q = substring(&q.to_lowercase(), 200);

            let clean_words: Vec<String> =
                Regex::new(r"([\w-]+)").unwrap().captures_iter(&lower_q)
                .map(|cap| cap.get(1).unwrap().as_str().to_owned()).collect();

            if clean_words.is_empty() {
                return Ok(vec![]);
            }

            let clean_words_length = clean_words.len();
            let mut clean_words_for_url = String::new();

            for (i, word) in clean_words.iter().enumerate() {
                if i == clean_words_length - 1 {
                    clean_words_for_url += &format!("{} {}~0.8 {}*", word, word, word);
                } else {
                    clean_words_for_url += &format!("{} {}~0.8 ", word, word);
                }
            }

            let url_parts =
                vec!["title", "citation", "authors", "authors_abbrev"]
                .iter()
                .map(|field_name| format!("{}:({})", field_name, clean_words_for_url))
                .collect::<Vec<String>>();

            refs_url += &url_parts.join(" OR ");

            for word in clean_words {
                if word.len() == 4 && (word.starts_with("19") || word.starts_with("20")) {
                    if let Ok(num) = word.parse::<u32>() {
                        refs_url += &format!(" OR publication_year:{}^10", num);
                    }
                }
            }
        }

        print!("Solr refs URL: {:?}\n", refs_url);

        match reqwest::get(&refs_url) {
            Ok(res) => {
                println!("Status: {}", res.status());

                if res.status().is_success() {
                    match serde_json::from_reader(res) {
                        Ok(container) => {
                            let solr_response_container: SolrRefResponseContainer = container;
                            Ok(solr_response_container.response.docs)
                        },
                        Err(err) => {
                            Err(format!("Error parsing response from Solr: {:?}", err))
                        }
                    }
                } else {
                    if let Some(reason) = res.status().canonical_reason() {
                        Err(format!("HTTP request to Solr failed: {} - {}", res.status(), reason))
                    } else {
                        Err(format!("HTTP request to Solr failed with status code: {}",
                                    res.status()))
                    }
                }
            },
            Err(err) => {
                Err(format!("Error from Reqwest: {:?}", err))
            }
        }
    }

}
<|endoftext|>


<commit_before>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities, EntitiesRes};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {

        handle_new_connections(&player, &*entities, &actor, &mut connect);
        handle_disconnects(&player, &actor, &disconnect);

        send_world_updates(&player, &actor, &pos, &vel);
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize + Debug,
{
    let msg = serde_json::to_string(&msg).expect(&format!("Failed to serialize object {:?}", msg));
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn handle_new_connections(
    player: &ReadStorage<PlayerComp>,
    entities: &EntitiesRes,
    actor: &ReadStorage<Actor>,
    connect: &mut WriteStorage<Connect>,
) {
    let mut new_connections = Vec::new();
    for (new_player, entity, new_actor, _) in (player, entities, actor, &mut *connect).join() {
        new_connections.push((entity.clone(), new_actor.clone()));
        let mut payload = Vec::new();
        payload.push(json!({"id": new_actor.id}));
        let mut actors = Vec::new();
        for actor in (&actor).join() {
            actors.push(actor);
        }
        payload.push(json!({"actors": actors}));
        let greeting = ClientMessage {
            opcode: OpCode::Greeting,
            payload: payload,
        };
        send(new_player, &greeting);
    }

    for new_connection in new_connections {
        let (new_entity, new_actor) = new_connection;
        connect.remove(new_entity);
        let connection = ClientMessage {
            opcode: OpCode::Connect,
            payload: new_actor.clone(),
        };
        for (player, entity) in (player, entities).join() {
            if entity != new_entity {
                send(player, &connection);
            }
        }
    }
}

fn handle_disconnects(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    disconnect: &ReadStorage<Disconnect>,
) {
    for (actor, _) in (actor, disconnect).join() {
        let disconnect = ClientMessage {
            opcode: OpCode::Disconnect,
            payload: actor.id.clone(),
        };
        for player in (player).join() {
            send(player, &disconnect);
        }
    }

}

fn send_world_updates(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    pos: &ReadStorage<Pos>,
    vel: &ReadStorage<Vel>,
) {
    let mut serialized_actors = HashMap::new();
    for actor in (actor).join() {
        serialized_actors.insert(actor.id, Vec::new());
    }

    for (pos, vel, actor) in (pos, vel, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.push(json!({
            "pos": pos,
            "vel": vel
        }));
    }

    for (player, actor) in (player, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.push(json!({"delay": player.delay}));
    }
    let world_state = ClientMessage {
        opcode: OpCode::WorldUpdate,
        payload: serialized_actors,
    };
    for player in (player).join() {
        send(player, &world_state);
    }
}
<commit_msg>Core: Fix #35<commit_after>extern crate specs;
extern crate futures;
extern crate serde;
extern crate serde_json;
extern crate websocket_server;

use self::specs::{Join, ReadStorage, WriteStorage, System, Entities, EntitiesRes};
use self::futures::{Future, Sink};
use self::websocket_server::Message;
use self::serde::ser::Serialize;

use model::comp::{Pos, Vel, Connect, Disconnect, Player as PlayerComp, Actor};
use model::client::{Message as ClientMessage, OpCode};

use std::collections::HashMap;
use std::fmt::Debug;

pub struct Sending;
impl<'a> System<'a> for Sending {
    #[allow(type_complexity)]
    type SystemData = (ReadStorage<'a, Pos>,
     ReadStorage<'a, Vel>,
     ReadStorage<'a, PlayerComp>,
     ReadStorage<'a, Actor>,
     WriteStorage<'a, Connect>,
     ReadStorage<'a, Disconnect>,
     Entities<'a>);

    fn run(
        &mut self,
        (pos, vel, player, actor, mut connect, disconnect, entities): Self::SystemData,
    ) {

        handle_new_connections(&player, &*entities, &actor, &mut connect);
        handle_disconnects(&player, &actor, &disconnect);

        send_world_updates(&player, &actor, &pos, &vel);
    }
}

fn send<T>(player: &PlayerComp, msg: &ClientMessage<T>)
where
    T: Serialize + Debug,
{
    let msg = serde_json::to_string(&msg).expect(&format!("Failed to serialize object {:?}", msg));
    let send_channel = player.send_channel.clone();
    send_channel.send(Message::Text(msg)).wait().expect(
        "Failed to send message",
    );
}

fn handle_new_connections(
    player: &ReadStorage<PlayerComp>,
    entities: &EntitiesRes,
    actor: &ReadStorage<Actor>,
    connect: &mut WriteStorage<Connect>,
) {
    let mut new_connections = Vec::new();
    for (new_player, entity, new_actor, _) in (player, entities, actor, &mut *connect).join() {
        new_connections.push((entity.clone(), new_actor.clone()));
        let mut payload = Vec::new();
        payload.push(json!(new_actor.id));
        let mut actors = Vec::new();
        for actor in (&actor).join() {
            actors.push(actor);
        }
        payload.push(json!(actors));
        let greeting = ClientMessage {
            opcode: OpCode::Greeting,
            payload: payload,
        };
        send(new_player, &greeting);
    }

    for new_connection in new_connections {
        let (new_entity, new_actor) = new_connection;
        connect.remove(new_entity);
        let connection = ClientMessage {
            opcode: OpCode::Connect,
            payload: new_actor.clone(),
        };
        for (player, entity) in (player, entities).join() {
            if entity != new_entity {
                send(player, &connection);
            }
        }
    }
}

fn handle_disconnects(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    disconnect: &ReadStorage<Disconnect>,
) {
    for (actor, _) in (actor, disconnect).join() {
        let disconnect = ClientMessage {
            opcode: OpCode::Disconnect,
            payload: actor.id.clone(),
        };
        for player in (player).join() {
            send(player, &disconnect);
        }
    }

}

fn send_world_updates(
    player: &ReadStorage<PlayerComp>,
    actor: &ReadStorage<Actor>,
    pos: &ReadStorage<Pos>,
    vel: &ReadStorage<Vel>,
) {
    let mut serialized_actors = HashMap::new();
    for actor in (actor).join() {
        serialized_actors.insert(actor.id, HashMap::new());
    }

    for (pos, vel, actor) in (pos, vel, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("pos", json!(pos));
        actor.insert("vel", json!(vel));
    }

    for (player, actor) in (player, actor).join() {
        let mut actor = serialized_actors.get_mut(&actor.id).unwrap();
        actor.insert("delay", json!(player.delay));
    }
    let world_state = ClientMessage {
        opcode: OpCode::WorldUpdate,
        payload: serialized_actors,
    };
    for player in (player).join() {
        send(player, &world_state);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use serde_json::Value;

use crate::model::interactions::ApplicationCommandPermissionType;
use crate::utils;

/// A builder for creating several [`ApplicationCommandPermission`].
///
/// [`ApplicationCommandPermission`]: crate::model::interactions::ApplicationCommandPermission
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandsPermissions(pub Vec<Value>);

impl CreateApplicationCommandsPermissions {
    /// Creates a new application command.
    pub fn create_application_command<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateApplicationCommandPermissions) -> &mut Self,
    {
        let mut data = CreateApplicationCommandPermissions::default();
        f(&mut data);

        self.add_application_command(data);

        self
    }

    /// Adds a new interaction.
    pub fn add_application_command(
        &mut self,
        application_command: CreateApplicationCommandPermissions,
    ) -> &mut Self {
        let new_data = Value::Object(utils::hashmap_to_json_map(application_command.0));

        self.0.push(new_data);

        self
    }

    /// Sets all the interactions.
    pub fn set_application_commands(
        &mut self,
        application_commands: Vec<CreateApplicationCommandPermissions>,
    ) -> &mut Self {
        let new_application_commands = application_commands
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        for application_command in new_application_commands {
            self.0.push(application_command);
        }

        self
    }
}
/// A builder for creating an [`ApplicationCommandPermission`].
///
/// [`ApplicationCommandPermission`]: crate::model::interactions::ApplicationCommandPermission
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissions(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissions {
    /// The [`CommandId`] these permissions belong to.
    ///
    /// [`CommandId`]: crate::model::id::CommandId
    pub fn id(&mut self, application_command_id: u64) -> &mut Self {
        self.0.insert("id", Value::String(application_command_id.to_string()));
        self
    }

    /// Creates a new permission for the interaction.
    pub fn create_permission<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(
            &mut CreateApplicationCommandPermissionData,
        ) -> &mut CreateApplicationCommandPermissionData,
    {
        let mut data = CreateApplicationCommandPermissionData::default();
        f(&mut data);

        self.add_permission(data);

        self
    }

    /// Adds a permission for the interaction.
    pub fn add_permission(
        &mut self,
        permission: CreateApplicationCommandPermissionData,
    ) -> &mut Self {
        let new_data = utils::hashmap_to_json_map(permission.0);
        let permissions = self.0.entry("permissions").or_insert_with(|| Value::Array(Vec::new()));

        let permissions_array = permissions.as_array_mut().expect("Must be an array");

        permissions_array.push(Value::Object(new_data));

        self
    }

    /// Sets all the permissions for the interaction.
    pub fn set_permissions(
        &mut self,
        permissions: Vec<CreateApplicationCommandPermissionData>,
    ) -> &mut Self {
        let new_permissions = permissions
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        self.0.insert("permissions", Value::Array(new_permissions));

        self
    }
}

/// A builder for creating several [`ApplicationCommandPermissionData`].
///
/// [`ApplicationCommandPermissionData`]: crate::model::interactions::ApplicationCommandPermissionData
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissionsData(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissionsData {
    /// Creates a permission for the interaction.
    pub fn create_permission<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateApplicationCommandPermissionData) -> &mut Self,
    {
        let mut data = CreateApplicationCommandPermissionData::default();
        f(&mut data);

        self.add_permission(data);

        self
    }

    /// Adds a permission.
    pub fn add_permission(
        &mut self,
        permission: CreateApplicationCommandPermissionData,
    ) -> &mut Self {
        let new_data = utils::hashmap_to_json_map(permission.0);
        let permissions = self.0.entry("permissions").or_insert_with(|| Value::Array(Vec::new()));

        let permissions_array = permissions.as_array_mut().expect("Must be an array");

        permissions_array.push(Value::Object(new_data));

        self
    }

    /// Sets all the permissions for the interaction.
    pub fn set_permissions(
        &mut self,
        permissions: Vec<CreateApplicationCommandPermissionData>,
    ) -> &mut Self {
        let new_permissions = permissions
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        self.0.insert("permissions", Value::Array(new_permissions));

        self
    }
}

/// A builder for creating an [`ApplicationCommandPermissionData`].
///
/// All fields are required.
///
/// [`ApplicationCommandPermissionData`]: crate::model::interactions::ApplicationCommandPermissionData
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissionData(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissionData {
    /// Sets the `ApplicationCommandPermissionType` for the [`ApplicationCommandPermissionData`].
    ///
    /// [`ApplicationCommandPermissionData`]: crate::model::interaction::ApplicationCommandPermissionData
    pub fn kind(&mut self, kind: ApplicationCommandPermissionType) -> &mut Self {
        self.0.insert("type", Value::Number(serde_json::Number::from(kind as u8)));
        self
    }

    /// Sets the CommandPermissionId for the [`ApplicationCommandPermissionData`].
    ///
    /// [`ApplicationCommandPermissionData`]: crate::model::interaction::ApplicationCommandPermissionData
    pub fn id(&mut self, id: u64) -> &mut Self {
        self.0.insert("id", Value::String(id.to_string()));
        self
    }

    /// Sets the permission.
    pub fn permission(&mut self, permission: bool) -> &mut Self {
        self.0.insert("permission", Value::Bool(permission));
        self
    }
}
<commit_msg>Fix application command permission builder closures (#1386)<commit_after>use std::collections::HashMap;

use serde_json::Value;

use crate::model::interactions::ApplicationCommandPermissionType;
use crate::utils;

/// A builder for creating several [`ApplicationCommandPermission`].
///
/// [`ApplicationCommandPermission`]: crate::model::interactions::ApplicationCommandPermission
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandsPermissions(pub Vec<Value>);

impl CreateApplicationCommandsPermissions {
    /// Creates a new application command.
    pub fn create_application_command<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(
            &mut CreateApplicationCommandPermissions,
        ) -> &mut CreateApplicationCommandPermissions,
    {
        let mut data = CreateApplicationCommandPermissions::default();
        f(&mut data);

        self.add_application_command(data);

        self
    }

    /// Adds a new interaction.
    pub fn add_application_command(
        &mut self,
        application_command: CreateApplicationCommandPermissions,
    ) -> &mut Self {
        let new_data = Value::Object(utils::hashmap_to_json_map(application_command.0));

        self.0.push(new_data);

        self
    }

    /// Sets all the interactions.
    pub fn set_application_commands(
        &mut self,
        application_commands: Vec<CreateApplicationCommandPermissions>,
    ) -> &mut Self {
        let new_application_commands = application_commands
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        for application_command in new_application_commands {
            self.0.push(application_command);
        }

        self
    }
}
/// A builder for creating an [`ApplicationCommandPermission`].
///
/// [`ApplicationCommandPermission`]: crate::model::interactions::ApplicationCommandPermission
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissions(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissions {
    /// The [`CommandId`] these permissions belong to.
    ///
    /// [`CommandId`]: crate::model::id::CommandId
    pub fn id(&mut self, application_command_id: u64) -> &mut Self {
        self.0.insert("id", Value::String(application_command_id.to_string()));
        self
    }

    /// Creates a new permission for the interaction.
    pub fn create_permission<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(
            &mut CreateApplicationCommandPermissionData,
        ) -> &mut CreateApplicationCommandPermissionData,
    {
        let mut data = CreateApplicationCommandPermissionData::default();
        f(&mut data);

        self.add_permission(data);

        self
    }

    /// Adds a permission for the interaction.
    pub fn add_permission(
        &mut self,
        permission: CreateApplicationCommandPermissionData,
    ) -> &mut Self {
        let new_data = utils::hashmap_to_json_map(permission.0);
        let permissions = self.0.entry("permissions").or_insert_with(|| Value::Array(Vec::new()));

        let permissions_array = permissions.as_array_mut().expect("Must be an array");

        permissions_array.push(Value::Object(new_data));

        self
    }

    /// Sets all the permissions for the interaction.
    pub fn set_permissions(
        &mut self,
        permissions: Vec<CreateApplicationCommandPermissionData>,
    ) -> &mut Self {
        let new_permissions = permissions
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        self.0.insert("permissions", Value::Array(new_permissions));

        self
    }
}

/// A builder for creating several [`ApplicationCommandPermissionData`].
///
/// [`ApplicationCommandPermissionData`]: crate::model::interactions::ApplicationCommandPermissionData
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissionsData(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissionsData {
    /// Creates a permission for the interaction.
    pub fn create_permission<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(
            &mut CreateApplicationCommandPermissionData,
        ) -> &mut CreateApplicationCommandPermissionData,
    {
        let mut data = CreateApplicationCommandPermissionData::default();
        f(&mut data);

        self.add_permission(data);

        self
    }

    /// Adds a permission.
    pub fn add_permission(
        &mut self,
        permission: CreateApplicationCommandPermissionData,
    ) -> &mut Self {
        let new_data = utils::hashmap_to_json_map(permission.0);
        let permissions = self.0.entry("permissions").or_insert_with(|| Value::Array(Vec::new()));

        let permissions_array = permissions.as_array_mut().expect("Must be an array");

        permissions_array.push(Value::Object(new_data));

        self
    }

    /// Sets all the permissions for the interaction.
    pub fn set_permissions(
        &mut self,
        permissions: Vec<CreateApplicationCommandPermissionData>,
    ) -> &mut Self {
        let new_permissions = permissions
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        self.0.insert("permissions", Value::Array(new_permissions));

        self
    }
}

/// A builder for creating an [`ApplicationCommandPermissionData`].
///
/// All fields are required.
///
/// [`ApplicationCommandPermissionData`]: crate::model::interactions::ApplicationCommandPermissionData
/// [`kind`]: Self::kind
#[derive(Clone, Debug, Default)]
pub struct CreateApplicationCommandPermissionData(pub HashMap<&'static str, Value>);

impl CreateApplicationCommandPermissionData {
    /// Sets the `ApplicationCommandPermissionType` for the [`ApplicationCommandPermissionData`].
    ///
    /// [`ApplicationCommandPermissionData`]: crate::model::interaction::ApplicationCommandPermissionData
    pub fn kind(&mut self, kind: ApplicationCommandPermissionType) -> &mut Self {
        self.0.insert("type", Value::Number(serde_json::Number::from(kind as u8)));
        self
    }

    /// Sets the CommandPermissionId for the [`ApplicationCommandPermissionData`].
    ///
    /// [`ApplicationCommandPermissionData`]: crate::model::interaction::ApplicationCommandPermissionData
    pub fn id(&mut self, id: u64) -> &mut Self {
        self.0.insert("id", Value::String(id.to_string()));
        self
    }

    /// Sets the permission.
    pub fn permission(&mut self, permission: bool) -> &mut Self {
        self.0.insert("permission", Value::Bool(permission));
        self
    }
}
<|endoftext|>