<commit_before>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum QueryParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Filter {
    let filter_json = json.as_object().unwrap();
    let first_key = filter_json.keys().nth(0).unwrap();

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone())
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Filter::Prefix(first_key.clone(), value.to_owned())
    } else if first_key == "and" {
        Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "or" {
        Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f))
                               .collect::<Vec<_>>(),)
    } else if first_key == "not" {
        Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap())))
    } else {
        Filter::Term("not".to_owned(), Json::String("implemented".to_owned()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                let obj = doc.data.as_object().unwrap();

                for field in fields.iter() {
                    if let Some(field_value) = obj.get(field) {
                        let mut field_value = field_value.as_string().unwrap().to_lowercase();
                        let mut query = query.to_lowercase();

                        if field_value.contains(&query) {
                            return true;
                        }
                    }
                }

                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QueryParseError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QueryParseError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QueryParseError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QueryParseError::FilteredNoFilter));
    let filter = parse_filter(filter_json);

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QueryParseError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QueryParseError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoFilter))
    }
}
<commit_msg>Implement some filter parse errors<commit_after>use rustc_serialize::json::Json;

use super::Document;

#[derive(Debug, PartialEq)]
pub enum FilterParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownFilterType(String),
    NoFilter,
}

#[derive(Debug, PartialEq)]
pub enum Filter {
    Term(String, Json),
    Prefix(String, String),
    And(Vec<Filter>),
    Or(Vec<Filter>),
    Not(Box<Filter>),
}

#[derive(Debug, PartialEq)]
pub enum QueryParseError {
    ExpectedObject,
    ExpectedString,
    ExpectedArray,
    UnknownQueryType(String),
    NoQuery,
    FilteredNoFilter,
    FilteredNoQuery,
    FilterParseError(FilterParseError),
    MissingQueryString,
    MultiMatchMissingFields,
}

#[derive(Debug, PartialEq)]
pub enum Query {
    MatchAll,
    Match{field: String, query: String},
    MultiMatch{fields: Vec<String>, query: String},
    Filtered{query: Box<Query>, filter: Box<Filter>},
}

impl Filter {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Filter::Term(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    return field_value == value;
                }

                false
            }
            Filter::Prefix(ref field, ref value) => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    if let Json::String(ref field_value) = *field_value {
                        return field_value.starts_with(value);
                    }
                }

                false
            }
            Filter::And(ref filters) => {
                for filter in filters.iter() {
                    if !filter.matches(doc) {
                        return false;
                    }
                }

                true
            }
            Filter::Or(ref filters) => {
                for filter in filters.iter() {
                    if filter.matches(doc) {
                        return true;
                    }
                }

                false
            }
            Filter::Not(ref filter) => !filter.matches(doc),
        }
    }
}

pub fn parse_filter(json: &Json) -> Result<Filter, FilterParseError> {
    let filter_json = try!(json.as_object().ok_or(FilterParseError::ExpectedObject));
    let first_key = try!(filter_json.keys().nth(0).ok_or(FilterParseError::NoFilter));

    if first_key == "term" {
        let filter_json = filter_json.get("term").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();

        Ok(Filter::Term(first_key.clone(), filter_json.get(first_key).unwrap().clone()))
    } else if first_key == "prefix" {
        let filter_json = filter_json.get("prefix").unwrap().as_object().unwrap();
        let first_key = filter_json.keys().nth(0).unwrap();
        let value = filter_json.get(first_key).unwrap().as_string().unwrap();

        Ok(Filter::Prefix(first_key.clone(), value.to_owned()))
    } else if first_key == "and" {
        Ok(Filter::And(filter_json.get("and").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f).unwrap())
                               .collect::<Vec<_>>(),))
    } else if first_key == "or" {
        Ok(Filter::Or(filter_json.get("or").unwrap()
                               .as_array().unwrap()
                               .iter().map(|f| parse_filter(f).unwrap())
                               .collect::<Vec<_>>(),))
    } else if first_key == "not" {
        Ok(Filter::Not(Box::new(parse_filter(filter_json.get("not").unwrap()).unwrap())))
    } else {
        Err(FilterParseError::UnknownFilterType(first_key.clone()))
    }
}

impl Query {
    pub fn matches(&self, doc: &Document) -> bool {
        match *self {
            Query::MatchAll => true,
            Query::Match{ref field, ref query} => {
                let obj = doc.data.as_object().unwrap();

                if let Some(field_value) = obj.get(field) {
                    let mut field_value = field_value.as_string().unwrap().to_lowercase();
                    let mut query = query.to_lowercase();

                    return field_value.contains(&query);
                }

                false
            }
            Query::MultiMatch{ref fields, ref query} => {
                let obj = doc.data.as_object().unwrap();

                for field in fields.iter() {
                    if let Some(field_value) = obj.get(field) {
                        let mut field_value = field_value.as_string().unwrap().to_lowercase();
                        let mut query = query.to_lowercase();

                        if field_value.contains(&query) {
                            return true;
                        }
                    }
                }

                false
            }
            Query::Filtered{ref query, ref filter} => {
                if filter.matches(doc) {
                    query.matches(doc)
                } else {
                    false
                }
            }
        }
    }
}

pub fn parse_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    Ok(Query::Match {
        field: first_key.clone(),
        query: json_object.get(first_key).unwrap().as_string().unwrap().to_owned(),
    })
}

pub fn parse_multi_match_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    // Convert "fields" into a Vec<String>
    let fields_json = try!(json_object.get("fields").ok_or(QueryParseError::MultiMatchMissingFields));
    let fields = try!(fields_json.as_array().ok_or(QueryParseError::ExpectedArray))
                      .iter().map(|s| s.as_string().unwrap().to_owned())
                      .collect::<Vec<_>>();

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::MissingQueryString));
    let query = try!(query_json.as_string().ok_or(QueryParseError::ExpectedString)).to_owned();

    Ok(Query::MultiMatch {
        fields: fields,
        query: query,
    })
}

pub fn parse_filtered_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));

    let filter_json = try!(json_object.get("filter").ok_or(QueryParseError::FilteredNoFilter));
    let filter = match parse_filter(filter_json) {
        Ok(filter) => filter,
        Err(err) => return Err(QueryParseError::FilterParseError(err)),
    };

    let query_json = try!(json_object.get("query").ok_or(QueryParseError::FilteredNoQuery));
    let query = try!(parse_query(query_json));

    Ok(Query::Filtered {
        filter: Box::new(filter),
        query: Box::new(query),
    })
}

pub fn parse_query(json: &Json) -> Result<Query, QueryParseError> {
    let json_object = try!(json.as_object().ok_or(QueryParseError::ExpectedObject));
    let first_key = try!(json_object.keys().nth(0).ok_or(QueryParseError::NoQuery));

    if first_key == "match_all" {
        Ok(Query::MatchAll)
    } else if first_key == "match" {
        let inner_query = json_object.get("match").unwrap();
        Ok(try!(parse_match_query(inner_query)))
    } else if first_key == "multi_match" {
        let inner_query = json_object.get("multi_match").unwrap();
        Ok(try!(parse_multi_match_query(inner_query)))
    } else if first_key == "filtered" {
        let inner_query = json_object.get("filtered").unwrap();
        Ok(try!(parse_filtered_query(inner_query)))
    } else {
        Err(QueryParseError::UnknownQueryType(first_key.clone()))
    }
}

#[cfg(test)]
mod tests {
    use rustc_serialize::json::Json;
    use super::{Query, Filter, QueryParseError, parse_query};

