<commit_before>use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;
use std::borrow::Cow;

use zip::read::{ZipFile, ZipArchive};
use zip::result::ZipError;
use quick_xml::reader::Reader;
use quick_xml::events::Event;
use quick_xml::events::attributes::{Attribute, Attributes};

use {DataType, ExcelReader, Range, Cell};
use vba::VbaProject;
use errors::*;

/// A struct representing xml zipped excel file
/// Xlsx, Xlsm, Xlam
pub struct Xlsx {
    zip: ZipArchive<File>,
}

impl Xlsx {
    fn xml_reader<'a>(&'a mut self,
                      path: &str)
                      -> Option<Result<Reader<BufReader<ZipFile<'a>>>>> {
        match self.zip.by_name(path) {
            Ok(f) => {
                let mut r = Reader::from_reader(BufReader::new(f));
                r.check_end_names(false)
                    .trim_text(false)
                    .check_comments(false)
                    .expand_empty_elements(true);
                Some(Ok(r))
            }
            Err(ZipError::FileNotFound) => None,
            Err(e) => return Some(Err(e.into())),
        }
    }
}

impl ExcelReader for Xlsx {
    fn new(f: File) -> Result<Self> {
        Ok(Xlsx { zip: ZipArchive::new(f)? })
    }

    fn has_vba(&mut self) -> bool {
        self.zip.by_name("xl/vbaProject.bin").is_ok()
    }

    fn vba_project(&mut self) -> Result<Cow<VbaProject>> {
        let mut f = self.zip.by_name("xl/vbaProject.bin")?;
        let len = f.size() as usize;
        VbaProject::new(&mut f, len).map(|v| Cow::Owned(v))
    }

    fn read_shared_strings(&mut self) -> Result<Vec<String>> {
        let mut xml = match self.xml_reader("xl/sharedStrings.xml") {
            None => return Ok(Vec::new()),
            Some(x) => x?,
        };
        let mut strings = Vec::new();
        let mut buf = Vec::new();
        let mut rich_buffer: Option<String> = None;
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"r" => {
                    if rich_buffer.is_none() {
                        // use a buffer since richtext has multiples <r> and <t> for the same cell
                        rich_buffer = Some(String::new());
                    }
                }
                Ok(Event::End(ref e)) if e.name() == b"si" => {
                    if let Some(s) = rich_buffer {
                        strings.push(s);
                        rich_buffer = None;
                    }
                }
                Ok(Event::Start(ref e)) if e.name() == b"t" => {
                    let value = xml.read_text(b"t", &mut Vec::new())?;
                    if let Some(ref mut s) = rich_buffer {
                        s.push_str(&value);
                    } else {
                        strings.push(value);
                    }
                }
                Ok(Event::Eof) => break,
                Err(e) => return Err(e.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(strings)
    }

    fn read_sheets_names(&mut self,
                         relationships: &HashMap<Vec<u8>, String>)
                         -> Result<Vec<(String, String)>> {
        let mut xml = match self.xml_reader("xl/workbook.xml") {
            None => return Ok(Vec::new()),
            Some(x) => x?,
        };
        let mut sheets = Vec::new();
        let mut buf = Vec::new();
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"sheet" => {
                    let mut name = String::new();
                    let mut path = String::new();
                    for a in e.attributes() {
                        let a = a?;
                        match a {
                            Attribute { key: b"name", .. } => {
                                name = a.unescape_and_decode_value(&xml)?;
                            },
                            Attribute { key: b"r:id", value: v } => {
                                let r = &relationships[&*v][..];
                                // target may have pre-prended "/xl/" or "xl/" path;
                                // strip if present
                                path = if r.starts_with("/xl/") {
                                    r[1..].to_string()
                                } else if r.starts_with("xl/") {
                                    r.to_string()
                                } else {
                                    format!("xl/{}", r)
                                };
                            }
                            _ => (),
                        }
                    }
                    sheets.push((name, path));
                }
                Ok(Event::Eof) => break,
                Err(e) => return Err(e.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(sheets)
    }

    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>> {
        let mut xml = match self.xml_reader("xl/_rels/workbook.xml.rels") {
            None => return Err("Cannot find relationships file".into()),
            Some(x) => x?,
        };
        let mut relationships = HashMap::new();
        let mut buf = Vec::new();
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"Relationship" => {
                    let mut id = Vec::new();
                    let mut target = String::new();
                    for a in e.attributes() {
                        match a? {
                            Attribute { key: b"Id", value: v } => id.extend_from_slice(v),
                            Attribute { key: b"Target", value: v } => target = xml.decode(v).into_owned(),
                            _ => (),
                        }
                    }
                    relationships.insert(id, target);
                }
                Ok(Event::Eof) => break,
                Err(e) => return Err(e.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(relationships)
    }

    fn read_worksheet_range(&mut self, path: &str, strings: &[String]) -> Result<Range> {
        let mut xml = match self.xml_reader(path) {
            None => return Err(format!("Cannot find {} path", path).into()),
            Some(x) => x?,
        };
        let mut cells = Vec::new();
        let mut buf = Vec::new();
        'xml: loop {
            match xml.read_event(&mut buf) {
                Err(e) => return Err(e.into()),
                Ok(Event::Start(ref e)) => {
                    match e.name() {
                        b"dimension" => {
                            for a in e.attributes() {
                                if let Attribute { key:b"ref", value: rdim } = a? {
                                    let (start, end) = get_dimension(rdim)?;
                                    cells.reserve(((end.0 - start.0 + 1) * (end.1 - start.1 + 1)) as
                                                 usize);
                                    continue 'xml;
                                }
                            }
                            return Err(format!("Expecting dimension, got {:?}", e).into());
                        }
                        b"sheetData" => read_sheet_data(&mut xml, strings, &mut cells)?,
                        _ => (),
                    }
                }
                Ok(Event::Eof) => break,
                _ => (),
            }
            buf.clear();
        }
        Ok(Range::from_sparse(cells))
    }
}

/// read sheetData node
fn read_sheet_data(xml: &mut Reader<BufReader<ZipFile>>,
                   strings: &[String],
                   cells: &mut Vec<Cell>)
                   -> Result<()> {
    /// read the contents of an <is> cell
    fn read_inline_str(xml: &mut Reader<BufReader<ZipFile>>, buf: &mut Vec<u8>) -> Result<DataType> {
        loop {
            match xml.read_event(buf) {
                Err(e) => return Err(e.into()),
                Ok(Event::Eof) => break,
                Ok(Event::Start(ref t)) if t.name() == b"t" => {
                    return Ok(DataType::String(xml.read_text(b"t", &mut Vec::new())?));
                }
                _ => {}
            }
            buf.clear();
        }
        Err("unable to read inlineStr".into())
    }

    /// read the contents of a <v> cell
    fn read_value<'a>(xml: &mut Reader<BufReader<ZipFile>>, strings: &[String],
                      atts: Attributes<'a>, buf: &mut Vec<u8>)
                  -> Result<DataType>
    {
        let v = xml.read_text(b"v", buf)?;
        match get_attribute(atts, b"t")? {
            Some(b"s") => {
                // shared string
                let idx: usize = v.parse()?;
                Ok(DataType::String(strings[idx].clone()))
            }
            Some(b"b") => {
                // boolean
                Ok(DataType::Bool(v != "0"))
            }
            Some(b"e") => {
                // error
                Ok(DataType::Error(v.parse()?))
            }
            Some(b"d") => {
                // date
                // TODO: create a DataType::Date
                // currently just return as string (ISO 8601)
                Ok(DataType::String(v))
            }
            Some(b"str") => {
                // see http://officeopenxml.com/SScontentOverview.php
                // str - refers to formula cells
                // * <c .. t='v' .. > indicates calculated value (this case)
                // * <c .. t='f' .. > to the formula string (ignored case
                // TODO: Fully support a DataType::Formula representing both Formula string &
                // last calculated value?
                //
                // NB: the result of a formula may not be a numeric value (=A3&" "&A4).
                // We do try an initial parse as Float for utility, but fall back to a string
                // representation if that fails
                v.parse()
                    .map(DataType::Float)
                    .map_err(Error::from)
                    .or_else::<Error, _>(|_| Ok(DataType::String(v)))
            }
            Some(b"n") => {
                // n - number
                v.parse().map(DataType::Float).map_err(Error::from)
            }
            None => {
                // If type is not known, we try to parse as Float for utility, but fall back to
                // String if this fails.
                v.parse()
                    .map(DataType::Float)
                    .map_err(Error::from)
                    .or_else::<Error, _>(|_| Ok(DataType::String(v)))
            }
            Some(b"is") => {
                // this case should be handled in outer loop over cell elements, in which
                // case read_inline_str is called instead. Case included here for completeness.
                return Err("called read_value on a cell of type inlineStr".into());
            }
            Some(t) => return Err(format!("unknown cell 't' attribute={:?}", t).into()),
        }
    }

    /// search through an Element's attributes for the named one
    fn get_attribute<'a>(atts: Attributes<'a>, n: &'a [u8]) -> Result<Option<&'a [u8]>> {
        for a in atts {
            match a {
                Ok(Attribute { key: k, value: v }) if k == n => return Ok(Some(v)),
                Err(qe) => return Err(qe.into()),
                _ => {} // ignore other attributes
            }
        }
        Ok(None)
    }

    let mut buf = Vec::new();

    /// main content of read_sheet_data
    loop {
        match xml.read_event(&mut buf) {
            Err(e) => return Err(e.into()),
            Ok(Event::Start(ref c_element)) if c_element.name() == b"c" => {
                let pos = get_attribute(c_element.attributes(), b"r")
                    .and_then(|o| o.ok_or_else(|| "Cell missing 'r' attribute tag".into()))
                    .and_then(get_row_column)?;

                loop {
                    let mut buf = Vec::new();
                    match xml.read_event(&mut buf) {
                        Err(e) => return Err(e.into()),
                        Ok(Event::Start(ref e)) => {
                            debug!("e: {:?}", e);
                            match e.name() {
                                b"is" => {
                                    cells.push(Cell::new(pos, read_inline_str(xml, &mut Vec::new())?));
                                    break;
                                }
                                b"v" => {
                                    cells.push(Cell::new(pos, read_value(xml,
                                                                         strings,
                                                                         c_element.attributes(),
                                                                         &mut Vec::new())?));
                                    break;
                                }
                                b"f" => {} // ignore f nodes
                                n => {
                                    return Err(format!("not a 'v', 'f', or 'is' node: {:?}", n).into())
                                }
                            }
                        }
                        Ok(Event::End(ref e)) if e.name() == b"c" => {
                            debug!("</c>");
                            break;
                        }
                        Ok(Event::Eof) => return Err("End of xml".into()),
                        o => debug!("ignored Event: {:?}", o),
                    }
                }
            }
            Ok(Event::End(ref e)) if e.name() == b"sheetData" => return Ok(()),
            Ok(Event::Eof) => break,
            _ => (),
        }
        buf.clear();
    }
    Err("Could not find </sheetData>".into())
}

/// converts a text representation (e.g. "A6:G67") of a dimension into integers
/// - top left (row, column),
/// - bottom right (row, column)
fn get_dimension(dimension: &[u8]) -> Result<((u32, u32), (u32, u32))> {
    let parts: Vec<_> = dimension.split(|c| *c == b':')
        .map(|s| get_row_column(s))
        .collect::<Result<Vec<_>>>()?;

    match parts.len() {
        0 => Err("dimension cannot be empty".into()),
        1 => Ok((parts[0], parts[0])),
        2 => Ok((parts[0], parts[1])),
        len => Err(format!("range dimension has 0 or 1 ':', got {}", len).into()),
    }
}

/// converts a text range name into its position (row, column) (0 based index)
fn get_row_column(range: &[u8]) -> Result<(u32, u32)> {
    let (mut row, mut col) = (0, 0);
    let mut pow = 1;
    let mut readrow = true;
    for c in range.iter().rev() {
        match *c {
            c @ b'0'...b'9' => {
                if readrow {
                    row += ((c - b'0') as u32) * pow;
                    pow *= 10;
                } else {
                    return Err(format!("Numeric character are only allowed \
                        at the end of the range: {:x}",
                                       c)
                        .into());
                }
            }
            c @ b'A'...b'Z' => {
                if readrow {
                    pow = 1;
                    readrow = false;
                }
                col += ((c - b'A') as u32 + 1) * pow;
                pow *= 26;
            }
            c @ b'a'...b'z' => {
                if readrow {
                    pow = 1;
                    readrow = false;
                }
                col += ((c - b'a') as u32 + 1) * pow;
                pow *= 26;
            }
            _ => return Err(format!("Expecting alphanumeric character, got {:x}", c).into()),
        }
    }
    Ok((row - 1, col - 1))
}

#[test]
fn test_dimensions() {
    assert_eq!(get_row_column(b"A1").unwrap(), (0, 0));
    assert_eq!(get_row_column(b"C107").unwrap(), (106, 2));
    assert_eq!(get_dimension(b"C2:D35").unwrap(), ((1, 2), (34, 3)));
}
<commit_msg>Support richtext in inlineStr (#72)<commit_after>use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;
use std::borrow::Cow;

use zip::read::{ZipFile, ZipArchive};
use zip::result::ZipError;
use quick_xml::reader::Reader;
use quick_xml::events::Event;
use quick_xml::events::attributes::{Attribute, Attributes};

use {DataType, ExcelReader, Range, Cell};
use vba::VbaProject;
use errors::*;

/// A struct representing xml zipped excel file
/// Xlsx, Xlsm, Xlam
pub struct Xlsx {
    zip: ZipArchive<File>,
}

impl Xlsx {
    fn xml_reader<'a>(&'a mut self, path: &str) -> Option<Result<Reader<BufReader<ZipFile<'a>>>>> {
        match self.zip.by_name(path) {
            Ok(f) => {
                let mut r = Reader::from_reader(BufReader::new(f));
                r.check_end_names(false)
                    .trim_text(false)
                    .check_comments(false)
                    .expand_empty_elements(true);
                Some(Ok(r))
            }
            Err(ZipError::FileNotFound) => None,
            Err(e) => return Some(Err(e.into())),
        }
    }
}

impl ExcelReader for Xlsx {
    fn new(f: File) -> Result<Self> {
        Ok(Xlsx { zip: ZipArchive::new(f)? })
    }

