<commit_before>use std::path::PathBuf;
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{BufReader, BufWriter};
use bincode::{deserialize_from, serialize_into, Infinite};

use errors::*;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Bookmark {
    pub name: String,
    pub directory: PathBuf,
    pub created_at: u64,
    pub updated_at: u64,
    pub last_access: Option<u64>,
    pub count: i64,
}

pub type Bookmarks = BTreeMap<String, Bookmark>;

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        let timestamp = ::now();

        Bookmark {
            name: name,
            directory: directory,
            created_at: timestamp,
            updated_at: timestamp,
            last_access: None,
            count: 0,
        }
    }
}

#[derive(Debug)]
pub struct Database {
    pub location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    pub fn open(mut path: PathBuf) -> Result<Database> {
        if !path.ends_with("db") {
            path.push("db");
        }

        let bookmarks = match File::open(&path) {
            Ok(file) => try!(hydrate(file)),
            Err(ref err) if notfound(err) => Bookmarks::new(),
            Err(_) => bail!(ErrorKind::DBOpenError(path)),
        };

        let db = Database::new(path, bookmarks);
        Ok(db)
    }

    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn get(&self, key: &str) -> Option<&Bookmark> {
        self.bookmarks.get(key)
    }

    pub fn get_path(&mut self, key: &str) -> Result<PathBuf> {
        let path: PathBuf;
        match self.bookmarks.get_mut(key) {
            Some(bookmark) => {
                bookmark.last_access = Some(::now());
                path = bookmark.directory.clone();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key.to_string())),
        };

        try!(self.close());
        Ok(path)
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(&mut self, key: String, value: PathBuf) -> Result<()> {
        if self.bookmarks.contains_key(&key) {
            self.update(key, value)
        } else {
            self.create(key, value)
        }
    }

    pub fn delete(&mut self, key: String) -> Result<()> {
        if self.bookmarks.remove(&key).is_none() {
            bail!(ErrorKind::BookmarkNotFound(key));
        }

        try!(self.close());
        Ok(())
    }

    fn update(&mut self, key: String, path: PathBuf) -> Result<()> {
        match self.bookmarks.get_mut(&key) {
            Some(bookmark) => {
                bookmark.directory = path;
                bookmark.updated_at = ::now();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key)),
        }

        try!(self.close());
        Ok(())
    }

    fn create(&mut self, key: String, value: PathBuf) -> Result<()> {
        let bookmark = Bookmark::new(key.clone(), value);
        self.bookmarks.insert(key, bookmark);

        try!(self.close());
        Ok(())
    }

    pub fn list(&self) -> Iter<String, Bookmark> {
        self.bookmarks.iter()
    }

    fn close(&self) -> Result<()> {
        let path = PathBuf::from(&self.location);

        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .chain_err(|| ErrorKind::DBOpenError(path))?;

        try!(dehydrate(file, &self.bookmarks));
        Ok(())
    }
}

fn notfound(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::NotFound
}

fn hydrate(file: File) -> Result<Bookmarks> {
    let mut reader = BufReader::new(file);
    let bookmarks: Bookmarks = try!(deserialize_from(&mut reader, Infinite));
    Ok(bookmarks)
}

fn dehydrate(file: File, bookmarks: &Bookmarks) -> Result<()> {
    let mut writer = BufWriter::new(file);

    try!(serialize_into(&mut writer, &bookmarks, Infinite));
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::{Bookmark};
    use std::path::PathBuf;

    #[test]
    fn bookmark_values() {
        let name = String::from("hello");
        let path = PathBuf::from("/tmp/hello");
        let bookmark = Bookmark::new(name, path);

        assert_eq!(bookmark.name, String::from("hello"));
        assert_eq!(bookmark.directory, PathBuf::from("/tmp/hello"));
        assert!(bookmark.last_access.is_none());
        assert_eq!(bookmark.count, 0);
    }
}
<commit_msg>cargo fmt<commit_after>use std::path::PathBuf;
use std::collections::BTreeMap;
use std::collections::btree_map::Iter;
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{BufReader, BufWriter};
use bincode::{deserialize_from, serialize_into, Infinite};

use errors::*;

#[derive(Serialize, Deserialize, PartialEq, Debug)]
pub struct Bookmark {
    pub name: String,
    pub directory: PathBuf,
    pub created_at: u64,
    pub updated_at: u64,
    pub last_access: Option<u64>,
    pub count: i64,
}

pub type Bookmarks = BTreeMap<String, Bookmark>;

impl Bookmark {
    pub fn new(name: String, directory: PathBuf) -> Bookmark {
        let timestamp = ::now();

        Bookmark {
            name: name,
            directory: directory,
            created_at: timestamp,
            updated_at: timestamp,
            last_access: None,
            count: 0,
        }
    }
}

#[derive(Debug)]
pub struct Database {
    pub location: PathBuf,
    bookmarks: Bookmarks,
}

impl Database {
    pub fn open(mut path: PathBuf) -> Result<Database> {
        if !path.ends_with("db") {
            path.push("db");
        }

        let bookmarks = match File::open(&path) {
            Ok(file) => try!(hydrate(file)),
            Err(ref err) if notfound(err) => Bookmarks::new(),
            Err(_) => bail!(ErrorKind::DBOpenError(path)),
        };

        let db = Database::new(path, bookmarks);
        Ok(db)
    }

    fn new(location: PathBuf, bookmarks: Bookmarks) -> Database {
        Database {
            location: location,
            bookmarks: bookmarks,
        }
    }

    pub fn get(&self, key: &str) -> Option<&Bookmark> {
        self.bookmarks.get(key)
    }

    pub fn get_path(&mut self, key: &str) -> Result<PathBuf> {
        let path: PathBuf;
        match self.bookmarks.get_mut(key) {
            Some(bookmark) => {
                bookmark.last_access = Some(::now());
                path = bookmark.directory.clone();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key.to_string())),
        };

        try!(self.close());
        Ok(path)
    }

    // TODO: add a check to verify the db is open.
    // TODO: add check to verify value is a valid directory.
    pub fn put(&mut self, key: String, value: PathBuf) -> Result<()> {
        if self.bookmarks.contains_key(&key) {
            self.update(key, value)
        } else {
            self.create(key, value)
        }
    }

    pub fn delete(&mut self, key: String) -> Result<()> {
        if self.bookmarks.remove(&key).is_none() {
            bail!(ErrorKind::BookmarkNotFound(key));
        }

        try!(self.close());
        Ok(())
    }

    fn update(&mut self, key: String, path: PathBuf) -> Result<()> {
        match self.bookmarks.get_mut(&key) {
            Some(bookmark) => {
                bookmark.directory = path;
                bookmark.updated_at = ::now();
            }
            None => bail!(ErrorKind::BookmarkNotFound(key)),
        }

        try!(self.close());
        Ok(())
    }

    fn create(&mut self, key: String, value: PathBuf) -> Result<()> {
        let bookmark = Bookmark::new(key.clone(), value);
        self.bookmarks.insert(key, bookmark);

        try!(self.close());
        Ok(())
    }

    pub fn list(&self) -> Iter<String, Bookmark> {
        self.bookmarks.iter()
    }

    fn close(&self) -> Result<()> {
        let path = PathBuf::from(&self.location);

        let file = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open(&path)
            .chain_err(|| ErrorKind::DBOpenError(path))?;

        try!(dehydrate(file, &self.bookmarks));
        Ok(())
    }
}