    #[test]
    fn test_match_all_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match_all\": {}
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MatchAll))
    }

    #[test]
    fn test_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {
                    \"title\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Match{
            field: "title".to_owned(),
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_match_query_without_field() {
        let query = parse_query(&Json::from_str("
            {
                \"match\": {}
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::NoQuery))
    }

    #[test]
    fn test_multi_match_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"],
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::MultiMatch{
            fields: vec!["title".to_owned(), "body".to_owned()],
            query: "Hello world!".to_owned(),
        }))
    }

    #[test]
    fn test_multi_match_query_without_fields() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"query\": \"Hello world!\"
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MultiMatchMissingFields))
    }

    #[test]
    fn test_multi_match_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"multi_match\": {
                    \"fields\": [\"title\", \"body\"]
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::MissingQueryString))
    }

    #[test]
    fn test_filtered_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    },
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Ok(Query::Filtered{
            query: Box::new(Query::Match{
                field: "title".to_owned(),
                query: "Hello world!".to_owned(),
            }),
            filter: Box::new(Filter::Term(
                "date".to_owned(),
                Json::from_str("\"2016-01-25\"").unwrap(),
            ))
        }))
    }

    #[test]
    fn test_filtered_query_without_query() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"filter\": {
                        \"term\": {
                            \"date\": \"2016-01-25\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoQuery))
    }

    #[test]
    fn test_filtered_query_without_filter() {
        let query = parse_query(&Json::from_str("
            {
                \"filtered\": {
                    \"query\": {
                        \"match\": {
                            \"title\": \"Hello world!\"
                        }
                    }
                }
            }
        ").unwrap());

        assert_eq!(query, Err(QueryParseError::FilteredNoFilter))
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]
extern crate capnp;

use std::{error, fmt, str};

use index::Index;
use key_builder::KeyBuilder;
use stems::{StemmedWord, Stems};

// TODO vmx 2016-11-02: Make it import "rocksdb" properly instead of needing to import the individual tihngs
use rocksdb::{DBIterator, SeekKey};
use rocksdb::rocksdb::Snapshot;
use records_capnp::payload;

#[derive(Debug)]
enum Error<'a> {
    Parse(&'a str),
    Capnp(capnp::Error),
}

impl<'a> error::Error for Error<'a> {
    fn description(&self) -> &str {
        match *self {
            Error::Parse(description) => description,
            Error::Capnp(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Parse(_) => None,
            Error::Capnp(ref err) => Some(err as &error::Error),
        }
    }
}

impl<'a> From<capnp::Error> for Error<'a> {
    fn from(err: capnp::Error) -> Error<'a> {
        Error::Capnp(err)
    }
}

impl<'a> fmt::Display for Error<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parse(ref err) => write!(f, "Parse error: {}", err),
            Error::Capnp(ref err) => write!(f, "Capnproto error: {}", err),
        }
    }
}

struct DocResult {
    seq: u64,
    array_paths: Vec<Vec<u64>>,
}

impl DocResult {
    fn new() -> DocResult {
        DocResult {
            seq: 0,
            array_paths: Vec::new(),
        }
    }
}

//trait QueryRuntimeFilter {
//struct QueryRuntimeFilter {}

trait QueryRuntimeFilter {
    fn first_result<'a>(&'a mut self, start_id: u64) -> Result<Option<DocResult>, Error<'a>>;
    fn next_result<'a>(&'a mut self) -> Result<Option<DocResult>, Error<'a>>;
}

pub struct Query {}

pub struct QueryResults {
}

//struct SnapshotIteratorCreator {
//    snapshot: rocksdb::Snapshot,
//}
//
//impl SnapshotIteratorCreator {
//    fn new(db: &rocksdb::DB) {
//        let snapshot = rocksdb::Snapshot::new(db);
//        SnapshotIteratorCreator{
//            snapshot: snapshot,
//        }
//    }
//
//    fn new_iterator(&self) {
//        self.snapshot.iter()
//    }
//}

struct ExactMatchFilter<'a> {
    iter: DBIterator<'a>,
    kb: KeyBuilder,
    stemmed_offset: u64,
    suffix: String,
    suffix_offset: u64,
}

impl<'a> ExactMatchFilter<'a> {
    fn new(iter: DBIterator<'a>, stemmed_word: &StemmedWord, mut kb: KeyBuilder) -> ExactMatchFilter<'a> {
        kb.push_word(&stemmed_word.stemmed);
        ExactMatchFilter{
            iter: iter,
            kb: kb,
            stemmed_offset: stemmed_word.stemmed_offset as u64,
            suffix: stemmed_word.suffix.clone(),
            suffix_offset: stemmed_word.suffix_offset as u64,
        }
    }
}

impl<'a> QueryRuntimeFilter for ExactMatchFilter<'a> {
    fn first_result(&mut self, start_id: u64) -> Result<Option<DocResult>, Error> {
        // Build the full key
        self.kb.push_doc_seq(start_id);

        // Seek in index to >= entry
        self.iter.seek(SeekKey::from(self.kb.key().as_bytes()));

        // Revert
        self.kb.pop_doc_seq();

        self.next_result()
    }

    fn next_result(&mut self) -> Result<Option<DocResult>, Error> {
        let mut doc_result = DocResult::new();

        loop {
            if !self.iter.valid() {
                return Ok(None)
            }

            // New scope needed as the iter.next() below invalidates the
            // current key and value
            {
                let key = self.iter.key();
                if !key.starts_with(self.kb.key().as_bytes()) {
                    return Ok(None)
                }
                let seq = &key[self.kb.key().len()..];

                let value = self.iter.value();
                // NOTE vmx 2016-10-13: I'm not really sure why the dereferencing is needed
                // and why we pass on mutable reference of it to `read_message()`
                let mut ref_value = &*value;
                let message_reader = ::capnp::serialize_packed::read_message(
                    &mut ref_value, ::capnp::message::ReaderOptions::new()).unwrap();
                let payload = message_reader.get_root::<payload::Reader>().unwrap();

                for aos_wis in try!(payload.get_arrayoffsets_to_wordinfos()).iter() {
                    for wi in try!(aos_wis.get_wordinfos()).iter() {
                        if self.stemmed_offset == wi.get_stemmed_offset() &&
                            self.suffix_offset == wi.get_suffix_offset() &&
                            self.suffix == try!(wi.get_suffix_text()) {
                                // We have a candidate document to return
                                let arrayoffsets = try!(aos_wis.get_arrayoffsets());
                                doc_result.array_paths.push(arrayoffsets.iter().collect::<>());
                                doc_result.seq = str::from_utf8(&seq).unwrap().parse().unwrap();
                                break;
                            }
                    }
                }
            }
            self.iter.next();

            if doc_result.seq > 0 {
                return Ok(Some(doc_result));
            }
        }
    }
}

struct AndFilter {
    filters: Vec<Box<QueryRuntimeFilter>>,
    array_depth: u64,
}

impl AndFilter {
    fn new(filters: Vec<Box<QueryRuntimeFilter>>, array_depth: u64) -> AndFilter {
        AndFilter {
            filters: filters,
            array_depth: array_depth,
        }
   }
}

impl QueryRuntimeFilter for AndFilter {
    fn first_result(&mut self, start_id: u64) -> Result<Option<DocResult>, Error> {
        Ok(None)
    }
    fn next_result(&mut self) -> Result<Option<DocResult>, Error> {
        Ok(None)
    }
}

struct Parser<'a, 'b> {
    query: &'a str,
    offset: usize,
    kb: KeyBuilder,
    snapshot: &'b Snapshot<'b>,
}

impl<'a, 'b> Parser<'a, 'b> {
    fn new(query: &'a str, snapshot: &'b Snapshot) -> Parser<'a, 'b> {
        Parser{
            query: query,
            offset: 0,
            kb: KeyBuilder::new(),
            snapshot: snapshot,
        }
    }