    fn has_vba(&mut self) -> bool {
        self.zip.by_name("xl/vbaProject.bin").is_ok()
    }

    fn vba_project(&mut self) -> Result<Cow<VbaProject>> {
        let mut f = self.zip.by_name("xl/vbaProject.bin")?;
        let len = f.size() as usize;
        VbaProject::new(&mut f, len).map(|v| Cow::Owned(v))
    }

    fn read_shared_strings(&mut self) -> Result<Vec<String>> {
        let mut xml = match self.xml_reader("xl/sharedStrings.xml") {
            None => return Ok(Vec::new()),
            Some(x) => x?,
        };
        let mut strings = Vec::new();
        let mut buf = Vec::new();
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"si" => {
                    if let Some(s) = read_string(&mut xml, b"si")? {
                        strings.push(s);
                    }
                }
                Ok(Event::End(ref e)) if e.name() == b"sst" => break,
                _ => (),
            }
            buf.clear();
        }
        Ok(strings)
    }

    fn read_sheets_names(&mut self,
                         relationships: &HashMap<Vec<u8>, String>)
                         -> Result<Vec<(String, String)>> {
        let mut xml = match self.xml_reader("xl/workbook.xml") {
            None => return Ok(Vec::new()),
            Some(x) => x?,
        };
        let mut sheets = Vec::new();
        let mut buf = Vec::new();
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"sheet" => {
                    let mut name = String::new();
                    let mut path = String::new();
                    for a in e.attributes() {
                        let a = a?;
                        match a {
                            Attribute { key: b"name", .. } => {
                                name = a.unescape_and_decode_value(&xml)?;
                            }
                            Attribute { key: b"r:id", value: v } => {
                                let r = &relationships[&*v][..];
                                // target may have pre-prended "/xl/" or "xl/" path;
                                // strip if present
                                path = if r.starts_with("/xl/") {
                                    r[1..].to_string()
                                } else if r.starts_with("xl/") {
                                    r.to_string()
                                } else {
                                    format!("xl/{}", r)
                                };
                            }
                            _ => (),
                        }
                    }
                    sheets.push((name, path));
                }
                Ok(Event::Eof) => break,
                Err(e) => return Err(e.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(sheets)
    }

    fn read_relationships(&mut self) -> Result<HashMap<Vec<u8>, String>> {
        let mut xml = match self.xml_reader("xl/_rels/workbook.xml.rels") {
            None => return Err("Cannot find relationships file".into()),
            Some(x) => x?,
        };
        let mut relationships = HashMap::new();
        let mut buf = Vec::new();
        loop {
            match xml.read_event(&mut buf) {
                Ok(Event::Start(ref e)) if e.name() == b"Relationship" => {
                    let mut id = Vec::new();
                    let mut target = String::new();
                    for a in e.attributes() {
                        match a? {
                            Attribute { key: b"Id", value: v } => id.extend_from_slice(v),
                            Attribute { key: b"Target", value: v } => {
                                target = xml.decode(v).into_owned()
                            }
                            _ => (),
                        }
                    }
                    relationships.insert(id, target);
                }
                Ok(Event::Eof) => break,
                Err(e) => return Err(e.into()),
                _ => (),
            }
            buf.clear();
        }
        Ok(relationships)
    }

    fn read_worksheet_range(&mut self, path: &str, strings: &[String]) -> Result<Range> {
        let mut xml = match self.xml_reader(path) {
            None => return Err(format!("Cannot find {} path", path).into()),
            Some(x) => x?,
        };
        let mut cells = Vec::new();
        let mut buf = Vec::new();
        'xml: loop {
            match xml.read_event(&mut buf) {
                Err(e) => return Err(e.into()),
                Ok(Event::Start(ref e)) => {
                    match e.name() {
                        b"dimension" => {
                            for a in e.attributes() {
                                if let Attribute { key: b"ref", value: rdim } = a? {
                                    let (start, end) = get_dimension(rdim)?;
                                    cells.reserve(((end.0 - start.0 + 1) * (end.1 - start.1 + 1)) as
                                                 usize);
                                    continue 'xml;
                                }
                            }
                            return Err(format!("Expecting dimension, got {:?}", e).into());
                        }
                        b"sheetData" => read_sheet_data(&mut xml, strings, &mut cells)?,
                        _ => (),
                    }
                }
                Ok(Event::Eof) => break,
                _ => (),
            }
            buf.clear();
        }
        Ok(Range::from_sparse(cells))
    }
}

