tweetust 0.10.0

The Twitter API wrapper
Documentation
mod internal;

#[derive(Debug)]
pub struct ApiTemplate {
    pub namespace: String,
    pub description: Option<String>,
    pub endpoints: Vec<Endpoint>,
}

#[derive(Debug)]
pub struct Endpoint {
    pub return_type: String,
    pub name: String,
    pub endpoint_type: EndpointType,
    pub json_path: Option<String>,
    pub attributes: Vec<(String, String)>,
    pub ignore: bool,
    pub description: Option<String>,
    pub returns: Option<String>,
    pub params: Vec<Param>,
}

#[derive(Debug, PartialEq, Eq)]
pub enum EndpointType {
    Get(String),
    Post(String),
    Impl,
}

#[derive(Debug)]
pub struct Param {
    pub kind: ParamKind,
    pub type_name_pairs: Vec<TypeNamePair>,
    pub when: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ParamKind {
    Required,
    Either(u8),
    Optional,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeNamePair {
    pub param_type: String,
    pub name: String,
}

#[derive(Debug)]
pub enum ParseErrorKind<'a> {
    InternalParserError(::nom::Err<&'a str>),
    Missing(&'static str),
}

pub fn parse(input: &str) -> Result<ApiTemplate, ParseErrorKind> {
    let root = match internal::parse_api_template(input) {
        Ok(x) => x,
        Err(x) => return Err(ParseErrorKind::InternalParserError(x))
    };

    let namespace = {
        let ns = root.iter()
            .filter_map(|x| match *x {
                internal::RootElement::Namespace(x) => Some(x.to_owned()),
                _ => None
            })
            .nth(0);
        if let Some(x) = ns { x }
        else { return Err(ParseErrorKind::Missing("#namespace")) }
    };

    let description = root.iter()
        .filter_map(|x| match *x {
            internal::RootElement::Description(x) => Some(x.to_owned()),
            _ => None
        })
        .nth(0);

    let mut endpoints = Vec::with_capacity(root.len() - (if description.is_some() { 2 } else { 1 }));
    for x in root.into_iter() {
        if let internal::RootElement::Endpoint { header: h, elements: e } = x {
            let with = e.iter()
                .filter_map(|x| match *x {
                    internal::EndpointElement::With(ref x) => Some(x),
                    _ => None
                })
                .nth(0);

            endpoints.push(
                Endpoint {
                    return_type: h.return_type.to_owned(),
                    name: h.name.to_owned(),
                    endpoint_type: match h.endpoint_type {
                        internal::EndpointType::Get(x) => EndpointType::Get(x.to_owned()),
                        internal::EndpointType::Post(x) => EndpointType::Post(x.to_owned()),
                        internal::EndpointType::Impl => EndpointType::Impl,
                    },
                    json_path: with.and_then(|with| with.iter()
                        .filter_map(|x| match *x {
                            internal::WithElement::JsonPath(x) => Some(x.to_owned()),
                            _ => None
                        })
                        .nth(0)
                    ),
                    attributes: match with {
                        Some(with) => with.iter()
                            .filter_map(|x| match *x {
                                internal::WithElement::Attribute(x, y) => Some((x.to_owned(), y.to_owned())),
                                _ => None
                            })
                            .collect(),
                        None => Vec::new()
                    },
                    ignore: match with {
                        Some(with) => with.iter().any(|x| x == &internal::WithElement::Ignore),
                        None => false,
                    },
                    description: e.iter()
                        .filter_map(|x| match *x {
                            internal::EndpointElement::Description(x) => Some(x.to_owned()),
                            _ => None
                        })
                        .nth(0),
                    returns: e.iter()
                        .filter_map(|x| match *x {
                            internal::EndpointElement::Returns(x) => Some(x.to_owned()),
                            _ => None
                        })
                        .nth(0),
                    params: e.iter()
                        .filter_map(|x| match *x {
                            internal::EndpointElement::Params(ref x) => Some(x),
                            _ => None
                        })
                        .nth(0)
                        .map(|params| params.iter()
                            .map(|x| Param {
                                kind: x.kind,
                                type_name_pairs: x.type_name_pairs.iter()
                                    .map(|x| {
                                        let name = if x.name.starts_with('@') { &x.name[1..] } else { x.name };
                                        TypeNamePair {
                                            param_type: x.param_type.to_owned(),
                                            name: name.to_owned()
                                        }
                                    })
                                    .collect(),
                                when: x.when.map(|x| x.to_owned()),
                            })
                            .collect()
                        )
                        .unwrap_or_else(Vec::new),
                }
            );
        }
    }

    Ok(ApiTemplate {
        namespace: namespace,
        description: description,
        endpoints: endpoints,
    })
}