    fn whitespace(&mut self) {
        loop {
            if let Some(char) = self.query[self.offset..].chars().next() {
                // Stop when the character isn't a whitespace
                if !char.is_whitespace() {
                    break;
                }
                self.offset += char.len_utf8();
            }
        }
    }

    fn consume(&mut self, token: &str) -> bool {
        if self.could_consume(token) {
            self.offset += token.len();
            true
        } else {
            false
        }
    }

    fn could_consume(&mut self, token: &str) -> bool {
        self.query[self.offset..].starts_with(token)
    }

    fn consume_field(&mut self) -> Option<String> {
        let mut result = String::new();
        for char in self.query[self.offset..].chars() {
            if char.is_alphanumeric() {
                result.push(char);
            } else {
                break;
            }
        }
        if result.len() > 0 {
            self.offset += result.len();
            self.whitespace();
            Some(result)
        } else {
            None
        }
    }

    fn consume_string_literal(&mut self) -> Result<Option<String>, String> {
        // Does not unescape yet
        let mut lit = String::new();
        if self.consume("\"") {
            for char in self.query[self.offset..].chars() {
                if char != '"' {
                    lit.push(char);
                }
                self.offset += char.len_utf8();
            }
            if self.consume("\"") {
                self.whitespace();
                Ok(Some(lit))
            } else {
                Err("Expected \"".to_string())
            }
        } else {
            Ok(None)
        }
    }

    fn compare(&mut self) -> Result<Box<QueryRuntimeFilter>, String> {
        match self.consume_field() {
            Some(field) => {
                if self.consume(".") {
                    self.kb.push_object_key(field);
                    let ret = self.compare();
                    self.kb.pop_object_key();
                    ret
                } else if self.consume("=") {
                    match self.consume_string_literal() {
                        Ok(Some(literal)) => {
                            self.kb.push_object_key(field);

                            let stems = Stems::new(&literal);
                            let mut filters: Vec<Box<QueryRuntimeFilter>> = Vec::new();
                            for stem in stems {
                                let iter = self.snapshot.iter();
                                let filter = Box::new(ExactMatchFilter::new(
                                   iter, &stem, self.kb.clone()));
                                filters.push(filter);
                            }

                            self.kb.pop_object_key();

                            match filters.len() {
                                0 => panic!("Cannot create a ExactMatchFilter"),
                                1 => Ok(filters[0]),
                                _ => Ok(Box::new(AndFilter::new(
                                    filters, self.kb.array_depth as u64))),
                                //_ => Ok(filters[0]),
                                //_ => Err("just get it compiled".to_string()),
                            }
                        },
                        // Empty literal
                        Ok(None) => {Err("not implemetned yet".to_string())},
                        Err(error) => {
                            Err(error)
                        }
                    }
                } else {
                    Err("not yet implemented".to_string())
                }
            },
            None => {
                Err("Expected comparison or array operator".to_string())
            }
        }
    }

    fn boolean<T: QueryRuntimeFilter>() -> Option<T> {

        None
    }

    fn build_filter(&mut self) -> Result<QueryResults, String> {
        self.whitespace();
        Ok(QueryResults{})
    }
}

impl Query {
    //pub fn get_matches<'a>(query: &str, index: &'a Index) -> Result<QueryResults, String> {
    pub fn get_matches<'a, 'b>(query: &str, snapshot: &'b Snapshot) -> Result<QueryResults, String> {
    //        match &index.rocks {
//            &Some(ref rocks) => {
//                let snapshot = Snapshot::new(rocks);
//                let parser = Parser::new(query, &snapshot);
//                Ok(QueryResults{})
//            },
//            &None => {
//                Err("You must open the index first".to_string())
//            },
//        }
        //let rocks = &index.rocks.unwrap();
        // This one would work as well
        //let rocks = index.rocks.as_ref().unwrap();
        //let snapshot = Snapshot::new(rocks);
        let parser = Parser::new(query, &snapshot);
        Ok(QueryResults{})
    }
}

#[cfg(test)]
mod tests {
    use super::Parser;

    use index::{Index, OpenOptions};

    use rocksdb::Snapshot;

    #[test]
    fn test_whitespace() {
        let mut index = Index::new();
        index.open("test_whitespace", Some(OpenOptions::Create)).unwrap();
        let rocks = &index.rocks.unwrap();
        let snapshot = Snapshot::new(rocks);

        let mut query = " \n \t test";
        let mut parser = Parser::new(query, &snapshot);
        parser.whitespace();
        assert_eq!(parser.offset, 5);

        query = "test";
        parser = Parser::new(query, &snapshot);
        parser.whitespace();
        assert_eq!(parser.offset, 0);
    }
}
<commit_msg>Lengthy battle with borrow checker<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]
extern crate capnp;

use std::{error, fmt, str};

use index::Index;
use key_builder::KeyBuilder;
use stems::{StemmedWord, Stems};

// TODO vmx 2016-11-02: Make it import "rocksdb" properly instead of needing to import the individual tihngs
use rocksdb::{DBIterator, SeekKey};
use rocksdb::rocksdb::Snapshot;
use records_capnp::payload;

#[derive(Debug)]
enum Error<'a> {
    Parse(&'a str),
    Capnp(capnp::Error),
}

impl<'a> error::Error for Error<'a> {
    fn description(&self) -> &str {
        match *self {
            Error::Parse(description) => description,
            Error::Capnp(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::Parse(_) => None,
            Error::Capnp(ref err) => Some(err as &error::Error),
        }
    }
}

impl<'a> From<capnp::Error> for Error<'a> {
    fn from(err: capnp::Error) -> Error<'a> {
        Error::Capnp(err)
    }
}

impl<'a> fmt::Display for Error<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Error::Parse(ref err) => write!(f, "Parse error: {}", err),
            Error::Capnp(ref err) => write!(f, "Capnproto error: {}", err),
        }
    }
}

struct DocResult {
    seq: u64,
    array_paths: Vec<Vec<u64>>,
}

impl DocResult {
    fn new() -> DocResult {
        DocResult {
            seq: 0,
            array_paths: Vec::new(),
        }
    }
}

//trait QueryRuntimeFilter {
//struct QueryRuntimeFilter {}

trait QueryRuntimeFilter {
    fn first_result(&mut self, start_id: u64) -> Result<Option<DocResult>, Error>;
    fn next_result(&mut self) -> Result<Option<DocResult>, Error>;
}

pub struct Query {}

pub struct QueryResults {
}

//struct SnapshotIteratorCreator {
//    snapshot: rocksdb::Snapshot,
//}
//
//impl SnapshotIteratorCreator {
//    fn new(db: &rocksdb::DB) {
//        let snapshot = rocksdb::Snapshot::new(db);
//        SnapshotIteratorCreator{
//            snapshot: snapshot,
//        }
//    }
//
//    fn new_iterator(&self) {
//        self.snapshot.iter()
//    }
//}

struct ExactMatchFilter<'a> {
    iter: DBIterator<'a>,
    kb: KeyBuilder,
    stemmed_offset: u64,
    suffix: String,
    suffix_offset: u64,
}

