neovim/
metadata.rs

1use mpack::{self, Value, ValueMap};
2use std::convert;
3use std::error;
4use std::fmt;
5
6/// Type identifiers for certain types, determined at runtime.
7pub struct Metadata {
8    pub buffer_id: i64,
9    pub window_id: i64,
10    pub tabpage_id: i64,
11}
12
13#[derive(Debug)]
14pub enum GetMetadataError {
15    /// Attempted to retrieve metadata from a non-map value.
16    NotAMap,
17    /// The map contains no `types` field.
18    NoTypeInformation,
19    /// A requested `id` value could not be found.
20    Missing(String),
21    /// A requested `id` value was found, but couldn't be parsed as an int.
22    Invalid(String),
23    /// Generic read error.
24    ReadError(mpack::ReadError),
25}
26
27impl fmt::Display for GetMetadataError {
28    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
29        write!(fmt, "{}", self)
30    }
31}
32
33impl error::Error for GetMetadataError {
34    fn description(&self) -> &str {
35        match *self {
36            GetMetadataError::NotAMap => "not a map",
37            GetMetadataError::NoTypeInformation => "no type information",
38            GetMetadataError::Invalid(_) => "invalid id",
39            GetMetadataError::Missing(_) => "missing id",
40            GetMetadataError::ReadError(_) => "read error",
41        }
42    }
43
44    fn cause(&self) -> Option<&error::Error> {
45        match *self {
46            GetMetadataError::ReadError(ref e) => Some(e as &error::Error),
47            _ => None,
48        }
49    }
50}
51
52impl convert::From<mpack::ReadError> for GetMetadataError {
53    fn from(err: mpack::ReadError) -> GetMetadataError {
54        GetMetadataError::ReadError(err)
55    }
56}
57
58impl Metadata {
59    /// Attempt to read metadata information from the provided value.
60    ///
61    /// This method expects the value to represent this type of data structure:
62    ///
63    /// ```json
64    /// {
65    ///     "types": {
66    ///         "Buffer":  { "id": <int> },
67    ///         "Window":  { "id": <int> },
68    ///         "Tabpage": { "id": <int> }
69    ///     }
70    /// }
71    /// ```
72    ///
73    /// It then pulls out the id values and stores them in the returned `Metadata` struct
74    /// so that buffer, window, and tabpage values received from Neovim can be parsed
75    /// appropriately.
76    pub fn new(metadata: Value) -> Result<Metadata, GetMetadataError> {
77        let metadata = match metadata.map() {
78            Ok(m) => m,
79            Err(_) => return Err(GetMetadataError::NotAMap),
80        };
81
82        let types = match metadata.get("types") {
83            Some(t) => t.clone().map().unwrap(),
84            None => return Err(GetMetadataError::NoTypeInformation),
85        };
86
87        fn get_id(types: &ValueMap, name: &'static str) -> Result<i64, GetMetadataError> {
88            let ob = match types.get(name) {
89                Some(v) => match v.clone().map() {
90                    Ok(ob) => ob,
91                    Err(_) => return Err(GetMetadataError::Missing(format!("{}.id", name))),
92                },
93                None => return Err(GetMetadataError::Missing(format!("{}.id", name))),
94            };
95
96            match ob.get("id") {
97                Some(id) => Ok(id.clone().int().unwrap()),
98                None => return Err(GetMetadataError::Invalid(format!("{}.id", name))),
99            }
100        }
101
102        Ok(Metadata {
103            buffer_id: try!(get_id(&types, "Buffer")),
104            window_id: try!(get_id(&types, "Window")),
105            tabpage_id: try!(get_id(&types, "Tabpage")),
106        })
107    }
108}