fn notfound(err: &io::Error) -> bool {
    err.kind() == io::ErrorKind::NotFound
}

fn hydrate(file: File) -> Result<Bookmarks> {
    let mut reader = BufReader::new(file);
    let bookmarks: Bookmarks = try!(deserialize_from(&mut reader, Infinite));
    Ok(bookmarks)
}

fn dehydrate(file: File, bookmarks: &Bookmarks) -> Result<()> {
    let mut writer = BufWriter::new(file);

    try!(serialize_into(&mut writer, &bookmarks, Infinite));
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::Bookmark;
    use std::path::PathBuf;

    #[test]
    fn bookmark_values() {
        let name = String::from("hello");
        let path = PathBuf::from("/tmp/hello");
        let bookmark = Bookmark::new(name, path);

        assert_eq!(bookmark.name, String::from("hello"));
        assert_eq!(bookmark.directory, PathBuf::from("/tmp/hello"));
        assert!(bookmark.last_access.is_none());
        assert_eq!(bookmark.count, 0);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str;

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, NonRelativeSchemeData};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    // NB: we don't spawn a new task.
    // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
    // Should be tested at some point.
    // Left in separate function to allow easy moving to a task, if desired.
    load(load_data, start_chan)
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        NonRelativeSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = parts[0];
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts[1].as_bytes());

    if is_base64 {
        // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
        // but Acid 3 apparently depends on spaces being ignored.
        let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
        // FIXME(#2877): use bytes.as_slice().from_base64() when we upgrade to a Rust version
        // that includes https://github.com/rust-lang/rust/pull/15810
        let fake_utf8 = unsafe { str::raw::from_utf8(bytes.as_slice()) };
        match fake_utf8.from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<commit_msg>Call from_base64 on a vector slice rather than a string slice (fixes #2877).<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::str;

use resource_task::{Done, Payload, Metadata, LoadData, LoadResponse, start_sending};

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use url::{percent_decode, NonRelativeSchemeData};

pub fn factory(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    // NB: we don't spawn a new task.
    // Hypothesis: data URLs are too small for parallel base64 etc. to be worth it.
    // Should be tested at some point.
    // Left in separate function to allow easy moving to a task, if desired.
    load(load_data, start_chan)
}

fn load(load_data: LoadData, start_chan: Sender<LoadResponse>) {
    let url = load_data.url;
    assert!("data" == url.scheme.as_slice());

    let mut metadata = Metadata::default(url.clone());

    // Split out content type and data.
    let mut scheme_data = match url.scheme_data {
        NonRelativeSchemeData(scheme_data) => scheme_data,
        _ => fail!("Expected a non-relative scheme URL.")
    };
    match url.query {
        Some(query) => {
            scheme_data.push_str("?");
            scheme_data.push_str(query.as_slice());
        },
        None => ()
    }
    let parts: Vec<&str> = scheme_data.as_slice().splitn(',', 1).collect();
    if parts.len() != 2 {
        start_sending(start_chan, metadata).send(Done(Err("invalid data uri".to_string())));
        return;
    }

    // ";base64" must come at the end of the content type, per RFC 2397.
    // rust-http will fail to parse it because there's no =value part.
    let mut is_base64 = false;
    let mut ct_str = parts[0];
    if ct_str.ends_with(";base64") {
        is_base64 = true;
        ct_str = ct_str.slice_to(ct_str.as_bytes().len() - 7);
    }

    // Parse the content type using rust-http.
    // FIXME: this can go into an infinite loop! (rust-http #25)
    let content_type: Option<MediaType> = from_stream_with_str(ct_str);
    metadata.set_content_type(&content_type);

    let progress_chan = start_sending(start_chan, metadata);
    let bytes = percent_decode(parts[1].as_bytes());

    if is_base64 {
        // FIXME(#2909): It’s unclear what to do with non-alphabet characters,
        // but Acid 3 apparently depends on spaces being ignored.
        let bytes = bytes.move_iter().filter(|&b| b != ' ' as u8).collect::<Vec<u8>>();
        match bytes.as_slice().from_base64() {
            Err(..) => {
                progress_chan.send(Done(Err("non-base64 data uri".to_string())));
            }
            Ok(data) => {
                progress_chan.send(Payload(data));
                progress_chan.send(Done(Ok(())));
            }
        }
    } else {
        progress_chan.send(Payload(bytes));
        progress_chan.send(Done(Ok(())));
    }
}

#[cfg(test)]
fn assert_parse(url:          &'static str,
                content_type: Option<(String, String)>,
                charset:      Option<String>,
                data:         Option<Vec<u8>>) {
    use std::comm;
    use url::Url;

    let (start_chan, start_port) = comm::channel();
    load(LoadData::new(Url::parse(url).unwrap()), start_chan);

    let response = start_port.recv();
    assert_eq!(&response.metadata.content_type, &content_type);
    assert_eq!(&response.metadata.charset,      &charset);

    let progress = response.progress_port.recv();

    match data {
        None => {
            assert_eq!(progress, Done(Err("invalid data uri".to_string())));
        }
        Some(dat) => {
            assert_eq!(progress, Payload(dat));
            assert_eq!(response.progress_port.recv(), Done(Ok(())));
        }
    }
}

#[test]
fn empty_invalid() {
    assert_parse("data:", None, None, None);
}

#[test]
fn plain() {
    assert_parse("data:,hello%20world", None, None, Some(b"hello world".iter().map(|&x| x).collect()));
}

#[test]
fn plain_ct() {
    assert_parse("data:text/plain,hello",
        Some(("text".to_string(), "plain".to_string())), None, Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn plain_charset() {
    assert_parse("data:text/plain;charset=latin1,hello",
        Some(("text".to_string(), "plain".to_string())), Some("latin1".to_string()), Some(b"hello".iter().map(|&x| x).collect()));
}

#[test]
fn base64() {
    assert_parse("data:;base64,C62+7w==", None, None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_ct() {
    assert_parse("data:application/octet-stream;base64,C62+7w==",
        Some(("application".to_string(), "octet-stream".to_string())), None, Some(vec!(0x0B, 0xAD, 0xBE, 0xEF)));
}

#[test]
fn base64_charset() {
    assert_parse("data:text/plain;charset=koi8-r;base64,8PLl9+XkIO3l5Pfl5A==",
        Some(("text".to_string(), "plain".to_string())), Some("koi8-r".to_string()),
        Some(vec!(0xF0, 0xF2, 0xE5, 0xF7, 0xE5, 0xE4, 0x20, 0xED, 0xE5, 0xE4, 0xF7, 0xE5, 0xE4)));
}
<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_name="zinc"]
#![crate_type="rlib"]
#![allow(improper_ctypes)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

#[phase(plugin,link)] extern crate core;
#[cfg(not(test))] extern crate rlibc;

#[cfg(test)] #[phase(plugin,link)] extern crate std;
#[phase(plugin)] extern crate ioreg;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
pub mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
  pub use core::kinds;
}
<commit_msg>Supported MCU list update<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

#![feature(globs, macro_rules, asm, phase, unsafe_destructor, lang_items)]
#![crate_name="zinc"]
#![crate_type="rlib"]
#![allow(improper_ctypes)]
#![deny(missing_docs)]
#![no_std]

/*!
Zinc is an embedded stack for rust.

Zinc provides a complete embedded stack for application development in rust. It
is provided in a form of library, compiled for a specific MCU, that can be
linked into user's own applications.

### Supported architectures

ARM is the only architecture, supported at the moment. Zinc can be compiled for
"native" architecture as well, which should be useful only for testing the code,
though.

### Supported ARM MCUs

Two MCUs are supported at the moment, specifically

 * NXP LPC1768
 * ST STM32F407
 * ST STM32L152RCT6
 * Freescale MK20DX32
 * TI TM4C123GXL

The code is generic enough to support other MCUs in the same family (LPC17xx and
STM32F403/407).
*/

#[phase(plugin,link)] extern crate core;
#[cfg(not(test))] extern crate rlibc;

#[cfg(test)] #[phase(plugin,link)] extern crate std;
#[phase(plugin)] extern crate ioreg;

pub mod drivers;
pub mod hal;
pub mod util;
pub mod os;

/// Export a subset of `core` as `std.
///
/// This is exported as a temporary convenience as `rustc` still looks
/// for some items in the `std` namespace.
///
/// TODO(farcaller): clean up when fixed.
#[cfg(not(test))]
pub mod std {
  pub use core::cmp;  // used for #[deriving(Eq)] until fixed in rust.
  pub use core::option;
  pub use core::num;
  pub use core::kinds;
}
<|endoftext|>


<commit_before>extern crate libc;

pub mod tcl;
<commit_msg>Turned off warnings for bindgen items<commit_after>#![allow(raw_pointer_derive, non_snake_case, non_camel_case_types, missing_copy_implementations)]
#![feature(libc)]
extern crate libc;

pub mod tcl;
<|endoftext|>


<commit_before>use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray {
    ptr: FfiTypeArray_,
    len: usize,
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size = elements.len();
    let array = libc::malloc((size+1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;

    for i in 0 .. size {
        *array.offset(i as isize) = elements[i].0;
    }
    *array.offset(size as isize) = ptr::null::<low::ffi_type>() as FfiType_;

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", array);

    array
}

unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_) -> FfiType_ {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

unsafe fn ffi_type_array_clone(ffi_types: FfiTypeArray_) -> FfiTypeArray_ {
    let mut current = ffi_types;
    let mut count   = 0;
    while !(*current).is_null() {
        current = current.offset(1);
        count += 1;
    }

    let new = libc::malloc((count+1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;

    for i in 0 .. count {
        *new.offset(i as isize) = ffi_type_clone(*ffi_types.offset(i as isize));
    }
    *new.offset(count as isize) = ptr::null::<low::ffi_type>() as FfiType_;

    new
}

unsafe fn ffi_type_clone(old: FfiType_) -> FfiType_ {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(ffi_types: FfiTypeArray_) {
    println!("ffi_type_array_destroy({:?})", ffi_types);
    let mut current = ffi_types;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(ffi_types as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(ffi_type: FfiType_) {
    println!("ffi_type_destroy({:?})", ffi_type);
    if (*ffi_type).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*ffi_type).elements);
        libc::free(ffi_type as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.ptr) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(types: Vec<FfiType>) -> Self {
        let len = types.len();
        unsafe {
            FfiTypeArray {
                ptr: ffi_type_array_create(types),
                len: len,
            }
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.ptr
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<commit_msg>refactoring FfiTypeArray_ code<commit_after>use std::{mem, ptr};
use libc;

use c;
use low;

type FfiType_      = *mut low::ffi_type;
type FfiTypeArray_ = *mut FfiType_;

#[derive(Debug)]
pub struct FfiType(FfiType_);

#[derive(Debug)]
pub struct FfiTypeArray {
    ptr: FfiTypeArray_,
    len: usize,
}

/// Computes the length of a raw `FfiTypeArray_` by searching for the
/// null terminator.
unsafe fn ffi_type_array_len(mut array: FfiTypeArray_) -> usize {
    let mut current = array;
    let mut count   = 0;
    while !(*current).is_null() {
        count += 1;
    }
    count
}

unsafe fn ffi_type_array_create_empty(size: usize) -> FfiTypeArray_ {
    let array = libc::malloc((size + 1) * mem::size_of::<FfiType_>())
                    as FfiTypeArray_;
    *array.offset(size as isize) = ptr::null::<low::ffi_type>() as FfiType_;
    array
}

/// Creates a null-terminated array of FfiType_. Takes ownership of
/// the elements.
unsafe fn ffi_type_array_create(elements: Vec<FfiType>) -> FfiTypeArray_ {
    let size  = elements.len();
    let array = ffi_type_array_create_empty(size);
    for i in 0 .. size {
        *array.offset(i as isize) = elements[i].0;
    }

    for t in elements {
        mem::forget(t);
    }

    println!("ffi_type_array_create(...) = {:?}", array);

    array
}

unsafe fn ffi_type_struct_create_raw(elements: FfiTypeArray_) -> FfiType_ {
    let new = libc::malloc(mem::size_of::<low::ffi_type>()) as FfiType_;

    (*new).size      = 0;
    (*new).alignment = 0;
    (*new).type_     = c::ffi_type_enum::STRUCT as ::libc::c_ushort;
    (*new).elements  = elements;

    println!("ffi_type_struct_create_raw({:?}) = {:?}", elements, new);

    new
}

/// Creates a struct ffi_type with the given elements. Takes ownership
/// of the elements.
unsafe fn ffi_type_struct_create(elements: Vec<FfiType>) -> FfiType_ {
    println!("ffi_type_array_create({:?})", elements);
    ffi_type_struct_create_raw(ffi_type_array_create(elements))
}

unsafe fn ffi_type_array_clone(ffi_types: FfiTypeArray_) -> FfiTypeArray_ {
    let size = ffi_type_array_len(ffi_types);
    let new   = ffi_type_array_create_empty(size);

    for i in 0 .. size {
        *new.offset(i as isize) = ffi_type_clone(*ffi_types.offset(i as isize));
    }

    new
}

unsafe fn ffi_type_clone(old: FfiType_) -> FfiType_ {
    if (*old).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_struct_create_raw(ffi_type_array_clone((*old).elements))
    } else {
        old
    }
}

/// Destroys an array of FfiType_ and all of its elements.
unsafe fn ffi_type_array_destroy(ffi_types: FfiTypeArray_) {
    println!("ffi_type_array_destroy({:?})", ffi_types);
    let mut current = ffi_types;
    while !(*current).is_null() {
        ffi_type_destroy(*current);
        current = current.offset(1);
    }

    libc::free(ffi_types as *mut libc::c_void);
}

/// Destroys an FfiType_ if it was dynamically allocated.
unsafe fn ffi_type_destroy(ffi_type: FfiType_) {
    println!("ffi_type_destroy({:?})", ffi_type);
    if (*ffi_type).type_ == c::ffi_type_enum::STRUCT as u16 {
        ffi_type_array_destroy((*ffi_type).elements);
        libc::free(ffi_type as *mut libc::c_void);
    }
}

impl Drop for FfiType {
    fn drop(&mut self) {
        unsafe { ffi_type_destroy(self.0) }
    }
}

impl Drop for FfiTypeArray {
    fn drop(&mut self) {
        unsafe { ffi_type_array_destroy(self.ptr) }
    }
}

impl FfiType {
    pub fn void() -> Self {
        FfiType(unsafe { &mut low::ffi_type_void })
    }

    pub fn uint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint8 })
    }

    pub fn sint8() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint8 })
    }

    pub fn uint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint16 })
    }

    pub fn sint16() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint16 })
    }

    pub fn uint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint32 })
    }

    pub fn sint32() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint32 })
    }

    pub fn uint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_uint64 })
    }

    pub fn sint64() -> Self {
        FfiType(unsafe { &mut low::ffi_type_sint64 })
    }

    pub fn float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_float })
    }

    pub fn double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_double })
    }

    pub fn pointer() -> Self {
        FfiType(unsafe { &mut low::ffi_type_pointer })
    }

    pub fn longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_longdouble })
    }

    pub fn complex_float() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_float })
    }

    pub fn complex_double() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_double })
    }

    pub fn complex_longdouble() -> Self {
        FfiType(unsafe { &mut low::ffi_type_complex_longdouble })
    }

    pub fn structure(fields: Vec<FfiType>) -> Self {
        println!("FfiType::structure({:?})", fields);
        unsafe {
            FfiType(ffi_type_struct_create(fields))
        }
    }

    pub fn as_raw_ptr(&self) -> *mut low::ffi_type {
        self.0
    }
}