impl<'a> ExactMatchFilter<'a> {
    fn new(iter: DBIterator<'a>, stemmed_word: &StemmedWord, mut kb: KeyBuilder) -> ExactMatchFilter<'a> {
        kb.push_word(&stemmed_word.stemmed);
        ExactMatchFilter{
            iter: iter,
            kb: kb,
            stemmed_offset: stemmed_word.stemmed_offset as u64,
            suffix: stemmed_word.suffix.clone(),
            suffix_offset: stemmed_word.suffix_offset as u64,
        }
    }
}

impl<'a> QueryRuntimeFilter for ExactMatchFilter<'a> {
    fn first_result(&mut self, start_id: u64) -> Result<Option<DocResult>, Error> {
        // Build the full key
        self.kb.push_doc_seq(start_id);

        // Seek in index to >= entry
        self.iter.seek(SeekKey::from(self.kb.key().as_bytes()));

        // Revert
        self.kb.pop_doc_seq();

        self.next_result()
    }

    fn next_result(&mut self) -> Result<Option<DocResult>, Error> {
        let mut doc_result = DocResult::new();

        loop {
            if !self.iter.valid() {
                return Ok(None)
            }

            // New scope needed as the iter.next() below invalidates the
            // current key and value
            {
                let key = self.iter.key();
                if !key.starts_with(self.kb.key().as_bytes()) {
                    return Ok(None)
                }
                let seq = &key[self.kb.key().len()..];

                let value = self.iter.value();
                // NOTE vmx 2016-10-13: I'm not really sure why the dereferencing is needed
                // and why we pass on mutable reference of it to `read_message()`
                let mut ref_value = &*value;
                let message_reader = ::capnp::serialize_packed::read_message(
                    &mut ref_value, ::capnp::message::ReaderOptions::new()).unwrap();
                let payload = message_reader.get_root::<payload::Reader>().unwrap();

                for aos_wis in try!(payload.get_arrayoffsets_to_wordinfos()).iter() {
                    for wi in try!(aos_wis.get_wordinfos()).iter() {
                        if self.stemmed_offset == wi.get_stemmed_offset() &&
                            self.suffix_offset == wi.get_suffix_offset() &&
                            self.suffix == try!(wi.get_suffix_text()) {
                                // We have a candidate document to return
                                let arrayoffsets = try!(aos_wis.get_arrayoffsets());
                                doc_result.array_paths.push(arrayoffsets.iter().collect::<>());
                                doc_result.seq = str::from_utf8(&seq).unwrap().parse().unwrap();
                                break;
                            }
                    }
                }
            }
            self.iter.next();

            if doc_result.seq > 0 {
                return Ok(Some(doc_result));
            }
        }
    }
}

struct AndFilter<'a> {
    filters: Vec<Box<QueryRuntimeFilter + 'a>>,
    array_depth: u64,
}

impl<'a> AndFilter<'a> {
    fn new(filters: Vec<Box<QueryRuntimeFilter + 'a>>, array_depth: u64) -> AndFilter<'a> {
        AndFilter {
            filters: filters,
            array_depth: array_depth,
        }
   }
}

impl<'a> QueryRuntimeFilter for AndFilter<'a> {
    fn first_result(&mut self, start_id: u64) -> Result<Option<DocResult>, Error> {
        Ok(None)
    }
    fn next_result(&mut self) -> Result<Option<DocResult>, Error> {
        Ok(None)
    }
}

struct Parser<'a> {
    query: &'a str,
    offset: usize,
    kb: KeyBuilder,
    snapshot: &'a Snapshot<'a>,
}

impl<'a> Parser<'a> {
    fn new(query: &'a str, snapshot: &'a Snapshot<'a>) -> Parser<'a> {
        Parser{
            query: query,
            offset: 0,
            kb: KeyBuilder::new(),
            snapshot: &snapshot,
        }
    }

    fn whitespace(&mut self) {
        loop {
            if let Some(char) = self.query[self.offset..].chars().next() {
                // Stop when the character isn't a whitespace
                if !char.is_whitespace() {
                    break;
                }
                self.offset += char.len_utf8();
            }
        }
    }

    fn consume(&mut self, token: &str) -> bool {
        if self.could_consume(token) {
            self.offset += token.len();
            true
        } else {
            false
        }
    }

    fn could_consume(&mut self, token: &str) -> bool {
        self.query[self.offset..].starts_with(token)
    }

    fn consume_field(&mut self) -> Option<String> {
        let mut result = String::new();
        for char in self.query[self.offset..].chars() {
            if char.is_alphanumeric() {
                result.push(char);
            } else {
                break;
            }
        }
        if result.len() > 0 {
            self.offset += result.len();
            self.whitespace();
            Some(result)
        } else {
            None
        }
    }

    fn consume_string_literal(&mut self) -> Result<Option<String>, String> {
        // Does not unescape yet
        let mut lit = String::new();
        if self.consume("\"") {
            for char in self.query[self.offset..].chars() {
                if char != '"' {
                    lit.push(char);
                }
                self.offset += char.len_utf8();
            }
            if self.consume("\"") {
                self.whitespace();
                Ok(Some(lit))
            } else {
                Err("Expected \"".to_string())
            }
        } else {
            Ok(None)
        }
    }

    fn compare<'b>(&'b mut self) -> Result<Box<QueryRuntimeFilter + 'a>, String> {
        match self.consume_field() {
            Some(field) => {
                if self.consume(".") {
                    self.kb.push_object_key(field);
                    let ret = self.compare();
                    self.kb.pop_object_key();
                    ret
                } else if self.consume("=") {
                    match self.consume_string_literal() {
                        Ok(Some(literal)) => {
                            self.kb.push_object_key(field);

                            let stems = Stems::new(&literal);
                            let mut filters: Vec<Box<QueryRuntimeFilter + 'a>> = Vec::new();
                            for stem in stems {
                                let iter = self.snapshot.iter();
                                let filter = Box::new(ExactMatchFilter::new(
                                   iter, &stem, self.kb.clone()));
                                filters.push(filter);
                            }

                            self.kb.pop_object_key();

                            match filters.len() {
                                0 => panic!("Cannot create a ExactMatchFilter"),
                                1 => Ok(filters.pop().unwrap()),
                                _ => Ok(Box::new(AndFilter::<'a>::new(
                                    filters, self.kb.array_depth as u64))),
                                //_ => Ok(filters[0]),
                                //_ => Err("just get it compiled".to_string()),
                            }
                        },
                        // Empty literal
                        Ok(None) => {Err("not implemetned yet".to_string())},
                        Err(error) => {
                            Err(error)
                        }
                    }
                } else {
                    Err("not yet implemented".to_string())
                }
            },
            None => {
                Err("Expected comparison or array operator".to_string())
            }
        }
    }

    fn build_filter(&mut self) -> Result<QueryResults, String> {
        self.whitespace();
        Ok(QueryResults{})
    }
}

impl Query {
    //pub fn get_matches<'a>(query: &str, index: &'a Index) -> Result<QueryResults, String> {
    pub fn get_matches<'a>(query: &str, snapshot: &'a Snapshot) -> Result<QueryResults, String> {
    //        match &index.rocks {
//            &Some(ref rocks) => {
//                let snapshot = Snapshot::new(rocks);
//                let parser = Parser::new(query, &snapshot);
//                Ok(QueryResults{})
//            },
//            &None => {
//                Err("You must open the index first".to_string())
//            },
//        }
        //let rocks = &index.rocks.unwrap();
        // This one would work as well
        //let rocks = index.rocks.as_ref().unwrap();
        //let snapshot = Snapshot::new(rocks);
        let parser = Parser::new(query, &snapshot);
        Ok(QueryResults{})
    }
}

#[cfg(test)]
mod tests {
    use super::Parser;