/// read sheetData node
fn read_sheet_data(xml: &mut Reader<BufReader<ZipFile>>,
                   strings: &[String],
                   cells: &mut Vec<Cell>)
                   -> Result<()> {
    /// read the contents of a <v> cell
    fn read_value<'a>(xml: &mut Reader<BufReader<ZipFile>>,
                      strings: &[String],
                      atts: Attributes<'a>,
                      buf: &mut Vec<u8>)
                      -> Result<DataType> {
        let v = xml.read_text(b"v", buf)?;
        match get_attribute(atts, b"t")? {
            Some(b"s") => {
                // shared string
                let idx: usize = v.parse()?;
                Ok(DataType::String(strings[idx].clone()))
            }
            Some(b"b") => {
                // boolean
                Ok(DataType::Bool(v != "0"))
            }
            Some(b"e") => {
                // error
                Ok(DataType::Error(v.parse()?))
            }
            Some(b"d") => {
                // date
                // TODO: create a DataType::Date
                // currently just return as string (ISO 8601)
                Ok(DataType::String(v))
            }
            Some(b"str") => {
                // see http://officeopenxml.com/SScontentOverview.php
                // str - refers to formula cells
                // * <c .. t='v' .. > indicates calculated value (this case)
                // * <c .. t='f' .. > to the formula string (ignored case
                // TODO: Fully support a DataType::Formula representing both Formula string &
                // last calculated value?
                //
                // NB: the result of a formula may not be a numeric value (=A3&" "&A4).
                // We do try an initial parse as Float for utility, but fall back to a string
                // representation if that fails
                v.parse()
                    .map(DataType::Float)
                    .map_err(Error::from)
                    .or_else::<Error, _>(|_| Ok(DataType::String(v)))
            }
            Some(b"n") => {
                // n - number
                v.parse().map(DataType::Float).map_err(Error::from)
            }
            None => {
                // If type is not known, we try to parse as Float for utility, but fall back to
                // String if this fails.
                v.parse()
                    .map(DataType::Float)
                    .map_err(Error::from)
                    .or_else::<Error, _>(|_| Ok(DataType::String(v)))
            }
            Some(b"is") => {
                // this case should be handled in outer loop over cell elements, in which
                // case read_inline_str is called instead. Case included here for completeness.
                return Err("called read_value on a cell of type inlineStr".into());
            }
            Some(t) => return Err(format!("unknown cell 't' attribute={:?}", t).into()),
        }
    }

    /// search through an Element's attributes for the named one
    fn get_attribute<'a>(atts: Attributes<'a>, n: &'a [u8]) -> Result<Option<&'a [u8]>> {
        for a in atts {
            match a {
                Ok(Attribute { key: k, value: v }) if k == n => return Ok(Some(v)),
                Err(qe) => return Err(qe.into()),
                _ => {} // ignore other attributes
            }
        }
        Ok(None)
    }

    let mut buf = Vec::new();
    /// main content of read_sheet_data
    loop {
        match xml.read_event(&mut buf) {
            Err(e) => return Err(e.into()),
            Ok(Event::Start(ref c_element)) if c_element.name() == b"c" => {
                let pos = get_attribute(c_element.attributes(), b"r")
                    .and_then(|o| o.ok_or_else(|| "Cell missing 'r' attribute tag".into()))
                    .and_then(get_row_column)?;

                loop {
                    let mut buf = Vec::new();
                    match xml.read_event(&mut buf) {
                        Err(e) => return Err(e.into()),
                        Ok(Event::Start(ref e)) => {
                            debug!("e: {:?}", e);
                            match e.name() {
                                b"is" => {
                                    // inlineStr
                                    if let Some(s) = read_string(xml, b"is")? {
                                        cells.push(Cell::new(pos, DataType::String(s)));
                                    }
                                    break;
                                }
                                b"v" => {
                                    // value
                                    cells.push(Cell::new(pos,
                                                         read_value(xml,
                                                                    strings,
                                                                    c_element.attributes(),
                                                                    &mut Vec::new())?));
                                    break;
                                }
                                b"f" => {} // ignore f nodes
                                n => {
                                    return Err(format!("not a 'v', 'f', or 'is' node: {:?}", n)
                                        .into())
                                }
                            }
                        }
                        Ok(Event::End(ref e)) if e.name() == b"c" => {
                            debug!("</c>");
                            break;
                        }
                        Ok(Event::Eof) => return Err("End of xml".into()),
                        o => debug!("ignored Event: {:?}", o),
                    }
                }
            }
            Ok(Event::End(ref e)) if e.name() == b"sheetData" => return Ok(()),
            Ok(Event::Eof) => break,
            _ => (),
        }
        buf.clear();
    }
    Err("Could not find </sheetData>".into())
}

/// converts a text representation (e.g. "A6:G67") of a dimension into integers
/// - top left (row, column),
/// - bottom right (row, column)
fn get_dimension(dimension: &[u8]) -> Result<((u32, u32), (u32, u32))> {
    let parts: Vec<_> = dimension.split(|c| *c == b':')
        .map(|s| get_row_column(s))
        .collect::<Result<Vec<_>>>()?;

    match parts.len() {
        0 => Err("dimension cannot be empty".into()),
        1 => Ok((parts[0], parts[0])),
        2 => Ok((parts[0], parts[1])),
        len => Err(format!("range dimension has 0 or 1 ':', got {}", len).into()),
    }
}

/// converts a text range name into its position (row, column) (0 based index)
fn get_row_column(range: &[u8]) -> Result<(u32, u32)> {
    let (mut row, mut col) = (0, 0);
    let mut pow = 1;
    let mut readrow = true;
    for c in range.iter().rev() {
        match *c {
            c @ b'0'...b'9' => {
                if readrow {
                    row += ((c - b'0') as u32) * pow;
                    pow *= 10;
                } else {
                    return Err(format!("Numeric character are only allowed \
                        at the end of the range: {:x}",
                                       c)
                        .into());
                }
            }
            c @ b'A'...b'Z' => {
                if readrow {
                    pow = 1;
                    readrow = false;
                }
                col += ((c - b'A') as u32 + 1) * pow;
                pow *= 26;
            }
            c @ b'a'...b'z' => {
                if readrow {
                    pow = 1;
                    readrow = false;
                }
                col += ((c - b'a') as u32 + 1) * pow;
                pow *= 26;
            }
            _ => return Err(format!("Expecting alphanumeric character, got {:x}", c).into()),
        }
    }
    Ok((row - 1, col - 1))
}

/// attempts to read either a simple or richtext string
fn read_string(xml: &mut Reader<BufReader<ZipFile>>, closing: &[u8]) -> Result<Option<String>> {
    let mut buf = Vec::new();
    let mut rich_buffer: Option<String> = None;
    loop {
        match xml.read_event(&mut buf) {
            Ok(Event::Start(ref e)) if e.name() == b"r" => {
                if rich_buffer.is_none() {
                    // use a buffer since richtext has multiples <r> and <t> for the same cell
                    rich_buffer = Some(String::new());
                }
            }
            Ok(Event::End(ref e)) if e.name() == closing => {
                return Ok(rich_buffer);
            }
            Ok(Event::Start(ref e)) if e.name() == b"t" => {
                let value = xml.read_text(b"t", &mut Vec::new())?;
                if let Some(ref mut s) = rich_buffer {
                    s.push_str(&value);
                } else {
                    // consume any remaining events up to expected closing tag
                    xml.read_to_end(closing, &mut Vec::new())?;
                    return Ok(Some(value));
                }
            }
            Ok(Event::Eof) => return Err("unexpected end of xml".into()),
            Err(e) => return Err(e.into()),
            _ => (),
        }
        buf.clear();
    }
}

#[test]
fn test_dimensions() {
    assert_eq!(get_row_column(b"A1").unwrap(), (0, 0));
    assert_eq!(get_row_column(b"C107").unwrap(), (106, 2));
    assert_eq!(get_dimension(b"C2:D35").unwrap(), ((1, 2), (34, 3)));
}
<|endoftext|>


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

use crate::codec::*;
pub use codec::RedisMode;

use crate::config::Action;

use bytes::BytesMut;
use logger::*;

pub struct Redis {
    codec: codec::Redis,
    common: Common,
}

impl Redis {
    pub fn new(mode: RedisMode) -> Self {
        Self {
            codec: codec::Redis::new(mode),
            common: Common::new(),
        }
    }
}

impl Codec for Redis {
    fn common(&self) -> &Common {
        &self.common
    }

    fn common_mut(&mut self) -> &mut Common {
        &mut self.common
    }

    fn decode(&self, buf: &[u8]) -> Result<Response, Error> {
        self.codec.decode(buf)
    }