impl FfiTypeArray {
    pub fn new(types: Vec<FfiType>) -> Self {
        let len = types.len();
        unsafe {
            FfiTypeArray {
                ptr: ffi_type_array_create(types),
                len: len,
            }
        }
    }

    pub fn len(&self) -> usize {
        self.len
    }

    pub fn as_raw_ptr(&self) -> *mut *mut low::ffi_type {
        self.ptr
    }
}

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

    #[test]
    fn create_uint64() {
        FfiType::uint64();
    }

    #[test]
    fn create_struct() {
        FfiType::structure(vec![FfiType::sint64(),
                                FfiType::sint64(),
                                FfiType::uint64()]);
    }

}
<|endoftext|>


<commit_before>// Copyright 2017 Amos Onn.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

use std::fs::File;
use std::os::unix::fs::FileExt;
use std::ffi::OsStr;
use std::path::Path;
use libc;

use super::fusefl::*;
use fuse_mt::*;
use super::Result;

/// Trait to be implemented for providing the "reader" functionality, to be used with
/// FilesystemFLOpen or FilesystemFLRwOpen.
pub trait ReadFileLike {
    /// Read data.
    /// Read should send exactly the number of bytes requested except on EOF or error,
    /// otherwise the rest of the data will be substituted with zeroes. An exception to
    /// this is when the file has been opened in 'direct_io' mode, in which case the
    /// return value of the read system call will reflect the return value of this
    /// operation.
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

/// Trait to be implemented for providing the "writer" functionality, to be used with
/// FilesystemFLOpen or FilesystemFLRwOpen.
pub trait WriteFileLike {
    /// Write data.
    /// Write should return exactly the number of bytes requested except on error. An
    /// exception to this is when the file has been opened in 'direct_io' mode, in
    /// which case the return value of the write system call will reflect the return
    /// value of this operation.
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    /// Synchronize file contents.
    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

impl ReadFileLike for File {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        FileExt::read_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }
}

impl WriteFileLike for File {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        FileExt::write_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }

    // NOTE: we can't use the flush method from Write, because that wants a &mut. However, for now
    // File's impl of flush is the same as ours, Ok(()), so we can stick with that.
    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

/// Empty type for using with FilesystemFLRwOpen as the WriteLike and ReadWriteLike for readonly
/// fs-s (or the similar parallel for writeonly ones).
pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

/// Naive implementation of a read-write FileLike, given a read FileLike and
/// a write FileLike implementation.
pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

/// Implementation of a FileLike which can be either read-only, write-only or read-write.
/// Implementes both the ReadLike and WriteLike, returning EBADF in case of trying to write to a
/// read-only file or vice-versa (just like you'd expect).
pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

/// Trait for using different types for the read, write and read-write files. The read-write type
/// can be a ReadWriteAdaptor over the read and write ones.
/// Everything implementing this implements FilesystemFLOpen, dispatching the open and create calls
/// according to the ACCMODE to the open or create method for the right type of file.
/// NOTE: fsync_metadata is not dispatched, but rather gets an enum over the possible file types,
/// because persumably the synchronization of metadata is mostly unaffected by how the file was
/// opened.
pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_read(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &ModalFileLike<
        Self::ReadLike,
        Self::WriteLike,
        Self::ReadWriteLike,
    >) -> ResultEmpty {
        Err(libc::ENOSYS)
    }
}