    use index::{Index, OpenOptions};

    use rocksdb::Snapshot;

    #[test]
    fn test_whitespace() {
        let mut index = Index::new();
        index.open("test_whitespace", Some(OpenOptions::Create)).unwrap();
        let rocks = &index.rocks.unwrap();
        let snapshot = Snapshot::new(rocks);

        let mut query = " \n \t test";
        let mut parser = Parser::new(query, &snapshot);
        parser.whitespace();
        assert_eq!(parser.offset, 5);

        query = "test";
        parser = Parser::new(query, &snapshot);
        parser.whitespace();
        assert_eq!(parser.offset, 0);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![crate_name = "device"]
#![comment = "Back-ends to abstract over the differences between low-level, \
              platform-specific graphics APIs"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]
#![deny(missing_doc)]

//! Graphics device. Not meant for direct use.

#[phase(plugin, link)] extern crate log;
extern crate libc;

// when cargo is ready, re-enable the cfg's
/* #[cfg(gl)] */ pub use gl::GlDevice;
/* #[cfg(gl)] */ pub use back = self::gl;
/* #[cfg(gl)] */ pub use gl::DrawList;
// #[cfg(d3d11)] ... // TODO

use std::fmt;
use std::kinds::marker;
use std::mem::size_of;

pub mod attrib;
pub mod draw;
pub mod shade;
pub mod state;
pub mod target;
pub mod tex;
/* #[cfg(gl)] */ mod gl;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw index count.
pub type IndexCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// A generic handle struct
#[deriving(Clone, Show)]
pub struct Handle<T, I>(T, I);

#[deriving(Clone, Show)]
impl<T: Copy, I> Handle<T, I> {
    /// Get the internal name
    pub fn get_name(&self) -> T {
        let Handle(name, _) = *self;
        name
    }

    /// Get the info reference
    pub fn get_info(&self) -> &I {
        let Handle(_, ref info) = *self;
        info
    }
}

impl<T: Copy + PartialEq, I: PartialEq> PartialEq for Handle<T, I> {
    fn eq(&self, other: &Handle<T,I>) -> bool {
        self.get_name().eq(&other.get_name()) && self.get_info().eq(other.get_info())
    }
}

/// Buffer Handle
pub type BufferHandle  = Handle<back::Buffer, ()>;
/// Shader Handle
pub type ShaderHandle  = Handle<back::Shader, shade::Stage>;
/// Program Handle
pub type ProgramHandle = Handle<back::Program, shade::ProgramInfo>;
/// Surface Handle
pub type SurfaceHandle = Handle<back::Surface, tex::SurfaceInfo>;
/// Texture Handle
pub type TextureHandle = Handle<back::Texture, tex::TextureInfo>;
/// Sampler Handle
pub type SamplerHandle = Handle<back::Sampler, tex::SamplerInfo>;

/// A helper method to test `#[vertex_format]` without GL context
//#[cfg(test)]
pub fn make_fake_buffer() -> BufferHandle {
    Handle(0, ())
}

/// Features that the device supports.
#[deriving(Show)]
pub struct Capabilities {
    shader_model: shade::ShaderModel,
    max_draw_buffers : uint,
    max_texture_size : uint,
    max_vertex_attributes: uint,
    uniform_block_supported: bool,
    array_buffer_supported: bool,
    sampler_objects_supported: bool,
    immutable_storage_supported: bool,
}

/// A trait that slice-like types implement.
pub trait Blob {
    /// Get the address to the data this `Blob` stores.
    fn get_address(&self) -> uint;
    /// Get the number of bytes in this blob.
    fn get_size(&self) -> uint;
}

impl<T: Send> Blob for Vec<T> {
    fn get_address(&self) -> uint {
        self.as_ptr() as uint
    }
    fn get_size(&self) -> uint {
        self.len() * size_of::<T>()
    }
}

impl fmt::Show for Box<Blob + Send> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blob({:#x}, {})", self.get_address(), self.get_size())
    }
}

/// Describes what geometric primitives are created from vertex data.
#[deriving(Clone, PartialEq, Show)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[deriving(Clone, PartialEq, Show)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    UsageStatic,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    UsageDynamic,
    /// This buffer always or almost always be updated after each read.
    UsageStream,
}

/// Surface creation/update error.
#[deriving(Clone, PartialEq, Show)]
pub enum SurfaceError {
    /// Failed to map a given format to the device
    UnsupportedSurfaceFormat,
}

/// Texture creation/update error.
#[deriving(Clone, PartialEq, Show)]
pub enum TextureError {
    /// Failed to map a given format to the device
    UnsupportedTextureFormat,
}

/// Serialized device command.
/// While this is supposed to be an internal detail of a device,
/// this particular representation may be used by different backends,
/// such as OpenGL (prior to GLNG) and DirectX (prior to DX12)
#[allow(missing_doc)]
#[deriving(Show)]
enum Command {
    BindProgram(back::Program),
    BindArrayBuffer(back::ArrayBuffer),
    BindAttribute(AttributeSlot, back::Buffer, attrib::Count,
        attrib::Type, attrib::Stride, attrib::Offset),
    BindIndex(back::Buffer),
    BindFrameBuffer(back::FrameBuffer),
    /// Unbind any surface from the specified target slot
    UnbindTarget(target::Target),
    /// Bind a surface to the specified target slot
    BindTargetSurface(target::Target, back::Surface),
    /// Bind a level of the texture to the specified target slot
    BindTargetTexture(target::Target, back::Texture, target::Level, Option<target::Layer>),
    BindUniformBlock(back::Program, UniformBufferSlot, UniformBlockIndex, back::Buffer),
    BindUniform(shade::Location, shade::UniformValue),
    BindTexture(TextureSlot, tex::TextureKind, back::Texture, Option<SamplerHandle>),
    SetPrimitiveState(state::Primitive),
    SetViewport(target::Rect),
    SetScissor(Option<target::Rect>),
    SetDepthStencilState(Option<state::Depth>, Option<state::Stencil>, state::CullMode),
    SetBlendState(Option<state::Blend>),
    SetColorMask(state::ColorMask),
    UpdateBuffer(back::Buffer, Box<Blob + Send>),
    UpdateTexture(tex::TextureKind, back::Texture, tex::ImageInfo, Box<Blob + Send>),
    // drawing
    Clear(target::ClearData),
    Draw(PrimitiveType, VertexCount, VertexCount),
    DrawIndexed(PrimitiveType, IndexType, IndexCount, IndexCount),
}

/// An interface for performing draw calls using a specific graphics API
#[allow(missing_doc)]
pub trait Device<D> {
    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;
    // resource creation
    fn create_buffer(&mut self) -> BufferHandle;
    fn create_array_buffer(&mut self) -> Result<back::ArrayBuffer, ()>;
    fn create_shader(&mut self, stage: shade::Stage, code: shade::ShaderSource) ->
                     Result<ShaderHandle, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[ShaderHandle]) -> Result<ProgramHandle, ()>;
    fn create_frame_buffer(&mut self) -> back::FrameBuffer;
    fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result<SurfaceHandle, SurfaceError>;
    fn create_texture(&mut self, info: tex::TextureInfo) -> Result<TextureHandle, TextureError>;
    fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle;
    // resource deletion
    fn delete_buffer(&mut self, BufferHandle);
    fn delete_shader(&mut self, ShaderHandle);
    fn delete_program(&mut self, ProgramHandle);
    fn delete_surface(&mut self, SurfaceHandle);
    fn delete_texture(&mut self, TextureHandle);
    fn delete_sampler(&mut self, SamplerHandle);
    /// Update the information stored in a specific buffer
    fn update_buffer(&mut self, BufferHandle, &Blob, BufferUsage);
    /// Update the information stored in a texture
    fn update_texture(&mut self, &TextureHandle, &tex::ImageInfo, &Blob)
                      -> Result<(), TextureError>;
    /// Submit a draw list. TODO: enforce `draw::DrawList` trait here
    fn submit(&mut self, list: &D);
}