    fn encode(&mut self, buf: &mut BytesMut, rng: &mut ThreadRng) {
        let command = self.generate(rng);
        match command.action() {
            Action::Delete => {
                let key = command.key().unwrap();
                let keys = vec![key];
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/delete");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.delete(buf, &keys);
            }
            Action::Get => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/get");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.get(buf, key);
            }
            Action::Llen => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/len");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.llen(buf, key);
            }
            Action::Lpush => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.lpush(buf, key, &values);
            }
            Action::Lpushx => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.lpushx(buf, key, &values);
            }
            Action::Lrange => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/range");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                // TODO: proper handling of start and stop
                self.codec.lrange(buf, key, 0, command.count.unwrap_or(1) as isize);
            }
            Action::Ltrim => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/trim");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                // TODO: proper handling of start and stop
                self.codec.lrange(buf, key, 0, command.count.unwrap_or(1) as isize);
            }
            Action::Rpush => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.rpush(buf, key, &values);
            }
            Action::Rpushx => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.rpushx(buf, key, &values);
            }
            Action::Set => {
                let key = command.key().unwrap();
                let value = command.value().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/set");
                    recorder.distribution("keys/size", key.len() as u64);
                    recorder.distribution("values/size", value.len() as u64);
                }
                self.codec.set(buf, key, value, command.ttl());
            }
            action => {
                fatal!("Action: {:?} unsupported for Redis", action);
            }
        }
    }
}
<commit_msg>rpc-perf: bugfix redis ltrim<commit_after>//  Copyright 2019 Twitter, Inc
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

use crate::codec::*;
pub use codec::RedisMode;

use crate::config::Action;

use bytes::BytesMut;
use logger::*;

pub struct Redis {
    codec: codec::Redis,
    common: Common,
}

impl Redis {
    pub fn new(mode: RedisMode) -> Self {
        Self {
            codec: codec::Redis::new(mode),
            common: Common::new(),
        }
    }
}

impl Codec for Redis {
    fn common(&self) -> &Common {
        &self.common
    }

    fn common_mut(&mut self) -> &mut Common {
        &mut self.common
    }

    fn decode(&self, buf: &[u8]) -> Result<Response, Error> {
        self.codec.decode(buf)
    }

    fn encode(&mut self, buf: &mut BytesMut, rng: &mut ThreadRng) {
        let command = self.generate(rng);
        match command.action() {
            Action::Delete => {
                let key = command.key().unwrap();
                let keys = vec![key];
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/delete");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.delete(buf, &keys);
            }
            Action::Get => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/get");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.get(buf, key);
            }
            Action::Llen => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/len");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                self.codec.llen(buf, key);
            }
            Action::Lpush => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.lpush(buf, key, &values);
            }
            Action::Lpushx => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.lpushx(buf, key, &values);
            }
            Action::Lrange => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/range");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                // TODO: proper handling of start and stop
                self.codec.lrange(buf, key, 0, command.count.unwrap_or(1) as isize);
            }
            Action::Ltrim => {
                let key = command.key().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/trim");
                    recorder.distribution("keys/size", key.len() as u64);
                }
                // TODO: proper handling of start and stop
                self.codec.ltrim(buf, key, 0, command.count.unwrap_or(1) as isize);
            }
            Action::Rpush => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.rpush(buf, key, &values);
            }
            Action::Rpushx => {
                let key = command.key().unwrap();
                let values = command.values().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/push");
                    recorder.distribution("keys/size", key.len() as u64);
                    let len: usize = values.iter().map(|v| v.len()).sum();
                    recorder.distribution("values/size", len as u64);
                }
                self.codec.rpushx(buf, key, &values);
            }
            Action::Set => {
                let key = command.key().unwrap();
                let value = command.value().unwrap();
                if let Some(recorder) = self.common.recorder() {
                    recorder.increment("commands/set");
                    recorder.distribution("keys/size", key.len() as u64);
                    recorder.distribution("values/size", value.len() as u64);
                }
                self.codec.set(buf, key, value, command.ttl());
            }
            action => {
                fatal!("Action: {:?} unsupported for Redis", action);
            }
        }
    }
}
<|endoftext|>


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

#[derive(Debug, Deserialize)]
pub struct Service {
    pub documentation: Option<String>,
    pub examples: Option<BTreeMap<String, String>>,
    pub metadata: Metadata,
    pub operations: BTreeMap<String, Operation>,
    pub shapes: BTreeMap<String, Shape>,
    pub version: String,
}

impl Service {
    pub fn client_type_name(&self) -> String {
        format!("{}Client", self.service_type_name())
    }

    pub fn service_type_name(&self) -> &str {
        match &self.metadata.service_full_name[..] {
            "AWS Certificate Manager" => "Acm",
            "AWS CloudFormation" => "CloudFormation",
            "AWS CloudTrail" => "CloudTrail",
            "AWS CodeCommit" => "CodeCommit",
            "AWS CodeDeploy" => "CodeDeploy",
            "AWS CodePipeline" => "CodePipeline",
            "AWS Config" => "ConfigService",
            "AWS Data Pipeline" => "DataPipeline",
            "AWS Device Farm" => "DeviceFarm",
            "AWS Direct Connect" => "DirectConnect",
            "AWS Directory Service" => "DirectoryService",
            "AWS Elastic Beanstalk" => "ElasticBeanstalk",
            "AWS Identity and Access Management" => "Iam",
            "AWS Import/Export" => "ImportExport",
            "AWS IoT Data Plane" => "IotDataPlane",
            "AWS IoT" => "Iot",
            "AWS Key Management Service" => "Kms",
            "AWS Lambda" => "Lambda",
            "AWS Marketplace Commerce Analytics" => "MarketplaceCommerceAnalytics",
            "AWS OpsWorks" => "OpsWorks",
            "AWS Security Token Service" => "Sts",
            "AWS Storage Gateway" => "StorageGateway",
            "AWS Support" => "Support",
            "AWS WAF" => "Waf",
            "Amazon API Gateway" => "ApiGateway",
            "Amazon CloudFront" => "CloudFront",
            "Amazon CloudHSM" => "CloudHsm",
            "Amazon CloudSearch Domain" => "CloudSearchDomain",
            "Amazon CloudSearch" => "CloudSearch",
            "Amazon CloudWatch Events" => "CloudWatchEvents",
            "Amazon CloudWatch Logs" => "CloudWatchLogs",
            "Amazon CloudWatch" => "CloudWatch",
            "Amazon Cognito Identity" => "CognitoIdentity",
            "Amazon Cognito Sync" => "CognitoSync",
            "Amazon DynamoDB Streams" => "DynamoDbStreams",
            "Amazon DynamoDB" => "DynamoDb",
            "Amazon EC2 Container Registry" => "Ecr",
            "Amazon EC2 Container Service" => "Ecs",
            "Amazon ElastiCache" => "ElastiCache",
            "Amazon Elastic Compute Cloud" => "Ec2",
            "Amazon Elastic File System" => "Efs",
            "Amazon Elastic MapReduce" => "Emr",
            "Amazon Elastic Transcoder" => "Ets",
            "Amazon Elasticsearch Service" => "ElasticsearchService",
            "Amazon GameLift" => "GameLift",
            "Amazon Glacier" => "Glacier",
            "Amazon Inspector" => "Inspector",
            "Amazon Kinesis Firehose" => "KinesisFirehose",
            "Amazon Kinesis" => "Kinesis",
            "Amazon Machine Learning" => "MachineLearning",
            "Amazon Redshift" => "Redshift",
            "Amazon Relational Database Service" => "Rds",
            "Amazon Route 53 Domains" => "Route53Domains",
            "Amazon Route 53" => "Route53",
            "Amazon Simple Email Service" => "Ses",
            "Amazon Simple Notification Service" => "Sns",
            "Amazon Simple Queue Service" => "Sqs",
            "Amazon Simple Storage Service" => "S3",
            "Amazon Simple Systems Management Service" => "Ssm",
            "Amazon Simple Workflow Service" => "Swf",
            "Amazon SimpleDB" => "SimpleDb",
            "Amazon WorkSpaces" => "Workspaces",
            "Auto Scaling" => "Autoscaling",
            "Elastic Load Balancing" => "Elb",
            name => panic!("Unknown service full name: {}", name),
        }
    }