/// Trait for standard usecase of FilesystemFL - open and create methods return a FileLike object,
/// which supports reading, writing and flushing of data, and then these calls are passed directly
/// to it. Once specialization (RFC #1210) lands, this will be integrated as a default impl of
/// FilesystemFL for types implementing this; for now, this repeats some methods from FilesystemFL,
/// and these should be manually called in the implementation of FilesystemFL.
// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        _fl.flush()?;
        if !_datasync {
            self.fsync_metadata(_req, _path, _fl)
        } else {
            Ok(())
        }
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike) -> ResultEmpty {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
impl<T> FilesystemFLOpen for T where T: FilesystemFLRwOpen {
    type FileLike = ModalFileLike<
        <Self as FilesystemFLRwOpen>::ReadLike,
        <Self as FilesystemFLRwOpen>::WriteLike,
        <Self as FilesystemFLRwOpen>::ReadWriteLike,
    >;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_open(self.open_read(_req, _path, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_open(self.open_write(_req, _path, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_open(self.open_readwrite(_req, _path, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_create(self.create_read(_req, _parent, _name, _mode, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_create(self.create_write(_req, _parent, _name, _mode, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_create(self.create_readwrite(_req, _parent, _name, _mode, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike) -> ResultEmpty {
        FilesystemFLRwOpen::fsync_metadata(self, _req, _path, _fl)
    }
}

<commit_msg>impl'd ReadLike for [u8], WriteLike for int. mut. types around [u8]<commit_after>// Copyright 2017 Amos Onn.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//

use std::fs::File;
use std::cmp::min;
use std::cell::RefCell;
use std::sync::{Mutex, RwLock};
use std::os::unix::fs::FileExt;
use std::ffi::OsStr;
use std::path::Path;
use libc;

use super::fusefl::*;
use fuse_mt::*;
use super::Result;

/// Trait to be implemented for providing the "reader" functionality, to be used with
/// FilesystemFLOpen or FilesystemFLRwOpen.
pub trait ReadFileLike {
    /// Read data.
    /// Read should send exactly the number of bytes requested except on EOF or error,
    /// otherwise the rest of the data will be substituted with zeroes. An exception to
    /// this is when the file has been opened in 'direct_io' mode, in which case the
    /// return value of the read system call will reflect the return value of this
    /// operation.
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize>;
}

/// Trait to be implemented for providing the "writer" functionality, to be used with
/// FilesystemFLOpen or FilesystemFLRwOpen.
pub trait WriteFileLike {
    /// Write data.
    /// Write should return exactly the number of bytes requested except on error. An
    /// exception to this is when the file has been opened in 'direct_io' mode, in
    /// which case the return value of the write system call will reflect the return
    /// value of this operation.
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize>;

    /// Synchronize file contents.
    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

impl ReadFileLike for File {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        FileExt::read_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }
}

impl WriteFileLike for File {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        FileExt::write_at(self, buf, offset).map_err(|x| x.raw_os_error().unwrap())
    }

    // NOTE: we can't use the flush method from Write, because that wants a &mut. However, for now
    // File's impl of flush is the same as ours, Ok(()), so we can stick with that.
    fn flush(&self) -> Result<()> {
        Ok(())
    }
}

impl ReadFileLike for [u8] {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        if offset > usize::max_value() as u64 { return Ok(0); }
        let offset = offset as usize;
        let len = min(buf.len(), self.len() - offset);
        buf[..len].copy_from_slice(&self[offset..offset+len]);
        Ok(len)
    }
}

fn do_write_at(this: &mut [u8], buf: &[u8], offset: u64) -> usize {
    if offset > usize::max_value() as u64 { return 0; }
    let offset = offset as usize;
    let len = min(buf.len(), this.len() - offset);
    this[offset..offset+len].copy_from_slice(&buf[..len]);
    len
}

impl WriteFileLike for RefCell<[u8]> {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Ok(do_write_at(&mut *self.borrow_mut(), buf, offset))
    }
}

impl WriteFileLike for Mutex<[u8]> {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Ok(do_write_at(&mut *self.lock().unwrap(), buf, offset))
    }
}

impl WriteFileLike for RwLock<[u8]> {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Ok(do_write_at(&mut *self.write().unwrap(), buf, offset))
    }
}

/// Empty type for using with FilesystemFLRwOpen as the WriteLike and ReadWriteLike for readonly
/// fs-s (or the similar parallel for writeonly ones).
pub enum NoFile {}

#[allow(unused_variables)]
impl ReadFileLike for NoFile {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }
}

#[allow(unused_variables)]
impl WriteFileLike for NoFile {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        Err(libc::ENOSYS)
    }

    fn flush(&self) -> Result<()> {
        Err(libc::ENOSYS)
    }
}

/// Naive implementation of a read-write FileLike, given a read FileLike and
/// a write FileLike implementation.
pub struct ReadWriteAdaptor<R, W> {
    reader: R,
    writer: W,
}

impl<R, W> ReadFileLike for ReadWriteAdaptor<R, W> where R: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        self.reader.read_at(buf, offset)
    }
}

impl<R, W> WriteFileLike for ReadWriteAdaptor<R, W> where W: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        self.writer.write_at(buf, offset)
    }

    fn flush(&self) -> Result<()> {
        self.writer.flush()
    }
}

/// Implementation of a FileLike which can be either read-only, write-only or read-write.
/// Implementes both the ReadLike and WriteLike, returning EBADF in case of trying to write to a
/// read-only file or vice-versa (just like you'd expect).
pub enum ModalFileLike<R, W, RW> {
    ReadOnly(R),
    WriteOnly(W),
    ReadWrite(RW),
}

use self::ModalFileLike::*;

impl<R, W, RW> ReadFileLike for ModalFileLike<R, W, RW> where
    R: ReadFileLike, RW: ReadFileLike {
    fn read_at(&self, buf: &mut [u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(ref r) => r.read_at(buf, offset),
            WriteOnly(_) => Err(libc::EBADF),
            ReadWrite(ref rw) => rw.read_at(buf, offset),
        }
    }
}

impl<R, W, RW> WriteFileLike for ModalFileLike<R, W, RW> where
    W: WriteFileLike, RW: WriteFileLike {
    fn write_at(&self, buf: &[u8], offset: u64) -> Result<usize> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.write_at(buf, offset),
            ReadWrite(ref rw) => rw.write_at(buf, offset),
        }
    }

    fn flush(&self) -> Result<()> {
        match *self {
            ReadOnly(_) => Err(libc::EBADF),
            WriteOnly(ref w) => w.flush(),
            ReadWrite(ref rw) => rw.flush(),
        }
    }
}

/// Trait for using different types for the read, write and read-write files. The read-write type
/// can be a ReadWriteAdaptor over the read and write ones.
/// Everything implementing this implements FilesystemFLOpen, dispatching the open and create calls
/// according to the ACCMODE to the open or create method for the right type of file.
/// NOTE: fsync_metadata is not dispatched, but rather gets an enum over the possible file types,
/// because persumably the synchronization of metadata is mostly unaffected by how the file was
/// opened.
pub trait FilesystemFLRwOpen {
    type ReadLike: ReadFileLike; // = NoFile;
    type WriteLike: WriteFileLike; // = NoFile;
    type ReadWriteLike: ReadFileLike+WriteFileLike; // = ReadWriteAdaptor<Self::ReadLike, Self::WriteLike>;