/// A trait that OpenGL contexts implement.
pub trait GraphicsContext<T> {
    /// Swap the front and back buffers, displaying what has been rendered.
    fn swap_buffers(&self);
    /// Make this context active on the calling thread.
    fn make_current(&self);
}
<commit_msg>Remove incorrect usage of apostrophe<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// 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.

#![crate_name = "device"]
#![comment = "Back-ends to abstract over the differences between low-level, \
              platform-specific graphics APIs"]
#![license = "ASL2"]
#![crate_type = "lib"]

#![feature(phase)]
#![deny(missing_doc)]

//! Graphics device. Not meant for direct use.

#[phase(plugin, link)] extern crate log;
extern crate libc;

// when cargo is ready, re-enable the cfgs
/* #[cfg(gl)] */ pub use gl::GlDevice;
/* #[cfg(gl)] */ pub use back = self::gl;
/* #[cfg(gl)] */ pub use gl::DrawList;
// #[cfg(d3d11)] ... // TODO

use std::fmt;
use std::kinds::marker;
use std::mem::size_of;

pub mod attrib;
pub mod draw;
pub mod shade;
pub mod state;
pub mod target;
pub mod tex;
/* #[cfg(gl)] */ mod gl;

/// Draw vertex count.
pub type VertexCount = u32;
/// Draw index count.
pub type IndexCount = u32;
/// Index of a uniform block.
pub type UniformBlockIndex = u8;
/// Slot for an attribute.
pub type AttributeSlot = u8;
/// Slot for a uniform buffer object.
pub type UniformBufferSlot = u8;
/// Slot a texture can be bound to.
pub type TextureSlot = u8;

/// A generic handle struct
#[deriving(Clone, Show)]
pub struct Handle<T, I>(T, I);

#[deriving(Clone, Show)]
impl<T: Copy, I> Handle<T, I> {
    /// Get the internal name
    pub fn get_name(&self) -> T {
        let Handle(name, _) = *self;
        name
    }

    /// Get the info reference
    pub fn get_info(&self) -> &I {
        let Handle(_, ref info) = *self;
        info
    }
}

impl<T: Copy + PartialEq, I: PartialEq> PartialEq for Handle<T, I> {
    fn eq(&self, other: &Handle<T,I>) -> bool {
        self.get_name().eq(&other.get_name()) && self.get_info().eq(other.get_info())
    }
}

/// Buffer Handle
pub type BufferHandle  = Handle<back::Buffer, ()>;
/// Shader Handle
pub type ShaderHandle  = Handle<back::Shader, shade::Stage>;
/// Program Handle
pub type ProgramHandle = Handle<back::Program, shade::ProgramInfo>;
/// Surface Handle
pub type SurfaceHandle = Handle<back::Surface, tex::SurfaceInfo>;
/// Texture Handle
pub type TextureHandle = Handle<back::Texture, tex::TextureInfo>;
/// Sampler Handle
pub type SamplerHandle = Handle<back::Sampler, tex::SamplerInfo>;

/// A helper method to test `#[vertex_format]` without GL context
//#[cfg(test)]
pub fn make_fake_buffer() -> BufferHandle {
    Handle(0, ())
}

/// Features that the device supports.
#[deriving(Show)]
pub struct Capabilities {
    shader_model: shade::ShaderModel,
    max_draw_buffers : uint,
    max_texture_size : uint,
    max_vertex_attributes: uint,
    uniform_block_supported: bool,
    array_buffer_supported: bool,
    sampler_objects_supported: bool,
    immutable_storage_supported: bool,
}

/// A trait that slice-like types implement.
pub trait Blob {
    /// Get the address to the data this `Blob` stores.
    fn get_address(&self) -> uint;
    /// Get the number of bytes in this blob.
    fn get_size(&self) -> uint;
}

impl<T: Send> Blob for Vec<T> {
    fn get_address(&self) -> uint {
        self.as_ptr() as uint
    }
    fn get_size(&self) -> uint {
        self.len() * size_of::<T>()
    }
}

impl fmt::Show for Box<Blob + Send> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Blob({:#x}, {})", self.get_address(), self.get_size())
    }
}

/// Describes what geometric primitives are created from vertex data.
#[deriving(Clone, PartialEq, Show)]
#[repr(u8)]
pub enum PrimitiveType {
    /// Each vertex represents a single point.
    Point,
    /// Each pair of vertices represent a single line segment. For example, with `[a, b, c, d,
    /// e]`, `a` and `b` form a line, `c` and `d` form a line, and `e` is discarded.
    Line,
    /// Every two consecutive vertices represent a single line segment. Visually forms a "path" of
    /// lines, as they are all connected. For example, with `[a, b, c]`, `a` and `b` form a line
    /// line, and `b` and `c` form a line.
    LineStrip,
    /// Each triplet of vertices represent a single triangle. For example, with `[a, b, c, d, e]`,
    /// `a`, `b`, and `c` form a triangle, `d` and `e` are discarded.
    TriangleList,
    /// Every three consecutive vertices represent a single triangle. For example, with `[a, b, c,
    /// d]`, `a`, `b`, and `c` form a triangle, and `b`, `c`, and `d` form a triangle.
    TriangleStrip,
    /// The first vertex with the last two are forming a triangle. For example, with `[a, b, c, d
    /// ]`, `a` , `b`, and `c` form a triangle, and `a`, `c`, and `d` form a triangle.
    TriangleFan,
    //Quad,
}

/// A type of each index value in the mesh's index buffer
pub type IndexType = attrib::IntSize;

/// A hint as to how this buffer will be used.
///
/// The nature of these hints make them very implementation specific. Different drivers on
/// different hardware will handle them differently. Only careful profiling will tell which is the
/// best to use for a specific buffer.
#[deriving(Clone, PartialEq, Show)]
#[repr(u8)]
pub enum BufferUsage {
    /// Once uploaded, this buffer will rarely change, but will be read from often.
    UsageStatic,
    /// This buffer will be updated "frequently", and will be read from multiple times between
    /// updates.
    UsageDynamic,
    /// This buffer always or almost always be updated after each read.
    UsageStream,
}

/// Surface creation/update error.
#[deriving(Clone, PartialEq, Show)]
pub enum SurfaceError {
    /// Failed to map a given format to the device
    UnsupportedSurfaceFormat,
}

/// Texture creation/update error.
#[deriving(Clone, PartialEq, Show)]
pub enum TextureError {
    /// Failed to map a given format to the device
    UnsupportedTextureFormat,
}