    pub fn shape_for_member<'a>(&'a self, member: &Member) -> Option<&'a Shape> {
        self.shapes.get(&member.shape).map(|shape| shape)
    }

    pub fn shape_type_for_member<'a>(&'a self, member: &Member) -> Option<&'a str> {
        self.shapes.get(&member.shape).map(|ref shape| &shape.shape_type[..])
    }

    pub fn typed_errors(&self) -> bool {
        match self.metadata.protocol.as_ref() {
            "json" => true,
            _ => false
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct HttpRequest {
    pub method: String,
    #[serde(rename="requestUri")]
    pub request_uri: String,
    #[serde(rename="responseCode")]
    pub response_code: Option<i32>,
}

#[derive(Debug, Deserialize)]
pub struct Input {
    pub documentation: Option<String>,
    pub shape: String,
}

#[derive(Debug, Deserialize)]
pub struct Output {
    pub documentation: Option<String>,
    #[serde(rename="resultWrapper")]
    pub result_wrapper: Option<String>,
    pub shape: String,
}

#[derive(Debug, Deserialize)]
pub struct Error {
    pub documentation: Option<String>,
    pub error: Option<HttpError>,
    pub exception: Option<bool>,
    pub fault: Option<bool>,
    pub shape: String,
}

impl Error {
    pub fn idiomatic_error_name(&self) -> String {
        self.shape.replace("Exception","")
    }
}

#[derive(Debug, Deserialize)]
pub struct HttpError {
    pub code: Option<String>,
    #[serde(rename="httpStatusCode")]
    pub http_status_code: i32,
    #[serde(rename="senderFault")]
    pub sender_fault: Option<bool>,
}

#[derive(Debug, Deserialize)]
pub struct Member {
    pub deprecated: Option<bool>,
    pub documentation: Option<String>,
    pub flattened: Option<bool>,
    pub location: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub shape: String,
    pub streaming: Option<bool>,
    #[serde(rename="xmlAttribute")]
    pub xml_attribute: Option<bool>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<XmlNamespace>,
}

impl Member {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct XmlNamespace {
    pub prefix: Option<String>,
    pub uri: String,
}

#[derive(Debug, Deserialize)]
pub struct Key {
    pub documentation: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub required: Option<bool>,
    pub shape: String,
}

impl Key {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct Value {
    pub documentation: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub shape: String,
}

impl Value {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct Shape {
    #[serde(rename="box")]
    pub aws_box: Option<bool>,
    pub documentation: Option<String>,
    pub error: Option<HttpError>,
    pub exception: Option<bool>,
    pub fault: Option<bool>,
    pub flattened: Option<bool>,
    pub key: Option<Key>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub max: Option<i32>,
    pub member: Option<Member>,
    pub members: Option<BTreeMap<String, Member>>,
    pub min: Option<i32>,
    pub pattern: Option<String>,
    pub payload: Option<String>,
    pub required: Option<Vec<String>>,
    #[serde(rename="enum")]
    pub shape_enum: Option<Vec<String>>,
    #[serde(rename="type")]
    pub shape_type: String,
    pub sensitive: Option<bool>,
    #[serde(rename="timestampFormat")]
    pub timestamp_format: Option<String>,
    pub value: Option<Value>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<XmlNamespace>,
}

impl<'a> Shape {
    pub fn key(&'a self) -> &'a str {
        &self.key.as_ref().expect("Key shape undefined").shape
    }

    pub fn value(&'a self) -> &'a str {
        &self.value.as_ref().expect("Value shape undefined").shape
    }

    pub fn member(&'a self) -> &'a str {
        &self.member.as_ref().expect("Member shape undefined").shape
    }

    pub fn required(&self, field: &'a str) -> bool {
        self.required.is_some() && self.required.as_ref().unwrap().contains(&String::from(field))
    }

    pub fn exception(&self) -> bool {
        self.exception.unwrap_or(false)
    }
}

#[derive(Debug, Deserialize)]
pub struct Operation {
    pub alias: Option<String>,
    pub deprecated: Option<bool>,
    pub documentation: Option<String>,
    #[serde(rename="documentationUrl")]
    pub documentation_url: Option<String>,
    pub errors: Option<Vec<Error>>,
    pub http: HttpRequest,
    pub input: Option<Input>,
    pub name: String,
    pub output: Option<Output>,
}

impl<'a> Operation {
    pub fn input_shape(&'a self) -> &'a str {
        &self.input.as_ref().expect("Operation input undefined").shape
    }

    pub fn output_shape_or(&'a self, default: &'a str) -> &'a str {
        match self.output.as_ref() {
            Some(output) => &output.shape,
            None => default
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Metadata {
    #[serde(rename="apiVersion")]
    pub api_version: String,
    #[serde(rename="checksumFormat")]
    pub checksum_format: Option<String>,
    #[serde(rename="endpointPrefix")]
    pub endpoint_prefix: String,
    #[serde(rename="globalEndpoint")]
    pub global_endpoint: Option<String>,
    #[serde(rename="jsonVersion")]
    pub json_version: Option<String>,
    pub protocol: String,
    #[serde(rename="serviceAbbreviation")]
    pub service_abbreviation: Option<String>,
    #[serde(rename="serviceFullName")]
    pub service_full_name: String,
    #[serde(rename="signatureVersion")]
    pub signature_version: String,
    #[serde(rename="targetPrefix")]
    pub target_prefix: Option<String>,
    #[serde(rename="timestampFormat")]
    pub timestamp_format: Option<String>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<String>
}
<commit_msg>bump Shape.max from i32 -> u64<commit_after>use std::collections::BTreeMap;

#[derive(Debug, Deserialize)]
pub struct Service {
    pub documentation: Option<String>,
    pub examples: Option<BTreeMap<String, String>>,
    pub metadata: Metadata,
    pub operations: BTreeMap<String, Operation>,
    pub shapes: BTreeMap<String, Shape>,
    pub version: String,
}

impl Service {
    pub fn client_type_name(&self) -> String {
        format!("{}Client", self.service_type_name())
    }

    pub fn service_type_name(&self) -> &str {
        match &self.metadata.service_full_name[..] {
            "AWS Certificate Manager" => "Acm",
            "AWS CloudFormation" => "CloudFormation",
            "AWS CloudTrail" => "CloudTrail",
            "AWS CodeCommit" => "CodeCommit",
            "AWS CodeDeploy" => "CodeDeploy",
            "AWS CodePipeline" => "CodePipeline",
            "AWS Config" => "ConfigService",
            "AWS Data Pipeline" => "DataPipeline",
            "AWS Device Farm" => "DeviceFarm",
            "AWS Direct Connect" => "DirectConnect",
            "AWS Directory Service" => "DirectoryService",
            "AWS Elastic Beanstalk" => "ElasticBeanstalk",
            "AWS Identity and Access Management" => "Iam",
            "AWS Import/Export" => "ImportExport",
            "AWS IoT Data Plane" => "IotDataPlane",
            "AWS IoT" => "Iot",
            "AWS Key Management Service" => "Kms",
            "AWS Lambda" => "Lambda",
            "AWS Marketplace Commerce Analytics" => "MarketplaceCommerceAnalytics",
            "AWS OpsWorks" => "OpsWorks",
            "AWS Security Token Service" => "Sts",
            "AWS Storage Gateway" => "StorageGateway",
            "AWS Support" => "Support",
            "AWS WAF" => "Waf",
            "Amazon API Gateway" => "ApiGateway",
            "Amazon CloudFront" => "CloudFront",
            "Amazon CloudHSM" => "CloudHsm",
            "Amazon CloudSearch Domain" => "CloudSearchDomain",
            "Amazon CloudSearch" => "CloudSearch",
            "Amazon CloudWatch Events" => "CloudWatchEvents",
            "Amazon CloudWatch Logs" => "CloudWatchLogs",
            "Amazon CloudWatch" => "CloudWatch",
            "Amazon Cognito Identity" => "CognitoIdentity",
            "Amazon Cognito Sync" => "CognitoSync",
            "Amazon DynamoDB Streams" => "DynamoDbStreams",
            "Amazon DynamoDB" => "DynamoDb",
            "Amazon EC2 Container Registry" => "Ecr",
            "Amazon EC2 Container Service" => "Ecs",
            "Amazon ElastiCache" => "ElastiCache",
            "Amazon Elastic Compute Cloud" => "Ec2",
            "Amazon Elastic File System" => "Efs",
            "Amazon Elastic MapReduce" => "Emr",
            "Amazon Elastic Transcoder" => "Ets",
            "Amazon Elasticsearch Service" => "ElasticsearchService",
            "Amazon GameLift" => "GameLift",
            "Amazon Glacier" => "Glacier",
            "Amazon Inspector" => "Inspector",
            "Amazon Kinesis Firehose" => "KinesisFirehose",
            "Amazon Kinesis" => "Kinesis",
            "Amazon Machine Learning" => "MachineLearning",
            "Amazon Redshift" => "Redshift",
            "Amazon Relational Database Service" => "Rds",
            "Amazon Route 53 Domains" => "Route53Domains",
            "Amazon Route 53" => "Route53",
            "Amazon Simple Email Service" => "Ses",
            "Amazon Simple Notification Service" => "Sns",
            "Amazon Simple Queue Service" => "Sqs",
            "Amazon Simple Storage Service" => "S3",
            "Amazon Simple Systems Management Service" => "Ssm",
            "Amazon Simple Workflow Service" => "Swf",
            "Amazon SimpleDB" => "SimpleDb",
            "Amazon WorkSpaces" => "Workspaces",
            "Auto Scaling" => "Autoscaling",
            "Elastic Load Balancing" => "Elb",
            name => panic!("Unknown service full name: {}", name),
        }
    }

    pub fn shape_for_member<'a>(&'a self, member: &Member) -> Option<&'a Shape> {
        self.shapes.get(&member.shape).map(|shape| shape)
    }

    pub fn shape_type_for_member<'a>(&'a self, member: &Member) -> Option<&'a str> {
        self.shapes.get(&member.shape).map(|ref shape| &shape.shape_type[..])
    }

    pub fn typed_errors(&self) -> bool {
        match self.metadata.protocol.as_ref() {
            "json" => true,
            _ => false
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct HttpRequest {
    pub method: String,
    #[serde(rename="requestUri")]
    pub request_uri: String,
    #[serde(rename="responseCode")]
    pub response_code: Option<i32>,
}

#[derive(Debug, Deserialize)]
pub struct Input {
    pub documentation: Option<String>,
    pub shape: String,
}

#[derive(Debug, Deserialize)]
pub struct Output {
    pub documentation: Option<String>,
    #[serde(rename="resultWrapper")]
    pub result_wrapper: Option<String>,
    pub shape: String,
}

#[derive(Debug, Deserialize)]
pub struct Error {
    pub documentation: Option<String>,
    pub error: Option<HttpError>,
    pub exception: Option<bool>,
    pub fault: Option<bool>,
    pub shape: String,
}

impl Error {
    pub fn idiomatic_error_name(&self) -> String {
        self.shape.replace("Exception","")
    }
}

#[derive(Debug, Deserialize)]
pub struct HttpError {
    pub code: Option<String>,
    #[serde(rename="httpStatusCode")]
    pub http_status_code: i32,
    #[serde(rename="senderFault")]
    pub sender_fault: Option<bool>,
}

#[derive(Debug, Deserialize)]
pub struct Member {
    pub deprecated: Option<bool>,
    pub documentation: Option<String>,
    pub flattened: Option<bool>,
    pub location: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub shape: String,
    pub streaming: Option<bool>,
    #[serde(rename="xmlAttribute")]
    pub xml_attribute: Option<bool>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<XmlNamespace>,
}

impl Member {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct XmlNamespace {
    pub prefix: Option<String>,
    pub uri: String,
}

#[derive(Debug, Deserialize)]
pub struct Key {
    pub documentation: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub required: Option<bool>,
    pub shape: String,
}

impl Key {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct Value {
    pub documentation: Option<String>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub shape: String,
}

impl Value {
    pub fn tag_name(&self) -> String {
        self.location_name.clone().unwrap_or(self.shape.clone())
    }
}

#[derive(Debug, Deserialize)]
pub struct Shape {
    #[serde(rename="box")]
    pub aws_box: Option<bool>,
    pub documentation: Option<String>,
    pub error: Option<HttpError>,
    pub exception: Option<bool>,
    pub fault: Option<bool>,
    pub flattened: Option<bool>,
    pub key: Option<Key>,
    #[serde(rename="locationName")]
    pub location_name: Option<String>,
    pub max: Option<u64>,
    pub member: Option<Member>,
    pub members: Option<BTreeMap<String, Member>>,
    pub min: Option<i32>,
    pub pattern: Option<String>,
    pub payload: Option<String>,
    pub required: Option<Vec<String>>,
    #[serde(rename="enum")]
    pub shape_enum: Option<Vec<String>>,
    #[serde(rename="type")]
    pub shape_type: String,
    pub sensitive: Option<bool>,
    #[serde(rename="timestampFormat")]
    pub timestamp_format: Option<String>,
    pub value: Option<Value>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<XmlNamespace>,
}

impl<'a> Shape {
    pub fn key(&'a self) -> &'a str {
        &self.key.as_ref().expect("Key shape undefined").shape
    }

    pub fn value(&'a self) -> &'a str {
        &self.value.as_ref().expect("Value shape undefined").shape
    }

    pub fn member(&'a self) -> &'a str {
        &self.member.as_ref().expect("Member shape undefined").shape
    }

    pub fn required(&self, field: &'a str) -> bool {
        self.required.is_some() && self.required.as_ref().unwrap().contains(&String::from(field))
    }

    pub fn exception(&self) -> bool {
        self.exception.unwrap_or(false)
    }
}

#[derive(Debug, Deserialize)]
pub struct Operation {
    pub alias: Option<String>,
    pub deprecated: Option<bool>,
    pub documentation: Option<String>,
    #[serde(rename="documentationUrl")]
    pub documentation_url: Option<String>,
    pub errors: Option<Vec<Error>>,
    pub http: HttpRequest,
    pub input: Option<Input>,
    pub name: String,
    pub output: Option<Output>,
}

impl<'a> Operation {
    pub fn input_shape(&'a self) -> &'a str {
        &self.input.as_ref().expect("Operation input undefined").shape
    }

    pub fn output_shape_or(&'a self, default: &'a str) -> &'a str {
        match self.output.as_ref() {
            Some(output) => &output.shape,
            None => default
        }
    }
}

#[derive(Debug, Deserialize)]
pub struct Metadata {
    #[serde(rename="apiVersion")]
    pub api_version: String,
    #[serde(rename="checksumFormat")]
    pub checksum_format: Option<String>,
    #[serde(rename="endpointPrefix")]
    pub endpoint_prefix: String,
    #[serde(rename="globalEndpoint")]
    pub global_endpoint: Option<String>,
    #[serde(rename="jsonVersion")]
    pub json_version: Option<String>,
    pub protocol: String,
    #[serde(rename="serviceAbbreviation")]
    pub service_abbreviation: Option<String>,
    #[serde(rename="serviceFullName")]
    pub service_full_name: String,
    #[serde(rename="signatureVersion")]
    pub signature_version: String,
    #[serde(rename="targetPrefix")]
    pub target_prefix: Option<String>,
    #[serde(rename="timestampFormat")]
    pub timestamp_format: Option<String>,
    #[serde(rename="xmlNamespace")]
    pub xml_namespace: Option<String>
}
<|endoftext|>


<commit_before>use handlers::geometry::UsableScreenGeometry;

use handlers::store::{Store, StoreKey};
use handlers::workspaces::modes::Mode;
use slog;
use slog_scope;

use std::cmp;
use wlc::{Button, ButtonState, Callback, Geometry, Modifiers, Output, Point, ResizeEdge, Size, View,
          ViewType, ViewState, WeakView, input};

/// A `Mode` that does traditional `View` management.
///
/// `View`s are "floating" on the `Output`, may obstruct each other and
/// their requests for placement (like maximizing) are respected.
pub struct Floating {
    views: Vec<WeakView>,
    active_view: Option<WeakView>,
    geo: Geometry,
    logger: slog::Logger,
}

/// Configuration for `Floating`
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct FloatingConfig {}

struct InteractiveMove;
struct InteractiveResize;
struct Maximized;

impl StoreKey for InteractiveMove {
    type Value = Point;
}
impl StoreKey for InteractiveResize {
    type Value = ResizeEdge::Flags;
}
impl StoreKey for Maximized {
    type Value = Geometry;
}

impl Callback for Floating {
    fn view_created(&mut self, view: &View) -> bool {
        debug!(self.logger, "Register View: {:?}", view);

        if let Some(pos) = view.positioner() {
            let mut size_req = pos.size();
            if size_req.w == 0 || size_req.h == 0 {
                size_req = view.geometry().size;
            }

            let mut geometry = Geometry {
                origin: pos.anchor_rect().origin,
                size: size_req,
            };

            if let Some(parent) = view.parent() {
                let parent_geometry = parent.geometry();
                geometry.origin.x += parent_geometry.origin.x;
                geometry.origin.y += parent_geometry.origin.y;
            }

            view.set_geometry(ResizeEdge::Null, geometry);
        } else {
            // fix out of bounds
            {
                let view_geometry = view.geometry();
                if !(view_geometry.origin > self.geo.origin) || (view_geometry.size > self.geo.size) {
                    view.set_geometry(ResizeEdge::Null,
                                      Geometry {
                                          origin: Point {
                                              x: cmp::max(self.geo.origin.x, view_geometry.origin.x),
                                              y: cmp::max(self.geo.origin.y, view_geometry.origin.y),
                                          },
                                          size: Size {
                                              w: cmp::min(self.geo.size.w, view_geometry.size.w),
                                              h: cmp::min(self.geo.size.h, view_geometry.size.h),
                                          },
                                      });
                }
            }
            // center
            if !view.view_type().contains(ViewType::Unmanaged)
            {
                let view_geometry = view.geometry();
                view.set_geometry(ResizeEdge::Null, Geometry {
                    origin: Point {
                        x: (self.geo.size.w as i32 / 2) - (view_geometry.size.w as i32 / 2),
                        y: (self.geo.size.h as i32 / 2) - (view_geometry.size.h as i32 / 2),
                    },
                    size: view_geometry.size,
                });
            }
        }

        self.views.push(view.weak_reference());
        true
    }

    fn view_focus(&mut self, view: &View, focus: bool) {
        if focus {
            view.bring_to_front();
        }
    }

    fn view_destroyed(&mut self, view: &View) {
        self.views.retain(|x| x != &view.weak_reference());
    }

    fn view_request_geometry(&mut self, view: &View, geometry: Geometry) {
        view.set_geometry(ResizeEdge::Null,
                          Geometry {
                              origin: Point {
                                  x: cmp::max(self.geo.origin.x, geometry.origin.x),
                                  y: cmp::max(self.geo.origin.y, geometry.origin.y),
                              },
                              size: Size {
                                  w: cmp::min(self.geo.size.w, geometry.size.w),
                                  h: cmp::min(self.geo.size.h, geometry.size.h),
                              },
                          });
    }

    fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {
        match state {
            x if x.contains(ViewState::Moving) && !toggle => view.set_state(ViewState::Moving, false),
            x if x.contains(ViewState::Moving) && toggle => info!(self.logger, "Moving true?"),
            x if x.contains(ViewState::Resizing) && !toggle => view.set_state(ViewState::Resizing, false),
            x if x.contains(ViewState::Resizing) && toggle => info!(self.logger, "Resizing true?"),
            x if x.contains(ViewState::Maximized) => {
                if toggle {
                    debug!(self.logger, "Maximizing {:?}", view);
                    let old_geo = view.geometry();
                    view.set_geometry(ResizeEdge::Null, self.geo);
                    view.set_state(state, true);
                    view.insert::<Maximized>(old_geo);
                } else {
                    if let Some(old_geo) = view.remove::<Maximized>() {
                        view.set_geometry(ResizeEdge::Null, old_geo);
                    }
                    view.set_state(state, false);
                }
            }
            _ => {}
        };
    }

    fn view_request_move(&mut self, view: &View, _origin: Point) {
        debug!(self.logger, "Start moving View: {:?}", view);
        view.set_state(ViewState::Moving, true);
        let pointer = input::pointer::position();
        let geo = view.geometry();
        let relative = Point {
            x: geo.origin.x - pointer.x,
            y: geo.origin.y - pointer.y,
        };
        view.insert::<InteractiveMove>(relative);
        self.active_view = Some(view.weak_reference());
    }

    fn view_request_resize(&mut self, view: &View, edges: ResizeEdge::Flags, _origin: Point) {
        debug!(self.logger, "Start resizing View: {:?}", view);
        view.set_state(ViewState::Resizing, true);
        view.insert::<InteractiveResize>(edges);
        self.active_view = Some(view.weak_reference());
    }

    fn output_resolution(&mut self, output: &Output, from: Size, to: Size) {
        if to < from {
            for view in &mut self.views {
                view.run(|view| {
                    let geo = view.geometry();
                    let width = if geo.origin.x as u32 + geo.size.w > to.w {
                        to.w as i32 - geo.origin.x
                    } else {
                        geo.size.w as i32
                    } as u32;
                    let height = if geo.origin.y as u32 + geo.size.h > to.h {
                        to.h as i32 - geo.origin.y
                    } else {
                        geo.size.h as i32
                    } as u32;
                    view.set_geometry(ResizeEdge::Null,
                                      Geometry {
                                          origin: Point {
                                              x: geo.origin.x,
                                              y: geo.origin.y,
                                          },
                                          size: Size {
                                              w: width,
                                              h: height,
                                          },
                                      });
                });
            }
        }

        let lock = output.get::<UsableScreenGeometry>();
        self.geo = match lock.as_ref().and_then(|x| x.read().ok()) {
            Some(size) => *size,
            None => {
                Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: to,
                }
            }
        };
    }

    fn pointer_button(&mut self, _view: Option<&View>, _time: u32, _modifiers: Modifiers, button: Button,
                      state: ButtonState, _origin: Point)
                      -> bool {
        if let Some(ref view) = self.active_view {
            view.run(|view| if state == ButtonState::Released && button == Button::Left {
                view.set_state(ViewState::Resizing, false);
                view.set_state(ViewState::Moving, false);
            });
        }
        false
    }

    fn pointer_motion(&mut self, _view: Option<&View>, _time: u32, origin: Point) -> bool {
        let still_active = if let Some(ref view) = self.active_view {
            view.run(|view| {
                    if !view.state().contains(ViewState::Moving) {
                        view.remove::<InteractiveMove>();
                    }
                    if !view.state().contains(ViewState::Resizing) {
                        view.remove::<InteractiveResize>();
                    }
                    view.get::<InteractiveMove>().is_some() || view.get::<InteractiveResize>().is_some()
                })
                .unwrap_or(false)
        } else {
            false
        };

        if !still_active {
            self.active_view = None;
            return false;
        }

        if let Some(ref view) = self.active_view {
            view.run(|view| {
                    let lock = view.get::<InteractiveMove>();
                    if let Some(relative) = lock.as_ref().and_then(|x| x.read().ok()) {
                        let old = view.geometry();
                        view.set_geometry(ResizeEdge::Null,
                                          Geometry {
                                              origin: Point {
                                                  x: cmp::max(origin.x + (*relative).x, self.geo.origin.x),
                                                  y: cmp::max(origin.y + (*relative).y, self.geo.origin.y),
                                              },
                                              size: old.size,
                                          });
                        return true;
                    }

                    let lock = view.get::<InteractiveResize>();
                    if let Some(edges) = lock.as_ref().and_then(|x| x.read().ok()) {
                        if edges.contains(ResizeEdge::Bottom) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: old.origin,
                                                  size: Size {
                                                      w: old.size.w,
                                                      h: cmp::max(origin.y - old.origin.y, 1) as u32,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Top) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: Point {
                                                      x: old.origin.x,
                                                      y: cmp::max(self.geo.origin.y, origin.y),
                                                  },
                                                  size: Size {
                                                      w: old.size.w,
                                                      h: cmp::max(old.size.h as i32 +
                                                                  (old.origin.y -
                                                                   cmp::max(self.geo.origin.y, origin.y)),
                                                                  1) as
                                                         u32,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Left) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: Point {
                                                      x: cmp::max(self.geo.origin.x, origin.x),
                                                      y: old.origin.y,
                                                  },
                                                  size: Size {
                                                      w: cmp::max(old.size.w as i32 +
                                                                  (old.origin.x -
                                                                   cmp::max(self.geo.origin.x, origin.x)),
                                                                  1) as
                                                         u32,
                                                      h: old.size.h,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Right) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: old.origin,
                                                  size: Size {
                                                      w: cmp::max(origin.x - old.origin.x, 1) as u32,
                                                      h: old.size.h,
                                                  },
                                              });
                        }
                        return true;
                    };

                    false
                })
                .unwrap_or(false)
        } else {
            false
        }
    }
}

impl Mode for Floating {
    type Arguments = FloatingConfig;

    fn new(_: FloatingConfig) -> Floating {
        let mode = Floating {
            views: Vec::new(),
            active_view: None,
            geo: Geometry {
                origin: Point { x: 0, y: 0 },
                size: Size { w: 0, h: 0 },
            },
            logger: slog_scope::logger().new(o!("instance" => "Floating")),
        };
        debug!(mode.logger, "Created");
        mode
    }

    fn len(&self) -> usize {
        self.views.len()
    }
}
<commit_msg>Dont center tooltips, menus, etc<commit_after>use handlers::geometry::UsableScreenGeometry;

use handlers::store::{Store, StoreKey};
use handlers::workspaces::modes::Mode;
use slog;
use slog_scope;

use std::cmp;
use wlc::{Button, ButtonState, Callback, Geometry, Modifiers, Output, Point, ResizeEdge, Size, View,
          ViewType, ViewState, WeakView, input};

/// A `Mode` that does traditional `View` management.
///
/// `View`s are "floating" on the `Output`, may obstruct each other and
/// their requests for placement (like maximizing) are respected.
pub struct Floating {
    views: Vec<WeakView>,
    active_view: Option<WeakView>,
    geo: Geometry,
    logger: slog::Logger,
}

/// Configuration for `Floating`
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize)]
pub struct FloatingConfig {}

struct InteractiveMove;
struct InteractiveResize;
struct Maximized;

impl StoreKey for InteractiveMove {
    type Value = Point;
}
impl StoreKey for InteractiveResize {
    type Value = ResizeEdge::Flags;
}
impl StoreKey for Maximized {
    type Value = Geometry;
}

impl Callback for Floating {
    fn view_created(&mut self, view: &View) -> bool {
        debug!(self.logger, "Register View: {:?}", view);

        if let Some(pos) = view.positioner() {
            let mut size_req = pos.size();
            if size_req.w == 0 || size_req.h == 0 {
                size_req = view.geometry().size;
            }

            let mut geometry = Geometry {
                origin: pos.anchor_rect().origin,
                size: size_req,
            };

            if let Some(parent) = view.parent() {
                let parent_geometry = parent.geometry();
                geometry.origin.x += parent_geometry.origin.x;
                geometry.origin.y += parent_geometry.origin.y;
            }

            view.set_geometry(ResizeEdge::Null, geometry);
        } else {
            // fix out of bounds
            {
                let view_geometry = view.geometry();
                if !(view_geometry.origin > self.geo.origin) || (view_geometry.size > self.geo.size) {
                    view.set_geometry(ResizeEdge::Null,
                                      Geometry {
                                          origin: Point {
                                              x: cmp::max(self.geo.origin.x, view_geometry.origin.x),
                                              y: cmp::max(self.geo.origin.y, view_geometry.origin.y),
                                          },
                                          size: Size {
                                              w: cmp::min(self.geo.size.w, view_geometry.size.w),
                                              h: cmp::min(self.geo.size.h, view_geometry.size.h),
                                          },
                                      });
                }
            }
            // center
            if !view.view_type().intersects(ViewType::Unmanaged | ViewType::OverrideRedirect)
            {
                let view_geometry = view.geometry();
                view.set_geometry(ResizeEdge::Null, Geometry {
                    origin: Point {
                        x: (self.geo.size.w as i32 / 2) - (view_geometry.size.w as i32 / 2),
                        y: (self.geo.size.h as i32 / 2) - (view_geometry.size.h as i32 / 2),
                    },
                    size: view_geometry.size,
                });
            }
        }

        self.views.push(view.weak_reference());
        true
    }

    fn view_focus(&mut self, view: &View, focus: bool) {
        if focus {
            view.bring_to_front();
        }
    }

    fn view_destroyed(&mut self, view: &View) {
        self.views.retain(|x| x != &view.weak_reference());
    }

    fn view_request_geometry(&mut self, view: &View, geometry: Geometry) {
        view.set_geometry(ResizeEdge::Null,
                          Geometry {
                              origin: Point {
                                  x: cmp::max(self.geo.origin.x, geometry.origin.x),
                                  y: cmp::max(self.geo.origin.y, geometry.origin.y),
                              },
                              size: Size {
                                  w: cmp::min(self.geo.size.w, geometry.size.w),
                                  h: cmp::min(self.geo.size.h, geometry.size.h),
                              },
                          });
    }

    fn view_request_state(&mut self, view: &View, state: ViewState::Flags, toggle: bool) {
        match state {
            x if x.contains(ViewState::Moving) && !toggle => view.set_state(ViewState::Moving, false),
            x if x.contains(ViewState::Moving) && toggle => info!(self.logger, "Moving true?"),
            x if x.contains(ViewState::Resizing) && !toggle => view.set_state(ViewState::Resizing, false),
            x if x.contains(ViewState::Resizing) && toggle => info!(self.logger, "Resizing true?"),
            x if x.contains(ViewState::Maximized) => {
                if toggle {
                    debug!(self.logger, "Maximizing {:?}", view);
                    let old_geo = view.geometry();
                    view.set_geometry(ResizeEdge::Null, self.geo);
                    view.set_state(state, true);
                    view.insert::<Maximized>(old_geo);
                } else {
                    if let Some(old_geo) = view.remove::<Maximized>() {
                        view.set_geometry(ResizeEdge::Null, old_geo);
                    }
                    view.set_state(state, false);
                }
            }
            _ => {}
        };
    }

    fn view_request_move(&mut self, view: &View, _origin: Point) {
        debug!(self.logger, "Start moving View: {:?}", view);
        view.set_state(ViewState::Moving, true);
        let pointer = input::pointer::position();
        let geo = view.geometry();
        let relative = Point {
            x: geo.origin.x - pointer.x,
            y: geo.origin.y - pointer.y,
        };
        view.insert::<InteractiveMove>(relative);
        self.active_view = Some(view.weak_reference());
    }

    fn view_request_resize(&mut self, view: &View, edges: ResizeEdge::Flags, _origin: Point) {
        debug!(self.logger, "Start resizing View: {:?}", view);
        view.set_state(ViewState::Resizing, true);
        view.insert::<InteractiveResize>(edges);
        self.active_view = Some(view.weak_reference());
    }

    fn output_resolution(&mut self, output: &Output, from: Size, to: Size) {
        if to < from {
            for view in &mut self.views {
                view.run(|view| {
                    let geo = view.geometry();
                    let width = if geo.origin.x as u32 + geo.size.w > to.w {
                        to.w as i32 - geo.origin.x
                    } else {
                        geo.size.w as i32
                    } as u32;
                    let height = if geo.origin.y as u32 + geo.size.h > to.h {
                        to.h as i32 - geo.origin.y
                    } else {
                        geo.size.h as i32
                    } as u32;
                    view.set_geometry(ResizeEdge::Null,
                                      Geometry {
                                          origin: Point {
                                              x: geo.origin.x,
                                              y: geo.origin.y,
                                          },
                                          size: Size {
                                              w: width,
                                              h: height,
                                          },
                                      });
                });
            }
        }

        let lock = output.get::<UsableScreenGeometry>();
        self.geo = match lock.as_ref().and_then(|x| x.read().ok()) {
            Some(size) => *size,
            None => {
                Geometry {
                    origin: Point { x: 0, y: 0 },
                    size: to,
                }
            }
        };
    }

    fn pointer_button(&mut self, _view: Option<&View>, _time: u32, _modifiers: Modifiers, button: Button,
                      state: ButtonState, _origin: Point)
                      -> bool {
        if let Some(ref view) = self.active_view {
            view.run(|view| if state == ButtonState::Released && button == Button::Left {
                view.set_state(ViewState::Resizing, false);
                view.set_state(ViewState::Moving, false);
            });
        }
        false
    }

    fn pointer_motion(&mut self, _view: Option<&View>, _time: u32, origin: Point) -> bool {
        let still_active = if let Some(ref view) = self.active_view {
            view.run(|view| {
                    if !view.state().contains(ViewState::Moving) {
                        view.remove::<InteractiveMove>();
                    }
                    if !view.state().contains(ViewState::Resizing) {
                        view.remove::<InteractiveResize>();
                    }
                    view.get::<InteractiveMove>().is_some() || view.get::<InteractiveResize>().is_some()
                })
                .unwrap_or(false)
        } else {
            false
        };

        if !still_active {
            self.active_view = None;
            return false;
        }

        if let Some(ref view) = self.active_view {
            view.run(|view| {
                    let lock = view.get::<InteractiveMove>();
                    if let Some(relative) = lock.as_ref().and_then(|x| x.read().ok()) {
                        let old = view.geometry();
                        view.set_geometry(ResizeEdge::Null,
                                          Geometry {
                                              origin: Point {
                                                  x: cmp::max(origin.x + (*relative).x, self.geo.origin.x),
                                                  y: cmp::max(origin.y + (*relative).y, self.geo.origin.y),
                                              },
                                              size: old.size,
                                          });
                        return true;
                    }

                    let lock = view.get::<InteractiveResize>();
                    if let Some(edges) = lock.as_ref().and_then(|x| x.read().ok()) {
                        if edges.contains(ResizeEdge::Bottom) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: old.origin,
                                                  size: Size {
                                                      w: old.size.w,
                                                      h: cmp::max(origin.y - old.origin.y, 1) as u32,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Top) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: Point {
                                                      x: old.origin.x,
                                                      y: cmp::max(self.geo.origin.y, origin.y),
                                                  },
                                                  size: Size {
                                                      w: old.size.w,
                                                      h: cmp::max(old.size.h as i32 +
                                                                  (old.origin.y -
                                                                   cmp::max(self.geo.origin.y, origin.y)),
                                                                  1) as
                                                         u32,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Left) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: Point {
                                                      x: cmp::max(self.geo.origin.x, origin.x),
                                                      y: old.origin.y,
                                                  },
                                                  size: Size {
                                                      w: cmp::max(old.size.w as i32 +
                                                                  (old.origin.x -
                                                                   cmp::max(self.geo.origin.x, origin.x)),
                                                                  1) as
                                                         u32,
                                                      h: old.size.h,
                                                  },
                                              });
                        }
                        if edges.contains(ResizeEdge::Right) {
                            let old = view.geometry();
                            view.set_geometry(*edges,
                                              Geometry {
                                                  origin: old.origin,
                                                  size: Size {
                                                      w: cmp::max(origin.x - old.origin.x, 1) as u32,
                                                      h: old.size.h,
                                                  },
                                              });
                        }
                        return true;
                    };

                    false
                })
                .unwrap_or(false)
        } else {
            false
        }
    }
}

impl Mode for Floating {
    type Arguments = FloatingConfig;

    fn new(_: FloatingConfig) -> Floating {
        let mode = Floating {
            views: Vec::new(),
            active_view: None,
            geo: Geometry {
                origin: Point { x: 0, y: 0 },
                size: Size { w: 0, h: 0 },
            },
            logger: slog_scope::logger().new(o!("instance" => "Floating")),
        };
        debug!(mode.logger, "Created");
        mode
    }

    fn len(&self) -> usize {
        self.views.len()
    }
}
<|endoftext|>


<commit_before>use crate::view::View;
use std::any::Any;

/// A view that can be downcasted to its concrete type.
///
/// This trait is automatically implemented for any `T: View`.
pub trait AnyView {
    /// Downcast self to a `Any`.
    fn as_any(&self) -> &dyn Any;

    /// Downcast self to a mutable `Any`.
    fn as_any_mut(&mut self) -> &mut dyn Any;

    /// Returns a boxed any from a boxed self.
    ///
    /// Can be used before `Box::downcast()`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::views::TextView;
    /// # use cursive::view::View;
    /// # fn main() {
    /// let boxed: Box<View> = Box::new(TextView::new("text"));
    /// let text: Box<TextView> = boxed.as_boxed_any().downcast().unwrap();
    /// # }
    /// ```
    fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
}

impl<T: View> AnyView for T {
    /// Downcast self to a `Any`.
    fn as_any(&self) -> &dyn Any {
        self
    }

    /// Downcast self to a mutable `Any`.
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }

    fn as_boxed_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}
<commit_msg>Add direct downcast methods to AnyView<commit_after>use crate::view::View;
use std::any::Any;

/// A view that can be downcasted to its concrete type.
///
/// This trait is automatically implemented for any `T: View`.
pub trait AnyView {
    /// Downcast self to a `Any`.
    fn as_any(&self) -> &dyn Any;

    /// Downcast self to a mutable `Any`.
    fn as_any_mut(&mut self) -> &mut dyn Any;

    /// Returns a boxed any from a boxed self.
    ///
    /// Can be used before `Box::downcast()`.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cursive::views::TextView;
    /// # use cursive::view::View;
    /// # fn main() {
    /// let boxed: Box<View> = Box::new(TextView::new("text"));
    /// let text: Box<TextView> = boxed.as_boxed_any().downcast().unwrap();
    /// # }
    /// ```
    fn as_boxed_any(self: Box<Self>) -> Box<dyn Any>;
}

impl<T: View> AnyView for T {
    /// Downcast self to a `Any`.
    fn as_any(&self) -> &dyn Any {
        self
    }

    /// Downcast self to a mutable `Any`.
    fn as_any_mut(&mut self) -> &mut dyn Any {
        self
    }

    fn as_boxed_any(self: Box<Self>) -> Box<dyn Any> {
        self
    }
}

impl dyn AnyView {
    /// Attempts to downcast `self` to a concrete type.
    pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
        self.as_any().downcast_ref()
    }

    /// Attempts to downcast `self` to a concrete type.
    pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
        self.as_any_mut().downcast_mut()
    }

    /// Attempts to downcast `Box<Self>` to a concrete type.
    pub fn downcast<T: Any>(self: Box<Self>) -> Result<Box<T>, Box<Self>> {
        // Do the check here + unwrap, so the error
        // value is `Self` and not `dyn Any`.
        if self.as_any().is::<T>() {
            Ok(self.as_boxed_any().downcast().unwrap())
        } else {
            Err(self)
        }
    }
}
<|endoftext|>