    fn open_read(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn open_write(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn open_readwrite(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_read(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadLike> {
        Err(libc::ENOSYS)
    }

    fn create_write(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::WriteLike> {
        Err(libc::ENOSYS)
    }

    fn create_readwrite(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::ReadWriteLike> {
        Err(libc::ENOSYS)
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &ModalFileLike<
        Self::ReadLike,
        Self::WriteLike,
        Self::ReadWriteLike,
    >) -> ResultEmpty {
        Err(libc::ENOSYS)
    }
}

/// Trait for standard usecase of FilesystemFL - open and create methods return a FileLike object,
/// which supports reading, writing and flushing of data, and then these calls are passed directly
/// to it. Once specialization (RFC #1210) lands, this will be integrated as a default impl of
/// FilesystemFL for types implementing this; for now, this repeats some methods from FilesystemFL,
/// and these should be manually called in the implementation of FilesystemFL.
// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
pub trait FilesystemFLOpen {
    type FileLike: ReadFileLike+WriteFileLike;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        Err(libc::ENOSYS)
    }

    fn read(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _size: u32) -> ResultData {
        let _size = _size as usize;
        let mut vec = Vec::<u8>::with_capacity(_size);
        unsafe { vec.set_len(_size) };
        let num_read = _fl.read_at(vec.as_mut_slice(), _offset)?;
        assert!(num_read <= _size);
        unsafe { vec.set_len(num_read) };
        Ok(vec)
    }

    fn write(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _offset: u64, _data: Vec<u8>, _flags: u32) -> ResultWrite {
        assert!(_data.len() <= u32::max_value() as usize);
        _fl.write_at(_data.as_slice(), _offset).map(|x| x as u32)
    }

    fn fsync(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike, _datasync: bool) -> ResultEmpty {
        _fl.flush()?;
        if !_datasync {
            self.fsync_metadata(_req, _path, _fl)
        } else {
            Ok(())
        }
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike) -> ResultEmpty {
        Err(libc::ENOSYS)
    }
}

// Part of this will become a default impl of FilesystemFL when RFC #1210 lands.
impl<T> FilesystemFLOpen for T where T: FilesystemFLRwOpen {
    type FileLike = ModalFileLike<
        <Self as FilesystemFLRwOpen>::ReadLike,
        <Self as FilesystemFLRwOpen>::WriteLike,
        <Self as FilesystemFLRwOpen>::ReadWriteLike,
    >;

    fn open(&self, _req: RequestInfo, _path: &Path, _flags: u32) -> ResultOpenObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_open(self.open_read(_req, _path, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_open(self.open_write(_req, _path, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_open(self.open_readwrite(_req, _path, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    /// If this method is not implemented or under Linux kernel versions earlier than 2.6.15, the
    /// mknod() and open() methods will be called instead.
    fn create(&self, _req: RequestInfo, _parent: &Path, _name: &OsStr, _mode: u32, _flags: u32) -> ResultCreateObj<Self::FileLike> {
        match _flags as i32 & libc::O_ACCMODE {
            libc::O_RDONLY => map_res_create(self.create_read(_req, _parent, _name, _mode, _flags), |fl| ReadOnly(fl)),
            libc::O_WRONLY => map_res_create(self.create_write(_req, _parent, _name, _mode, _flags), |fl| WriteOnly(fl)),
            libc::O_RDWR => map_res_create(self.create_readwrite(_req, _parent, _name, _mode, _flags), |fl| ReadWrite(fl)),
            _ => Err(libc::EINVAL),
        }
    }

    fn fsync_metadata(&self, _req: RequestInfo, _path: &Path, _fl: &Self::FileLike) -> ResultEmpty {
        FilesystemFLRwOpen::fsync_metadata(self, _req, _path, _fl)
    }
}

<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use sdl2::render::{Renderer, Texture};
use sdl2::image::{LoadTexture};

use game::data::Rectangle;

pub trait Renderable {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle);
}

#[derive(Clone)]
pub struct Sprite {
  texture: Rc<RefCell<Texture>>,
  src: Rectangle,
}

impl Renderable for Sprite {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.texture.borrow_mut(), self.src.to_sdl(), dest.to_sdl());
  }
}

impl Sprite {
  pub fn new(texture: Texture) -> Sprite {
    let tex_query = texture.query();

    Sprite {
      texture: Rc::new(RefCell::new(texture)),
      src: Rectangle {
        w: tex_query.width as f64,
        h: tex_query.height as f64,
        x: 0.0,
        y: 0.0,
      }
    }
  }

  pub fn load(renderer: &Renderer, path: &str) -> Option<Sprite> {
    match renderer.load_texture(Path::new(path)).ok() {
      Some(f) => Some(f).map(Sprite::new),
      None => panic!("File not fount {}", path),
    }
  }

  pub fn size(&self) -> (f64, f64) {
    (self.src.w, self.src.h)
  }

  pub fn region(&self, rect: Rectangle) -> Option<Sprite> {
    let new_src = Rectangle {
      x: rect.x + self.src.x,
      y: rect.y + self.src.y,
      ..rect
    };

    if self.src.contains(new_src) {
      Some(Sprite {
        texture: self.texture.clone(),
        src: new_src,
      })
    } else {
      None
    }
  }

  pub fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.texture.borrow_mut(), self.src.to_sdl(), dest.to_sdl()).unwrap();
  }
}

#[derive(Clone)]
pub struct AnimatedSprite {
  sprites: Vec<Sprite>,
  start_index: usize,
  end_index: usize,
  frame_delay: f64,
  current_time: f64,
}

impl AnimatedSprite {
  pub fn new(sprites: Vec<Sprite>, frame_delay: f64) -> AnimatedSprite {
    AnimatedSprite {
      sprites: sprites,
      frame_delay: frame_delay,
      start_index: 0,
      end_index: 1,
      current_time: 0.0,
    }
  }

  pub fn with_fps(sprites: Vec<Sprite>, fps: f64) -> AnimatedSprite {
    if fps <= 0.0 {
      panic!("Passed non positive value to AnimatedSprite::with_fps");
    }

    AnimatedSprite::new(sprites, 1.0 / fps)
  }

  pub fn set_curr_frames(&mut self, start_index: usize, end_index: usize) {
    self.start_index = start_index;
    self.end_index = end_index;
  }

  pub fn frames(&self) -> usize {
    self.end_index - self.start_index
  }

  pub fn add_time(&mut self, dt: f64) {
    self.current_time += dt;
    if self.current_time < 0.0 {
      self.current_time = (self.frames() - 1) as f64 * self.frame_delay;
    }
  }
}

impl Renderable for AnimatedSprite {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    let current_frame =
    (self.current_time / self.frame_delay) as usize % self.frames();
    let curr_sprites = &self.sprites[self.start_index..self.end_index];
    let sprite = &curr_sprites[current_frame];
    sprite.render(renderer, dest);
  }
}

pub trait CopySprite<T> {
  fn copy_sprite(&mut self, sprite: &T, dest: Rectangle);
}

impl<'w, T: Renderable> CopySprite<T> for Renderer<'w> {
  fn copy_sprite(&mut self, renderable: &T, dest: Rectangle) {
    renderable.render(self, dest);
  }
}
<commit_msg>Unwrap renderer copy<commit_after>use std::cell::RefCell;
use std::path::Path;
use std::rc::Rc;
use sdl2::render::{Renderer, Texture};
use sdl2::image::{LoadTexture};

use game::data::Rectangle;

pub trait Renderable {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle);
}

#[derive(Clone)]
pub struct Sprite {
  texture: Rc<RefCell<Texture>>,
  src: Rectangle,
}

impl Renderable for Sprite {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.texture.borrow_mut(), self.src.to_sdl(), dest.to_sdl()).unwrap();
  }
}

impl Sprite {
  pub fn new(texture: Texture) -> Sprite {
    let tex_query = texture.query();

    Sprite {
      texture: Rc::new(RefCell::new(texture)),
      src: Rectangle {
        w: tex_query.width as f64,
        h: tex_query.height as f64,
        x: 0.0,
        y: 0.0,
      }
    }
  }

  pub fn load(renderer: &Renderer, path: &str) -> Option<Sprite> {
    match renderer.load_texture(Path::new(path)).ok() {
      Some(f) => Some(f).map(Sprite::new),
      None => panic!("File not fount {}", path),
    }
  }

  pub fn size(&self) -> (f64, f64) {
    (self.src.w, self.src.h)
  }

  pub fn region(&self, rect: Rectangle) -> Option<Sprite> {
    let new_src = Rectangle {
      x: rect.x + self.src.x,
      y: rect.y + self.src.y,
      ..rect
    };

    if self.src.contains(new_src) {
      Some(Sprite {
        texture: self.texture.clone(),
        src: new_src,
      })
    } else {
      None
    }
  }

  pub fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    renderer.copy(&mut self.texture.borrow_mut(), self.src.to_sdl(), dest.to_sdl()).unwrap();
  }
}

#[derive(Clone)]
pub struct AnimatedSprite {
  sprites: Vec<Sprite>,
  start_index: usize,
  end_index: usize,
  frame_delay: f64,
  current_time: f64,
}

impl AnimatedSprite {
  pub fn new(sprites: Vec<Sprite>, frame_delay: f64) -> AnimatedSprite {
    AnimatedSprite {
      sprites: sprites,
      frame_delay: frame_delay,
      start_index: 0,
      end_index: 1,
      current_time: 0.0,
    }
  }