/// Serialized device command.
/// While this is supposed to be an internal detail of a device,
/// this particular representation may be used by different backends,
/// such as OpenGL (prior to GLNG) and DirectX (prior to DX12)
#[allow(missing_doc)]
#[deriving(Show)]
enum Command {
    BindProgram(back::Program),
    BindArrayBuffer(back::ArrayBuffer),
    BindAttribute(AttributeSlot, back::Buffer, attrib::Count,
        attrib::Type, attrib::Stride, attrib::Offset),
    BindIndex(back::Buffer),
    BindFrameBuffer(back::FrameBuffer),
    /// Unbind any surface from the specified target slot
    UnbindTarget(target::Target),
    /// Bind a surface to the specified target slot
    BindTargetSurface(target::Target, back::Surface),
    /// Bind a level of the texture to the specified target slot
    BindTargetTexture(target::Target, back::Texture, target::Level, Option<target::Layer>),
    BindUniformBlock(back::Program, UniformBufferSlot, UniformBlockIndex, back::Buffer),
    BindUniform(shade::Location, shade::UniformValue),
    BindTexture(TextureSlot, tex::TextureKind, back::Texture, Option<SamplerHandle>),
    SetPrimitiveState(state::Primitive),
    SetViewport(target::Rect),
    SetScissor(Option<target::Rect>),
    SetDepthStencilState(Option<state::Depth>, Option<state::Stencil>, state::CullMode),
    SetBlendState(Option<state::Blend>),
    SetColorMask(state::ColorMask),
    UpdateBuffer(back::Buffer, Box<Blob + Send>),
    UpdateTexture(tex::TextureKind, back::Texture, tex::ImageInfo, Box<Blob + Send>),
    // drawing
    Clear(target::ClearData),
    Draw(PrimitiveType, VertexCount, VertexCount),
    DrawIndexed(PrimitiveType, IndexType, IndexCount, IndexCount),
}

/// An interface for performing draw calls using a specific graphics API
#[allow(missing_doc)]
pub trait Device<D> {
    /// Returns the capabilities available to the specific API implementation
    fn get_capabilities<'a>(&'a self) -> &'a Capabilities;
    // resource creation
    fn create_buffer(&mut self) -> BufferHandle;
    fn create_array_buffer(&mut self) -> Result<back::ArrayBuffer, ()>;
    fn create_shader(&mut self, stage: shade::Stage, code: shade::ShaderSource) ->
                     Result<ShaderHandle, shade::CreateShaderError>;
    fn create_program(&mut self, shaders: &[ShaderHandle]) -> Result<ProgramHandle, ()>;
    fn create_frame_buffer(&mut self) -> back::FrameBuffer;
    fn create_surface(&mut self, info: tex::SurfaceInfo) -> Result<SurfaceHandle, SurfaceError>;
    fn create_texture(&mut self, info: tex::TextureInfo) -> Result<TextureHandle, TextureError>;
    fn create_sampler(&mut self, info: tex::SamplerInfo) -> SamplerHandle;
    // resource deletion
    fn delete_buffer(&mut self, BufferHandle);
    fn delete_shader(&mut self, ShaderHandle);
    fn delete_program(&mut self, ProgramHandle);
    fn delete_surface(&mut self, SurfaceHandle);
    fn delete_texture(&mut self, TextureHandle);
    fn delete_sampler(&mut self, SamplerHandle);
    /// Update the information stored in a specific buffer
    fn update_buffer(&mut self, BufferHandle, &Blob, BufferUsage);
    /// Update the information stored in a texture
    fn update_texture(&mut self, &TextureHandle, &tex::ImageInfo, &Blob)
                      -> Result<(), TextureError>;
    /// Submit a draw list. TODO: enforce `draw::DrawList` trait here
    fn submit(&mut self, list: &D);
}

/// A trait that OpenGL contexts implement.
pub trait GraphicsContext<T> {
    /// Swap the front and back buffers, displaying what has been rendered.
    fn swap_buffers(&self);
    /// Make this context active on the calling thread.
    fn make_current(&self);
}
<|endoftext|>


<commit_before>#![crate_name = "od"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Hirsch <benhirsch24@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate collections;

use collections::string::String;
use std::io::File;

#[deriving(Show)]
enum Radix { Decimal, Hexadecimal, Octal, Binary }

pub fn uumain(args: Vec<String>) -> isize {
   let opts = [
      getopts::optopt("A", "address-radix", "Select the base in which file offsets are printed.", "RADIX"),
      getopts::optopt("j", "skip-bytes", "Skip bytes input bytes before formatting and writing.", "BYTES"),
      getopts::optopt("N", "read-bytes", "limit dump to BYTES input bytes", "BYTES"),
      getopts::optopt("S", "strings", "output strings of at least BYTES graphic chars. 3 is assumed when BYTES is not specified.", "BYTES"),
      getopts::optopt("t", "format", "select output format or formats", "TYPE"),
      getopts::optflag("v", "output-duplicates", "do not use * to mark line suppression"),
      getopts::optopt("w", "width", "output BYTES bytes per output line. 32 is implied when BYTES is not specified.", "BYTES"),
      getopts::optflag("h", "help", "display this help and exit."),
      getopts::optflag("v", "version", "output version information and exit."),
   ];

   let matches = match getopts::getopts(args.tail(), &opts) {
      Ok(m) => m,
      Err(f) => panic!("Invalid options\n{}", f)
   };

   let mut rad = Radix::Octal;
   if matches.opt_present("A") {
      rad = parse_radix(matches.opt_str("A"));
   } else {
      println!("{}", getopts::usage("od", &opts));
   }

   let mut fname;
   match args.last() {
      Some(n) => fname = n,
      None    => { panic!("Need fname for now") ; }
   };

   main(rad, fname.clone());

   0
}

fn main(radix: Radix, fname: String) {
   let mut f = match File::open(&Path::new(fname)) {
      Ok(f) => f,
      Err(e) => panic!("file error: {}", e)
   };

   let mut addr = 0;
   let bytes = &mut [b'\x00'; 16];
   loop {
      match f.read(bytes) {
         Ok(n) => {
            print!("{:07o}", addr);
            match radix {
               Radix::Decimal => {
               },
               Radix::Octal => {
                  for b in range(0, n/std::u16::BYTES) {
                     let bs = bytes.slice(2*b, 2*b+2);
                     let p: u16 = (bs[1] as u16) << 8 | bs[0] as u16;
                     print!(" {:06o}", p);
                  }
                  if n % std::u16::BYTES == 1 {
                     print!(" {:06o}", bytes[n-1]);
                  }
               }
               _ => { }
            };
            print!("\n");
            addr += n;
         },
         Err(_) => { println!("{:07o}", addr); break; }
      };
   };
}

fn parse_radix(radix_str: Option<String>) -> Radix {
   let rad = match radix_str {
      Some(s) => {
         let st = s.into_bytes();
         if st.len() != 1 {
            panic!("Radix must be one of [d, o, b, x]\n");
         }

         let radix: char = *(st.get(0).expect("byte string of length 1 lacks a 0th elem")) as char;
         if radix == 'd' {
            Radix::Decimal
         } else if radix == 'x' {
            Radix::Hexadecimal
         } else if radix == 'o' {
            Radix::Octal
         } else if radix == 'b' {
            Radix::Binary
         } else {
            panic!("Radix must be one of [d, o, b, x]\n");
         }
      },
      None => Radix::Octal
   };

   rad
}
<commit_msg>od: whitespace fix (4-space indents, 99-column)<commit_after>#![crate_name = "od"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Ben Hirsch <benhirsch24@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate collections;

use collections::string::String;
use std::io::File;

#[deriving(Show)]
enum Radix { Decimal, Hexadecimal, Octal, Binary }