  pub fn with_fps(sprites: Vec<Sprite>, fps: f64) -> AnimatedSprite {
    if fps <= 0.0 {
      panic!("Passed non positive value to AnimatedSprite::with_fps");
    }

    AnimatedSprite::new(sprites, 1.0 / fps)
  }

  pub fn set_curr_frames(&mut self, start_index: usize, end_index: usize) {
    self.start_index = start_index;
    self.end_index = end_index;
  }

  pub fn frames(&self) -> usize {
    self.end_index - self.start_index
  }

  pub fn add_time(&mut self, dt: f64) {
    self.current_time += dt;
    if self.current_time < 0.0 {
      self.current_time = (self.frames() - 1) as f64 * self.frame_delay;
    }
  }
}

impl Renderable for AnimatedSprite {
  fn render(&self, renderer: &mut Renderer, dest: Rectangle) {
    let current_frame =
    (self.current_time / self.frame_delay) as usize % self.frames();
    let curr_sprites = &self.sprites[self.start_index..self.end_index];
    let sprite = &curr_sprites[current_frame];
    sprite.render(renderer, dest);
  }
}

pub trait CopySprite<T> {
  fn copy_sprite(&mut self, sprite: &T, dest: Rectangle);
}

impl<'w, T: Renderable> CopySprite<T> for Renderer<'w> {
  fn copy_sprite(&mut self, renderable: &T, dest: Rectangle) {
    renderable.render(self, dest);
  }
}
<|endoftext|>


<commit_before>use DrawState;
use types::{ self, Matrix2d, Scalar };
use deform::DeformGrid;
use {
    CircleArc,
    Ellipse,
    Image,
    ImageSize,
    Line,
    Polygon,
    Rectangle,
};

/// Implemented by all graphics back-ends.
///
/// [An example back-end using raw OpenGL](https://github.com/PistonDevelopers/opengl_graphics)
///
/// By default, this design uses triangles as graphics primitives.
/// This is supported by all GPUs and easy to implement in shader languages.
///
/// Default trait methods can be overridden for better performance or higher
/// quality.
///
/// When drawing, use this trait as generic constraint:
///
/// ```ignore
/// fn draw<G: Graphics>(c: &Context, g: &mut G) { ... }
/// ```
///
/// Color space is sRGB.
///
/// ### Notice for back-end authors
///
/// When sRGB is enabled for a back-end shader, the gamma must be converted
/// to linear space when used as vertex color or uniform parameter.
/// To convert gamma, use `color::gamma_srgb_to_linear`.
///
/// For more information, see
/// https://github.com/PistonDevelopers/piston/issues/1014.
pub trait Graphics: Sized {
    /// The texture type associated with the back-end.
    ///
    /// In generic code, this type is often unknown.
    /// This might lead to more boilerplate code:
    ///
    /// ```ignore
    /// fn draw_texture<G, T>(c: &Context, g: &mut G)
    ///     where G: Graphcis<Texture = T>, T: ImageSize { ... }
    /// ```
    ///
    /// Code written specifically for one back-end can be easier to write.
    /// Later, when the code is done, it can be refactored into generic code.
    type Texture: ImageSize;

    /// Clears background with a color.
    ///
    /// The color should replace the values in the buffer.
    ///
    /// Color space is sRGB.
    fn clear_color(&mut self, color: types::Color);

    /// Clears stencil buffer with a value, usually 0.
    ///
    /// A stencil buffer contains values that are not visible on the screen.
    /// These values are used to test against the pixel to paint.
    ///
    /// If you are drawing a shape for clipping and forgot to clear the
    /// stencil buffer, then the clipping shape will carry over in next frame
    /// and cause artifacts.
    fn clear_stencil(&mut self, value: u8);

    /// Renders list of 2d triangles using a solid color.
    ///
    /// All vertices share the same color.
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[x0, y0, x1, y1, ...]`.
    ///
    /// Color space is sRGB.
    fn tri_list<F>(&mut self, draw_state: &DrawState, color: &[f32; 4], f: F)
        where F: FnMut(&mut FnMut(&[f32]));

    /// Renders list of 2d triangles using a color and a texture.
    ///
    /// All vertices share the same color.
    ///
    /// Tip: For objects of different colors, use grayscale textures.
    /// The texture color gets multiplied with the color.
    ///
    /// A texture coordinate is assigned per vertex (from [0, 0] to [1, 1]).
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[x0, y0, x1, y1, ...]`.
    /// Texture coordinates are encoded `[u0, v0, u1, v1, ...]`.
    ///
    /// Chunks uses separate buffer for vertex positions and texture coordinates.
    /// Arguments are `|vertices: &[f32], texture_coords: &[f32]`.
    ///
    /// Color space is sRGB.
    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        f: F
    ) where F: FnMut(&mut FnMut(&[f32], &[f32]));