pub fn uumain(args: Vec<String>) -> isize {
    let opts = [
        getopts::optopt("A", "address-radix",
                        "Select the base in which file offsets are printed.", "RADIX"),
        getopts::optopt("j", "skip-bytes",
                        "Skip bytes input bytes before formatting and writing.", "BYTES"),
        getopts::optopt("N", "read-bytes",
                        "limit dump to BYTES input bytes", "BYTES"),
        getopts::optopt("S", "strings",
                        ("output strings of at least BYTES graphic chars. 3 is assumed when \
                          BYTES is not specified."),
                        "BYTES"),
        getopts::optopt("t", "format", "select output format or formats", "TYPE"),
        getopts::optflag("v", "output-duplicates", "do not use * to mark line suppression"),
        getopts::optopt("w", "width",
                        ("output BYTES bytes per output line. 32 is implied when BYTES is not \
                          specified."),
                        "BYTES"),
        getopts::optflag("h", "help", "display this help and exit."),
        getopts::optflag("v", "version", "output version information and exit."),
        ];

    let matches = match getopts::getopts(args.tail(), &opts) {
        Ok(m) => m,
        Err(f) => panic!("Invalid options\n{}", f)
    };

    let mut rad = Radix::Octal;
    if matches.opt_present("A") {
        rad = parse_radix(matches.opt_str("A"));
    } else {
        println!("{}", getopts::usage("od", &opts));
    }

    let mut fname;
    match args.last() {
        Some(n) => fname = n,
        None    => { panic!("Need fname for now") ; }
    };

    main(rad, fname.clone());

    0
}

fn main(radix: Radix, fname: String) {
    let mut f = match File::open(&Path::new(fname)) {
        Ok(f) => f,
        Err(e) => panic!("file error: {}", e)
    };

    let mut addr = 0;
    let bytes = &mut [b'\x00'; 16];
    loop {
        match f.read(bytes) {
            Ok(n) => {
                print!("{:07o}", addr);
                match radix {
                    Radix::Decimal => {
                    },
                    Radix::Octal => {
                        for b in range(0, n/std::u16::BYTES) {
                            let bs = bytes.slice(2*b, 2*b+2);
                            let p: u16 = (bs[1] as u16) << 8 | bs[0] as u16;
                            print!(" {:06o}", p);
                        }
                        if n % std::u16::BYTES == 1 {
                            print!(" {:06o}", bytes[n-1]);
                        }
                    }
                    _ => { }
                };
                print!("\n");
                addr += n;
            },
            Err(_) => { println!("{:07o}", addr); break; }
        };
    };
}

fn parse_radix(radix_str: Option<String>) -> Radix {
    let rad = match radix_str {
        Some(s) => {
            let st = s.into_bytes();
            if st.len() != 1 {
                panic!("Radix must be one of [d, o, b, x]\n");
            }

            let radix: char = *(st.get(0)
                                .expect("byte string of length 1 lacks a 0th elem")) as char;
            if radix == 'd' {
                Radix::Decimal
            } else if radix == 'x' {
                Radix::Hexadecimal
            } else if radix == 'o' {
                Radix::Octal
            } else if radix == 'b' {
                Radix::Binary
            } else {
                panic!("Radix must be one of [d, o, b, x]\n");
            }
        },
        None => Radix::Octal
    };

    rad
}
<|endoftext|>


<commit_before>//!
//! A reply is passed to filesystem operation implementations and must
//! be used to send back the result of an operation.
//! The reply can optionally be sent to another task to asynchronously
//! work on an operation and provide the result later. Also it allows
//! replying with a block of data without cloning the data.
//! A reply *must always* be used (by calling either ok() or error()
//! exactly once).
//!

use std::mem;
use std::libc::{c_int, EIO};
use channel::ChannelSender;
use fuse::fuse_out_header;
use sendable::Sendable;

/// Create a new reply for the given request
pub fn reply<T: Sendable> (ch: ChannelSender, unique: u64) -> Reply<T> {
	Reply::new(ch, unique)
}

/// Reply data structure
pub struct Reply<T> {
	/// Channel sender for sending the reply
	priv ch: ChannelSender,
	/// Unique id of the request to reply to
	priv unique: u64,
	/// Flag whether the reply was sent
	priv replied: bool,
}

impl<T: Sendable> Reply<T> {
	/// Create a new reply for the given request
	fn new (ch: ChannelSender, unique: u64) -> Reply<T> {
		Reply { ch: ch, unique: unique, replied: false }
	}

	/// Reply to a request with the given error code and data
	fn send<T: Sendable> (&mut self, err: c_int, data: &T) {
		if self.replied {
			warn!("Ignoring duplicate reply for operation {:u}", self.unique);
			return;
		}
		data.as_bytegroups(|databytes| {
			let datalen = databytes.iter().fold(0, |l, b| { l +  b.len()});
			let outheader = fuse_out_header {
				len: mem::size_of::<fuse_out_header>() as u32 + datalen as u32,
				error: err,
				unique: self.unique,
			};
			outheader.as_bytegroups(|headbytes| {
				let _ = self.ch.send(headbytes + databytes);
				self.replied = true;
			});
		});
	}

	/// Reply to a request with the given data
	pub fn ok (mut self, data: &T) {
		self.send(0, data);
	}

	/// Reply to a request with the given error code
	pub fn error (mut self, err: c_int) {
		self.send(-err, &());
	}
}

#[unsafe_destructor]
impl<T: Sendable> Drop for Reply<T> {
	fn drop (&mut self) {
		if !self.replied {
			warn!("Reply not sent for operation {:u}, replying with I/O error", self.unique);
			self.send(-EIO, &());
		}
	}
}
<commit_msg>Refactor reply send method to be type-independent<commit_after>//!
//! A reply is passed to filesystem operation implementations and must
//! be used to send back the result of an operation.
//! The reply can optionally be sent to another task to asynchronously
//! work on an operation and provide the result later. Also it allows
//! replying with a block of data without cloning the data.
//! A reply *must always* be used (by calling either ok() or error()
//! exactly once).
//!

use std::mem;
use std::libc::{c_int, EIO};
use channel::ChannelSender;
use fuse::fuse_out_header;
use sendable::Sendable;

/// Create a new reply for the given request
pub fn reply<T: Sendable> (ch: ChannelSender, unique: u64) -> Reply<T> {
	Reply::new(ch, unique)
}

/// Reply data structure
pub struct Reply<T> {
	/// Channel sender for sending the reply
	priv ch: ChannelSender,
	/// Unique id of the request to reply to
	priv unique: u64,
	/// Flag whether the reply was sent
	priv replied: bool,
}

impl<T: Sendable> Reply<T> {
	/// Create a new reply for the given request
	fn new (ch: ChannelSender, unique: u64) -> Reply<T> {
		Reply { ch: ch, unique: unique, replied: false }
	}

	/// Reply to a request with the given error code and data
	fn send (&mut self, err: c_int, bytes: &[&[u8]]) {
		if self.replied {
			warn!("Ignoring duplicate reply for operation {:u}", self.unique);
			return;
		}
		let len = bytes.iter().fold(0, |l, b| { l +  b.len()});
		let outheader = fuse_out_header {
			len: mem::size_of::<fuse_out_header>() as u32 + len as u32,
			error: err,
			unique: self.unique,
		};
		outheader.as_bytegroups(|headbytes| {
			let _ = self.ch.send(headbytes + bytes);
			self.replied = true;
		});
	}

	/// Reply to a request with the given data
	pub fn ok (mut self, data: &T) {
		data.as_bytegroups(|bytes| {
			self.send(0, bytes);
		});
	}

	/// Reply to a request with the given error code
	pub fn error (mut self, err: c_int) {
		self.send(-err, []);
	}
}

#[unsafe_destructor]
impl<T: Sendable> Drop for Reply<T> {
	fn drop (&mut self) {
		if !self.replied {
			warn!("Reply not sent for operation {:u}, replying with I/O error", self.unique);
			self.send(-EIO, []);
		}
	}
}
<|endoftext|>