    /// Draws a rectangle.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Rectangle::draw`.
    #[inline(always)]
    fn rectangle<R: Into<types::Rectangle>>(
        &mut self,
        r: &Rectangle,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        r.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws a polygon.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw`.
    #[inline(always)]
    fn polygon(
        &mut self,
        p: &Polygon,
        polygon: types::Polygon,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        p.draw_tri(polygon, draw_state, transform, self);
    }

    /// Draws a tweened polygon using linear interpolation.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw_tween_lerp`.
    #[inline(always)]
    fn polygon_tween_lerp(
        &mut self,
        p: &Polygon,
        polygons: types::Polygons,
        tween_factor: Scalar,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        p.draw_tween_lerp_tri(polygons, tween_factor,
            draw_state, transform, self);
    }

    /// Draws image.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Image::draw`.
    #[inline(always)]
    fn image(
        &mut self,
        image: &Image,
        texture: &Self::Texture,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        image.draw_tri(texture, draw_state, transform, self);
    }

    /// Draws ellipse.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Ellipse::draw`.
    #[inline(always)]
    fn ellipse<R: Into<types::Rectangle>>(
        &mut self,
        e: &Ellipse,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        e.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws line.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Line::draw`.
    #[inline(always)]
    fn line<L: Into<types::Line>>(
        &mut self,
        l: &Line,
        line: L,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        l.draw_tri(line, draw_state, transform, self);
    }

    /// Draws circle arc.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `CircleArc::draw`.
    #[inline(always)]
    fn circle_arc<R: Into<types::Rectangle>>(
        &mut self,
        c: &CircleArc,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        c.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws deformed image.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `DeformGrid::draw_image`.
    #[inline(always)]
    fn deform_image(
        &mut self,
        d: &DeformGrid,
        texture: &Self::Texture,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        d.draw_image_tri(texture, draw_state, transform, self);
    }
}
<commit_msg>Make Graphics doctests easier to copy-paste<commit_after>use DrawState;
use types::{ self, Matrix2d, Scalar };
use deform::DeformGrid;
use {
    CircleArc,
    Ellipse,
    Image,
    ImageSize,
    Line,
    Polygon,
    Rectangle,
};

/// Implemented by all graphics back-ends.
///
/// [An example back-end using raw OpenGL](https://github.com/PistonDevelopers/opengl_graphics)
///
/// By default, this design uses triangles as graphics primitives.
/// This is supported by all GPUs and easy to implement in shader languages.
///
/// Default trait methods can be overridden for better performance or higher
/// quality.
///
/// When drawing, use this trait as generic constraint:
///
/// ```
/// use graphics::{Graphics, Context};
///
/// fn draw<G: Graphics>(c: &Context, g: &mut G) {
///     //...
/// }
/// ```
///
/// Color space is sRGB.
///
/// ### Notice for back-end authors
///
/// When sRGB is enabled for a back-end shader, the gamma must be converted
/// to linear space when used as vertex color or uniform parameter.
/// To convert gamma, use `color::gamma_srgb_to_linear`.
///
/// For more information, see
/// https://github.com/PistonDevelopers/piston/issues/1014.
pub trait Graphics: Sized {
    /// The texture type associated with the back-end.
    ///
    /// In generic code, this type is often unknown.
    /// This might lead to more boilerplate code:
    ///
    /// ```
    /// use graphics::{Graphics, Context, ImageSize};
    ///
    /// fn draw_texture<G, T>(c: &Context, g: &mut G)
    ///     where G: Graphics<Texture = T>, T: ImageSize {
    ///     //...
    /// }
    /// ```
    ///
    /// Code written specifically for one back-end can be easier to write.
    /// Later, when the code is done, it can be refactored into generic code.
    type Texture: ImageSize;

    /// Clears background with a color.
    ///
    /// The color should replace the values in the buffer.
    ///
    /// Color space is sRGB.
    fn clear_color(&mut self, color: types::Color);

    /// Clears stencil buffer with a value, usually 0.
    ///
    /// A stencil buffer contains values that are not visible on the screen.
    /// These values are used to test against the pixel to paint.
    ///
    /// If you are drawing a shape for clipping and forgot to clear the
    /// stencil buffer, then the clipping shape will carry over in next frame
    /// and cause artifacts.
    fn clear_stencil(&mut self, value: u8);

    /// Renders list of 2d triangles using a solid color.
    ///
    /// All vertices share the same color.
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[x0, y0, x1, y1, ...]`.
    ///
    /// Color space is sRGB.
    fn tri_list<F>(&mut self, draw_state: &DrawState, color: &[f32; 4], f: F)
        where F: FnMut(&mut FnMut(&[f32]));

    /// Renders list of 2d triangles using a color and a texture.
    ///
    /// All vertices share the same color.
    ///
    /// Tip: For objects of different colors, use grayscale textures.
    /// The texture color gets multiplied with the color.
    ///
    /// A texture coordinate is assigned per vertex (from [0, 0] to [1, 1]).
    ///
    /// The back-end calls the closure with a closure to receive vertices.
    /// First, the back-end sets up shaders and such to prepare.
    /// Then it calls the closure, which calls back with chunks of vertices.
    /// The number of vertices per chunk never exceeds
    /// `BACK_END_MAX_VERTEX_COUNT`.
    /// Vertex positions are encoded `[x0, y0, x1, y1, ...]`.
    /// Texture coordinates are encoded `[u0, v0, u1, v1, ...]`.
    ///
    /// Chunks uses separate buffer for vertex positions and texture coordinates.
    /// Arguments are `|vertices: &[f32], texture_coords: &[f32]`.
    ///
    /// Color space is sRGB.
    fn tri_list_uv<F>(
        &mut self,
        draw_state: &DrawState,
        color: &[f32; 4],
        texture: &<Self as Graphics>::Texture,
        f: F
    ) where F: FnMut(&mut FnMut(&[f32], &[f32]));

    /// Draws a rectangle.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Rectangle::draw`.
    #[inline(always)]
    fn rectangle<R: Into<types::Rectangle>>(
        &mut self,
        r: &Rectangle,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        r.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws a polygon.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw`.
    #[inline(always)]
    fn polygon(
        &mut self,
        p: &Polygon,
        polygon: types::Polygon,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        p.draw_tri(polygon, draw_state, transform, self);
    }

    /// Draws a tweened polygon using linear interpolation.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Polygon::draw_tween_lerp`.
    #[inline(always)]
    fn polygon_tween_lerp(
        &mut self,
        p: &Polygon,
        polygons: types::Polygons,
        tween_factor: Scalar,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        p.draw_tween_lerp_tri(polygons, tween_factor,
            draw_state, transform, self);
    }

    /// Draws image.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Image::draw`.
    #[inline(always)]
    fn image(
        &mut self,
        image: &Image,
        texture: &Self::Texture,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        image.draw_tri(texture, draw_state, transform, self);
    }

    /// Draws ellipse.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Ellipse::draw`.
    #[inline(always)]
    fn ellipse<R: Into<types::Rectangle>>(
        &mut self,
        e: &Ellipse,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        e.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws line.
    ///
    /// Can be overridden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `Line::draw`.
    #[inline(always)]
    fn line<L: Into<types::Line>>(
        &mut self,
        l: &Line,
        line: L,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        l.draw_tri(line, draw_state, transform, self);
    }

    /// Draws circle arc.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `CircleArc::draw`.
    #[inline(always)]
    fn circle_arc<R: Into<types::Rectangle>>(
        &mut self,
        c: &CircleArc,
        rectangle: R,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        c.draw_tri(rectangle, draw_state, transform, self);
    }

    /// Draws deformed image.
    ///
    /// Can be overriden in the back-end for higher performance.
    ///
    /// Instead of calling this directly, use `DeformGrid::draw_image`.
    #[inline(always)]
    fn deform_image(
        &mut self,
        d: &DeformGrid,
        texture: &Self::Texture,
        draw_state: &DrawState,
        transform: Matrix2d
    ) {
        d.draw_image_tri(texture, draw_state, transform, self);
    }
}
<|endoftext|>