<commit_before>use common::memory::*;
use common::scheduler::*;

use drivers::disk::*;

use programs::common::*;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Extent {
    pub block: u64,
    pub length: u64
}

#[repr(packed)]
pub struct Header {
    pub signature: [u8; 8],
    pub version: u32,
    pub name: [u8; 244],
    pub extents: [Extent; 16]
}

#[repr(packed)]
pub struct NodeData {
    pub name: [u8; 256],
    pub extents: [Extent; 16]
}

pub struct Node {
    pub address: u64,
    pub name: String,
    pub extents: [Extent; 16]
}

impl Node {
    pub fn new(address: u64, data: NodeData) -> Node {
        let mut utf8: Vec<u8> = Vec::new();
        for i in 0..data.name.len() {
            let c = data.name[i];
            if c == 0 {
                break;
            }else{
                utf8.push(c);
            }
        }

        Node {
            address: address,
            name: String::from_utf8(&utf8),
            extents: data.extents
        }
    }
}

impl Clone for Node {
    fn clone(&self) -> Node {
        return Node {
            address: self.address,
            name: self.name.clone(),
            extents: self.extents
        };
    }
}

pub struct FileSystem {
    pub disk: Disk,
    pub header: Header,
    pub nodes: Vec<Node>
}

impl FileSystem {
    pub fn from_disk(disk: Disk) -> FileSystem {
        unsafe {
            let header_ptr: *const Header = alloc_type();
            disk.read(1, 1, header_ptr as usize);
            let header = ptr::read(header_ptr);
            unalloc(header_ptr as usize);

            let mut nodes = Vec::new();
            let node_data: *const NodeData = alloc_type();
            for extent in &header.extents {
                if extent.block > 0 {
                    for node_address in extent.block..extent.block + (extent.length + 511)/512 {
                        disk.read(node_address, 1, node_data as usize);

                        nodes.push(Node::new(node_address, ptr::read(node_data)));
                    }
                }
            }
            unalloc(node_data as usize);

            return FileSystem {
                disk: disk,
                header: header,
                nodes: nodes
            };
        }
    }

    pub fn valid(&self) -> bool {
        return self.header.signature[0] == 'R' as u8
            && self.header.signature[1] == 'E' as u8
            && self.header.signature[2] == 'D' as u8
            && self.header.signature[3] == 'O' as u8
            && self.header.signature[4] == 'X' as u8
            && self.header.signature[5] == 'F' as u8
            && self.header.signature[6] == 'S' as u8
            && self.header.signature[7] == '\0' as u8
            && self.header.version == 0xFFFFFFFF;
    }

    pub fn node(&self, filename: &String) -> Option<Node> {
        for node in self.nodes.iter() {
            if node.name == *filename {
                return Option::Some(node.clone());
            }
        }

        return Option::None;
    }

    pub fn list(&self, directory: &String) -> Vec<String> {
        let mut ret = Vec::<String>::new();

        for node in self.nodes.iter() {
            if node.name.starts_with(directory.clone()) {
                ret.push(node.name.substr(directory.len(), node.name.len() - directory.len()));
            }
        }

        return ret;
    }
}

pub struct FileResource {
    pub disk: Disk,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool
}

impl Resource for FileResource {
    fn url(&self) -> URL {
        return URL::from_string(&("file:///".to_string() + &self.node.name));
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Option::Some(b) => buf[i] = *b,
                Option::None => ()
            }
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec.set(self.seek, buf[i]);
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        return Option::Some(i);
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) => self.seek = max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) => self.seek = max(0, self.vec.len() as isize + offset) as usize
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        return Option::Some(self.seek);
    }

    // TODO: Rename to sync
    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    // TODO: Allow reallocation
    fn flush(&mut self) -> bool {
        let block_size = 512;

        let mut pos: usize = 0;
        for extent in &self.node.extents {
            //Make sure it is a valid extent
            if extent.block > 0 && extent.length > 0 {
                let remaining = self.vec.len() - pos;

                let current_sectors = (extent.length as usize + block_size - 1)/block_size;
                let max_size = current_sectors * 512;

                let size = min(remaining, max_size);
                let sectors = (size + block_size - 1)/block_size;

                unsafe {
                    let mem_to_write = self.vec.as_ptr().offset(pos as isize) as usize;
                    //TODO: Make sure mem_to_write is copied safely into an zeroed area of the right size!
                    let bytes_written = self.disk.write(extent.block,
                                ((size + 511)/512) as u16,
                                mem_to_write as usize);
                }

                pos += size;
            }
        }
        if pos + 1 < self.vec.len() {
            d("Need to reallocate file\n");
        }
        return true;
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        self.flush();
    }
}

pub struct FileScheme {
    pub fs: FileSystem
}

impl SessionItem for FileScheme {
    fn scheme(&self) -> String {
        return "file".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        let path = url.path();
        if path.len() == 0 || path.ends_with("/".to_string()) {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(&path).iter() {
                let line;
                match file.find("/".to_string()) {
                    Option::Some(index) => {
                        let dirname = file.substr(0, index + 1);
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line = String::new();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    },
                    Option::None => line = file.clone()
                }
                if line.len() > 0 {
                    if list.len() > 0 {
                        list = list + '\n' + line;
                    } else {
                        list = line;
                    }
                }
            }

            return box VecResource::new(url.clone(), ResourceType::Dir, list.to_utf8());
        } else {
            match self.fs.node(&path) {
                Option::Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    //TODO: Handle more extents
                    if node.extents[0].block > 0 && node.extents[0].length > 0 {
                        unsafe {
                            let data = alloc(node.extents[0].length as usize);
                            if data > 0 {
                                let reenable = start_no_ints();

                                self.fs.disk.read(node.extents[0].block, ((node.extents[0].length + 511)/512) as u16, data);

                                end_no_ints(reenable);

                                vec = Vec {
                                    data: data as *mut u8,
                                    length: node.extents[0].length as usize
                                };
                            }
                        }
                    }

                    return box FileResource {
                        disk: self.fs.disk,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false
                    };
                },
                Option::None => {
                    /*
                    d("Creating ");
                    path.d();
                    dl();

                    let mut name = [0; 256];
                    for i in 0..256 {
                        //TODO: UTF8
                        let b = path[i] as u8;
                        name[i] = b;
                        if b == 0 {
                            break;
                        }
                    }

                    let node = Node {
                        name: name,
                        extents: [Extent { block: 0, length: 0 }; 16]
                    };

                    //TODO: Sync to disk
                    let mut node_i = 0;
                    while node_i < self.fs.nodes.len() {
                        let mut cmp = 0;

                        if let Option::Some(other_node) = self.fs.nodes.get(node_i) {
                            for i in 0..256 {
                                if other_node.name[i] != node.name[i] {
                                    cmp = other_node.name[i] as isize - node.name[i] as isize;
                                    break;
                                }
                            }
                        }

                        if cmp >= 0 {
                            break;
                        }

                        node_i += 1;
                    }
                    d("Insert at ");
                    dd(node_i);
                    dl();
                    self.fs.nodes.insert(node_i, node.clone());

                    return box FileResource {
                        node: node,
                        vec: Vec::new(),
                        seek: 0
                    };
                    */
                    return box NoneResource;
                }
            }
        }
    }
}
<commit_msg>Add reallocation warning<commit_after>use common::memory::*;
use common::scheduler::*;

use drivers::disk::*;

use programs::common::*;

#[derive(Copy, Clone)]
#[repr(packed)]
pub struct Extent {
    pub block: u64,
    pub length: u64
}

#[repr(packed)]
pub struct Header {
    pub signature: [u8; 8],
    pub version: u32,
    pub name: [u8; 244],
    pub extents: [Extent; 16]
}

#[repr(packed)]
pub struct NodeData {
    pub name: [u8; 256],
    pub extents: [Extent; 16]
}

pub struct Node {
    pub address: u64,
    pub name: String,
    pub extents: [Extent; 16]
}

impl Node {
    pub fn new(address: u64, data: NodeData) -> Node {
        let mut utf8: Vec<u8> = Vec::new();
        for i in 0..data.name.len() {
            let c = data.name[i];
            if c == 0 {
                break;
            }else{
                utf8.push(c);
            }
        }

        Node {
            address: address,
            name: String::from_utf8(&utf8),
            extents: data.extents
        }
    }
}

impl Clone for Node {
    fn clone(&self) -> Node {
        return Node {
            address: self.address,
            name: self.name.clone(),
            extents: self.extents
        };
    }
}

pub struct FileSystem {
    pub disk: Disk,
    pub header: Header,
    pub nodes: Vec<Node>
}

impl FileSystem {
    pub fn from_disk(disk: Disk) -> FileSystem {
        unsafe {
            let header_ptr: *const Header = alloc_type();
            disk.read(1, 1, header_ptr as usize);
            let header = ptr::read(header_ptr);
            unalloc(header_ptr as usize);

            let mut nodes = Vec::new();
            let node_data: *const NodeData = alloc_type();
            for extent in &header.extents {
                if extent.block > 0 {
                    for node_address in extent.block..extent.block + (extent.length + 511)/512 {
                        disk.read(node_address, 1, node_data as usize);

                        nodes.push(Node::new(node_address, ptr::read(node_data)));
                    }
                }
            }
            unalloc(node_data as usize);

            return FileSystem {
                disk: disk,
                header: header,
                nodes: nodes
            };
        }
    }

    pub fn valid(&self) -> bool {
        return self.header.signature[0] == 'R' as u8
            && self.header.signature[1] == 'E' as u8
            && self.header.signature[2] == 'D' as u8
            && self.header.signature[3] == 'O' as u8
            && self.header.signature[4] == 'X' as u8
            && self.header.signature[5] == 'F' as u8
            && self.header.signature[6] == 'S' as u8
            && self.header.signature[7] == '\0' as u8
            && self.header.version == 0xFFFFFFFF;
    }

    pub fn node(&self, filename: &String) -> Option<Node> {
        for node in self.nodes.iter() {
            if node.name == *filename {
                return Option::Some(node.clone());
            }
        }

        return Option::None;
    }

    pub fn list(&self, directory: &String) -> Vec<String> {
        let mut ret = Vec::<String>::new();

        for node in self.nodes.iter() {
            if node.name.starts_with(directory.clone()) {
                ret.push(node.name.substr(directory.len(), node.name.len() - directory.len()));
            }
        }

        return ret;
    }
}

pub struct FileResource {
    pub disk: Disk,
    pub node: Node,
    pub vec: Vec<u8>,
    pub seek: usize,
    pub dirty: bool
}

impl Resource for FileResource {
    fn url(&self) -> URL {
        return URL::from_string(&("file:///".to_string() + &self.node.name));
    }

    fn stat(&self) -> ResourceType {
        return ResourceType::File;
    }

    fn read(&mut self, buf: &mut [u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            match self.vec.get(self.seek) {
                Option::Some(b) => buf[i] = *b,
                Option::None => ()
            }
            self.seek += 1;
            i += 1;
        }
        return Option::Some(i);
    }

    fn write(&mut self, buf: &[u8]) -> Option<usize> {
        let mut i = 0;
        while i < buf.len() && self.seek < self.vec.len() {
            self.vec.set(self.seek, buf[i]);
            self.seek += 1;
            i += 1;
        }
        while i < buf.len() {
            self.vec.push(buf[i]);
            self.seek += 1;
            i += 1;
        }
        if i > 0 {
            self.dirty = true;
        }
        return Option::Some(i);
    }

    fn seek(&mut self, pos: ResourceSeek) -> Option<usize> {
        match pos {
            ResourceSeek::Start(offset) => self.seek = offset,
            ResourceSeek::Current(offset) => self.seek = max(0, self.seek as isize + offset) as usize,
            ResourceSeek::End(offset) => self.seek = max(0, self.vec.len() as isize + offset) as usize
        }
        while self.vec.len() < self.seek {
            self.vec.push(0);
        }
        return Option::Some(self.seek);
    }

    // TODO: Rename to sync
    // TODO: Check to make sure proper amount of bytes written. See Disk::write
    // TODO: Allow reallocation
    fn flush(&mut self) -> bool {
        if self.dirty {
            let block_size: usize = 512;

            let mut pos: isize = 0;
            let mut remaining = self.vec.len() as isize;
            for extent in &self.node.extents {
                //Make sure it is a valid extent
                if extent.block > 0 && extent.length > 0 {
                    let current_sectors = (extent.length as usize + block_size - 1)/block_size;
                    let max_size = current_sectors * 512;

                    let size = min(remaining as usize, max_size);
                    let sectors = (size + block_size - 1)/block_size;

                    unsafe {
                        let mem_to_write = self.vec.as_ptr().offset(pos) as usize;
                        //TODO: Make sure mem_to_write is copied safely into an zeroed area of the right size!
                        let bytes_written = self.disk.write(extent.block,
                                    sectors as u16,
                                    mem_to_write as usize);
                    }

                    pos += size as isize;
                    remaining -= size as isize;
                }
            }

            self.dirty = false;

            if remaining > 0 {
                d("Need to reallocate file, extra: ");
                ds(remaining);
                dl();
                return false;
            }
        }
        return true;
    }
}

impl Drop for FileResource {
    fn drop(&mut self) {
        self.flush();
    }
}

pub struct FileScheme {
    pub fs: FileSystem
}

impl SessionItem for FileScheme {
    fn scheme(&self) -> String {
        return "file".to_string();
    }

    fn open(&mut self, url: &URL) -> Box<Resource> {
        let path = url.path();
        if path.len() == 0 || path.ends_with("/".to_string()) {
            let mut list = String::new();
            let mut dirs: Vec<String> = Vec::new();

            for file in self.fs.list(&path).iter() {
                let line;
                match file.find("/".to_string()) {
                    Option::Some(index) => {
                        let dirname = file.substr(0, index + 1);
                        let mut found = false;
                        for dir in dirs.iter() {
                            if dirname == *dir {
                                found = true;
                                break;
                            }
                        }
                        if found {
                            line = String::new();
                        } else {
                            line = dirname.clone();
                            dirs.push(dirname);
                        }
                    },
                    Option::None => line = file.clone()
                }
                if line.len() > 0 {
                    if list.len() > 0 {
                        list = list + '\n' + line;
                    } else {
                        list = line;
                    }
                }
            }

            return box VecResource::new(url.clone(), ResourceType::Dir, list.to_utf8());
        } else {
            match self.fs.node(&path) {
                Option::Some(node) => {
                    let mut vec: Vec<u8> = Vec::new();
                    //TODO: Handle more extents
                    if node.extents[0].block > 0 && node.extents[0].length > 0 {
                        unsafe {
                            let data = alloc(node.extents[0].length as usize);
                            if data > 0 {
                                let reenable = start_no_ints();

                                self.fs.disk.read(node.extents[0].block, ((node.extents[0].length + 511)/512) as u16, data);

                                end_no_ints(reenable);

                                vec = Vec {
                                    data: data as *mut u8,
                                    length: node.extents[0].length as usize
                                };
                            }
                        }
                    }

                    return box FileResource {
                        disk: self.fs.disk,
                        node: node,
                        vec: vec,
                        seek: 0,
                        dirty: false
                    };
                },
                Option::None => {
                    /*
                    d("Creating ");
                    path.d();
                    dl();

                    let mut name = [0; 256];
                    for i in 0..256 {
                        //TODO: UTF8
                        let b = path[i] as u8;
                        name[i] = b;
                        if b == 0 {
                            break;
                        }
                    }

                    let node = Node {
                        name: name,
                        extents: [Extent { block: 0, length: 0 }; 16]
                    };

                    //TODO: Sync to disk
                    let mut node_i = 0;
                    while node_i < self.fs.nodes.len() {
                        let mut cmp = 0;

                        if let Option::Some(other_node) = self.fs.nodes.get(node_i) {
                            for i in 0..256 {
                                if other_node.name[i] != node.name[i] {
                                    cmp = other_node.name[i] as isize - node.name[i] as isize;
                                    break;
                                }
                            }
                        }

                        if cmp >= 0 {
                            break;
                        }

                        node_i += 1;
                    }
                    d("Insert at ");
                    dd(node_i);
                    dl();
                    self.fs.nodes.insert(node_i, node.clone());

                    return box FileResource {
                        node: node,
                        vec: Vec::new(),
                        seek: 0
                    };
                    */
                    return box NoneResource;
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>/**@file
 *
 * Module `symbol::scope`: traits useful for defining scope-like hierarchies of
 * value maps, keyed by Symbols.
 */
use super::Nameable;

/** Trait that defines a method to find the root of a scope hierarchy.
 *
 * @tparam T Root scope type.
 */
pub trait HasRootScope<T>
{ fn root_scope(&self) -> intrusive::Ref<T>; }

#[macro_export]
macro_rules! default_has_root_scope_impl {
    ($target:ty, $rstype:ty, $($mbr:ident).*) => (
        impl HasRootScope<$rstype> for $target {
            fn root_scope(&self) -> intrusive::Ref<$rstype> {
                self . $($mbr).+ . root_scope()
            }
        }
    );
}

/** Trait for types that define a method to find an instance's parent scope.
 */
pub trait HasParentScope<T>
{ fn parent_scope(&self) -> intrusive::Ref<T>; }

#[macro_export]
macro_rules! default_has_parent_scope_impl {
    ($target:ty, $pstype:ty, $($mbr:ident).*) => (
        impl HasParentScope<$pstype> for $target {
            fn parent_scope(&self) -> intrusive::Ref<$pstype> {
                self . $($mbr).+ . clone()
            }
        }
    );
}

pub trait RootScope<ValueType>: HasRootScope<Self> where ValueType: super::Nameable
{}

/*

/* ****************************************************************
 * SymbolTable
 */

/** A flexible, generic symbol-table utility for generated analyzers.
 */
pub struct
SymbolTable<RootScopeType: intrusive::RefCounted,
            ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted,
            ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
{
    name: intrusive::Ref<Symbol>,
    search_upward: bool,
    search_downward: bool,
    max_search_depth: usize,
    pool: Rc<SymbolPool>,
    map: HashMap<intrusive::Ref<Symbol>,intrusive::Ref<ValueType>>,
    root_scope: intrusive::Ref<RootScopeType>,
    parent_scope: intrusive::Ref<ParentScopeType>
}

/* ================================================================
 * impl Eq, PartialEq
 */
impl<RootScopeType: intrusive::RefCounted + Eq,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted + Eq,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
Eq for SymbolTable<RootScopeType,ParentScopeType,ValueType> {}

impl<RootScopeType: intrusive::RefCounted + Eq,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted + Eq,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
PartialEq<SymbolTable<RootScopeType,ParentScopeType,ValueType>>
for SymbolTable<RootScopeType,ParentScopeType,ValueType> {
    fn eq(&self, other: &Self) -> bool {
        self.name == other.name && self.search_upward == other.search_upward &&
        self.search_downward == other.search_downward && self.max_search_depth == other.max_search_depth &&
        self.pool == other.pool && self.map == other.map && self.root_scope == other.root_scope &&
        self.parent_scope == other.parent_scope
    }
}

/* ================================================================
 * impl std::fmt::Debug
 */
impl<RootScopeType: intrusive::RefCounted,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
std::fmt::Debug
for SymbolTable<RootScopeType,ParentScopeType,ValueType>
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        let mut first = true;
        try!(write!(f, "{{"));

        for (key, value) in self.map.iter() {
            if first {
                try!(write!(f, ", "));
                first = false;
            }
            try!(write!(f, "{:?}: {:?}", key, *value));
        }
        write!(f, "}}")
    }
}

/* ================================================================
 * impl Nameable
 */
impl<RootScopeType: intrusive::RefCounted,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
Nameable
for SymbolTable<RootScopeType,ParentScopeType,ValueType>
{
    fn name(&self) -> intrusive::Ref<Symbol>
    { self.name.clone() }
}

/* ================================================================
 * impl HasParentScope<ParentScopeType>
 */
impl<RootScopeType: intrusive::RefCounted,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
HasParentScope<ParentScopeType>
for SymbolTable<RootScopeType,ParentScopeType,ValueType>
{
    fn parent_scope(&self) -> intrusive::Ref<ParentScopeType>
    { self.parent_scope.clone() }
}

/* ================================================================
 * impl HasRootScope<ParentScopeType>
 */
impl<RootScopeType: intrusive::RefCounted,
     ParentScopeType: HasRootScope<RootScopeType> + intrusive::RefCounted,
     ValueType: super::Nameable + HasParentScope<ParentScopeType> + intrusive::RefCounted + std::fmt::Debug>
HasRootScope<RootScopeType>
for SymbolTable<RootScopeType,ParentScopeType,ValueType>
{
    fn root_scope(&self) -> intrusive::Ref<RootScopeType> {
        self.root_scope.clone()
    }
}
*/
<commit_msg>src/symbol/scope.rs:  removing ancient unused cruft<commit_after><|endoftext|>


<commit_before>use core;
use docopt;
use time;
use std::error;
use crypto::symmetriccipher::SymmetricCipherError;
use std::io::{IoError};
use std::string::FromUtf8Error;

pub use self::ErrorKind::{
    InternalIoError,
    GenericError
};

pub enum ErrorKind {
    InternalIoError(IoError),
    GenericError
}

pub struct ThecaError {
    pub kind: ErrorKind,
    pub desc: String,
    pub detail: Option<String>
}

#[macro_export]
macro_rules! specific_fail {
    ($short:expr) => {
        return Err(::std::error::FromError::from_error(
            ThecaError {
                kind: GenericError,
                desc: $short,
                detail: None
            }
        ))
    }
}

macro_rules! try_errno {
    ($e:expr) => {
        {
            use std::io::{IoError};
            use std::os::errno;
            let err = $e;
            if err != 0 {
                return Err(::std::error::FromError::from_error(IoError::from_errno(errno() as usize, true)));
            }
        }
    }
}

impl error::FromError<IoError> for ThecaError {
    fn from_error(err: IoError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.desc.to_string(),
            detail: None
        }
    }
}

impl error::FromError<(ErrorKind, &'static str)> for ThecaError {
    fn from_error((kind, desc): (ErrorKind, &'static str)) -> ThecaError {
        ThecaError { kind: kind, desc: desc.to_string(), detail: None }
    }
}

impl error::FromError<time::ParseError> for ThecaError {
    fn from_error(err: time::ParseError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("time parsing error: {}.", err),
            detail: None
        }
    }
}

impl error::FromError<FromUtf8Error> for ThecaError {
    fn from_error(err: FromUtf8Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("error parsing utf-8, is profile encrypted?\n({})", err),
            detail: None
        }
    }
}

impl error::FromError<SymmetricCipherError> for ThecaError {
    fn from_error(_: SymmetricCipherError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "invalid encryption key".to_string(),
            detail: None
        }
    }
}

impl error::FromError<docopt::Error> for ThecaError {
    fn from_error(err: docopt::Error) -> ThecaError {
        ThecaError { kind: GenericError, desc: err.to_string(), detail: None }
    }
}

impl error::FromError<core::fmt::Error> for ThecaError {
    fn from_error(_: core::fmt::Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "formatting error.".to_string(),
            detail: None
        }
    }
}
<commit_msg>some other stuff<commit_after>use core;
use docopt;
use time;
use std::error;
use crypto::symmetriccipher::SymmetricCipherError;
use std::io::{IoError};
use std::string::FromUtf8Error;

pub use self::ErrorKind::{
    InternalIoError,
    GenericError
};

pub enum ErrorKind {
    InternalIoError(IoError),
    GenericError
}

pub struct ThecaError {
    pub kind: ErrorKind,
    pub desc: String,
    pub detail: Option<String>
}

#[macro_export]
macro_rules! specific_fail {
    ($short:expr) => {
        return Err(::std::error::FromError::from_error(
            ThecaError {
                kind: GenericError,
                desc: $short,
                detail: None
            }
        ))
    }
}

macro_rules! try_errno {
    ($e:expr) => {
        {
            use std::io::{IoError};
            use std::os::errno;
            let err = $e;
            if err != 0 {
                return Err(::std::error::FromError::from_error(IoError::from_errno(errno() as usize, true)));
            }
        }
    }
}

impl error::FromError<IoError> for ThecaError {
    fn from_error(err: IoError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: err.desc.to_string(),
            detail: None
        }
    }
}

impl error::FromError<(ErrorKind, &'static str)> for ThecaError {
    fn from_error((kind, desc): (ErrorKind, &'static str)) -> ThecaError {
        ThecaError { kind: kind, desc: desc.to_string(), detail: None }
    }
}

impl error::FromError<time::ParseError> for ThecaError {
    fn from_error(err: time::ParseError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("\ntime parsing error: {}", err),
            detail: None
        }
    }
}

impl error::FromError<FromUtf8Error> for ThecaError {
    fn from_error(err: FromUtf8Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: format!("\nerror parsing utf-8, is profile encrypted?\n({})", err),
            detail: None
        }
    }
}

impl error::FromError<SymmetricCipherError> for ThecaError {
    fn from_error(_: SymmetricCipherError) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\ninvalid encryption key".to_string(),
            detail: None
        }
    }
}

impl error::FromError<docopt::Error> for ThecaError {
    fn from_error(err: docopt::Error) -> ThecaError {
        ThecaError { kind: GenericError, desc: err.to_string(), detail: None }
    }
}

impl error::FromError<core::fmt::Error> for ThecaError {
    fn from_error(_: core::fmt::Error) -> ThecaError {
        ThecaError {
            kind: GenericError,
            desc: "\nformatting error".to_string(),
            detail: None
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc::{c_int, c_uint, c_float, c_double};
use glib::translate::{from_glib_none, from_glib_full, ToGlibPtr};

use {EntryIconPosition, ImageType, InputPurpose, InputHints};
use cast::GTK_ENTRY;
use ffi;
use glib::{to_bool, to_gboolean};

pub trait EntryTrait: ::WidgetTrait {
    fn get_buffer(&self) -> ::EntryBuffer {
        let tmp_pointer = unsafe { ffi::gtk_entry_get_buffer(GTK_ENTRY(self.unwrap_widget())) };

        ::EntryBuffer::wrap_pointer(tmp_pointer)
    }

    fn set_buffer(&self, buffer: &::EntryBuffer) -> () {
        unsafe {
            ffi::gtk_entry_set_buffer(GTK_ENTRY(self.unwrap_widget()), buffer.unwrap_pointer())
        }
    }

    fn set_text(&self, text: &str) {
        unsafe {
            ffi::gtk_entry_set_text(GTK_ENTRY(self.unwrap_widget()), text.to_glib_none().0)
        }
    }

    fn get_text(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_text(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn get_text_length(&self) -> i16 {
        unsafe {
            ffi::gtk_entry_get_text_length(GTK_ENTRY(self.unwrap_widget())) as i16
        }
    }

    fn set_visibility(&self, visible: bool) -> () {
        unsafe { ffi::gtk_entry_set_visibility(GTK_ENTRY(self.unwrap_widget()), to_gboolean(visible)); }
    }

    fn set_invisible_char(&self, ch: char) -> () {
        unsafe {
            ffi::gtk_entry_set_invisible_char(GTK_ENTRY(self.unwrap_widget()), ch as c_uint);
        }
    }

    fn unset_invisible_char(&self) -> () {
        unsafe {
            ffi::gtk_entry_unset_invisible_char(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn set_max_length(&self, max_length: i32) -> () {
        unsafe {
            ffi::gtk_entry_set_max_length(GTK_ENTRY(self.unwrap_widget()), max_length as c_int);
        }
    }

    fn get_activates_default(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_activates_default(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn get_has_frame(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_has_frame(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn get_width_chars(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_width_chars(GTK_ENTRY(self.unwrap_widget()))
        }
    }

    fn set_activates_default(&self, setting: bool) {
        unsafe { ffi::gtk_entry_set_activates_default(GTK_ENTRY(self.unwrap_widget()), to_gboolean(setting)); }
    }

    fn set_has_frame(&self, setting: bool) {
        unsafe { ffi::gtk_entry_set_has_frame(GTK_ENTRY(self.unwrap_widget()), to_gboolean(setting)); }
    }

    fn set_width_chars(&self, n_chars: i32) -> () {
        unsafe {
            ffi::gtk_entry_set_width_chars(GTK_ENTRY(self.unwrap_widget()), n_chars as c_int);
        }
    }

    fn get_invisible_char(&self) -> u32 {
        unsafe {
            ffi::gtk_entry_get_invisible_char(GTK_ENTRY(self.unwrap_widget())) as u32
        }
    }

    fn set_alignment(&self, x_align: f32) -> () {
        unsafe {
            ffi::gtk_entry_set_alignment(GTK_ENTRY(self.unwrap_widget()), x_align as c_float);
        }
    }

    fn get_alignment(&self) -> f32 {
        unsafe {
            ffi::gtk_entry_get_alignment(GTK_ENTRY(self.unwrap_widget())) as f32
        }
    }

    fn set_placeholder(&self, text: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_placeholder_text(GTK_ENTRY(self.unwrap_widget()), text.to_glib_none().0)
        }
    }

    fn placeholder(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_placeholder_text(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn get_overwrite_mode(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_overwrite_mode(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn set_overwrite_mode(&self, overwrite: bool) {
        unsafe { ffi::gtk_entry_set_overwrite_mode(GTK_ENTRY(self.unwrap_widget()), to_gboolean(overwrite)); }
    }

    fn get_layout_offsets(&self) -> (i32, i32) {
        let mut x = 0;
        let mut y = 0;

        unsafe {
            ffi::gtk_entry_get_layout_offsets(GTK_ENTRY(self.unwrap_widget()), &mut x, &mut y);
        }
        (x, y)
    }

    fn layout_index_to_text_index(&self, layout_index: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_layout_index_to_text_index(GTK_ENTRY(self.unwrap_widget()), layout_index as c_int) as i32
        }
    }

    fn text_index_to_layout_index(&self, text_index: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_text_index_to_layout_index(GTK_ENTRY(self.unwrap_widget()), text_index as c_int) as i32
        }
    }

    fn get_max_length(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_max_length(GTK_ENTRY(self.unwrap_widget())) as i32
        }
    }

    fn get_visibility(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_visibility(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn set_cursor_hadjustment(&self, adjustment: &::Adjustment) -> () {
        unsafe {
            ffi::gtk_entry_set_cursor_hadjustment(GTK_ENTRY(self.unwrap_widget()), adjustment.unwrap_pointer())
        }
    }

    fn get_cursor_hadjustment(&self) -> ::Adjustment {
        unsafe {
            ::Adjustment::wrap_pointer(ffi::gtk_entry_get_cursor_hadjustment(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn set_progress_fraction(&self, fraction: f64) -> () {
        unsafe {
            ffi::gtk_entry_set_progress_fraction(GTK_ENTRY(self.unwrap_widget()), fraction as c_double);
        }
    }

    fn get_progress_fraction(&self) -> f64 {
        unsafe {
            ffi::gtk_entry_get_progress_fraction(GTK_ENTRY(self.unwrap_widget())) as f64
        }
    }

    fn set_progress_pulse_step(&self, pulse_step: f64) -> () {
        unsafe {
            ffi::gtk_entry_set_progress_pulse_step(GTK_ENTRY(self.unwrap_widget()), pulse_step as c_double);
        }
    }

    fn get_progress_pulse_step(&self) -> f64 {
        unsafe {
            ffi::gtk_entry_get_progress_pulse_step(GTK_ENTRY(self.unwrap_widget())) as f64
        }
    }

    fn progress_pulse(&self) -> () {
        unsafe {
            ffi::gtk_entry_progress_pulse(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn reset_im_context(&self) -> () {
        unsafe {
            ffi::gtk_entry_reset_im_context(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn set_icon_from_stock(&self, icon_pos: EntryIconPosition, stock_id: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_from_stock(GTK_ENTRY(self.unwrap_widget()), icon_pos, stock_id.to_glib_none().0);
        }
    }

    fn set_icon_from_icon_name(&self, icon_pos: EntryIconPosition, icon_name: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_from_icon_name(GTK_ENTRY(self.unwrap_widget()), icon_pos, icon_name.to_glib_none().0)
        }
    }

    fn get_icon_storage_type(&self, icon_pos: EntryIconPosition) -> ImageType {
        unsafe {
            ffi::gtk_entry_get_icon_storage_type(GTK_ENTRY(self.unwrap_widget()), icon_pos)
        }
    }

    fn get_icon_stock(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_icon_stock(GTK_ENTRY(self.unwrap_widget()), icon_pos))
        }
    }

    fn get_icon_name(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_icon_name(GTK_ENTRY(self.unwrap_widget()), icon_pos))
        }
    }

    fn get_icon_activatable(&self, icon_pos: EntryIconPosition) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_icon_activatable(GTK_ENTRY(self.unwrap_widget()), icon_pos)) }
    }

    fn set_icon_activatable(&self, icon_pos: EntryIconPosition, activatable: bool) {
        unsafe { ffi::gtk_entry_set_icon_activatable(GTK_ENTRY(self.unwrap_widget()), icon_pos, to_gboolean(activatable)); }
    }

    fn get_icon_sensitive(&self, icon_pos: EntryIconPosition) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_icon_sensitive(GTK_ENTRY(self.unwrap_widget()), icon_pos)) }
    }

    fn set_icon_sensitive(&self, icon_pos: EntryIconPosition, sensitive: bool) {
        unsafe { ffi::gtk_entry_set_icon_sensitive(GTK_ENTRY(self.unwrap_widget()), icon_pos, to_gboolean(sensitive)); }
    }

    fn get_icon_at_pos(&self, x: i32, y: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_get_icon_at_pos(GTK_ENTRY(self.unwrap_widget()), x, y) as i32
        }
    }

    fn set_icon_tooltip_text(&self, icon_pos: EntryIconPosition, tooltip: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_tooltip_text(GTK_ENTRY(self.unwrap_widget()), icon_pos, tooltip.to_glib_none().0)
        }
    }

    fn get_icon_tooltip_text(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_entry_get_icon_tooltip_text(GTK_ENTRY(self.unwrap_widget()),
                                                     icon_pos))
        }
    }

    fn set_icon_tooltip_markup(&self, icon_pos: EntryIconPosition, tooltip: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(self.unwrap_widget()), icon_pos, tooltip.to_glib_none().0)
        }
    }

    fn get_icon_tooltip_markup(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_entry_get_icon_tooltip_markup(GTK_ENTRY(self.unwrap_widget()),
                                                       icon_pos))
        }
    }

    fn get_current_icon_draw_source(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_current_icon_drag_source(GTK_ENTRY(self.unwrap_widget())) as i32
        }
    }

    fn set_input_purpose(&self, purpose: InputPurpose) -> () {
        unsafe {
            ffi::gtk_entry_set_input_purpose(GTK_ENTRY(self.unwrap_widget()), purpose)
        }
    }

    fn get_input_purpose(&self) -> InputPurpose {
        unsafe {
            ffi::gtk_entry_get_input_purpose(GTK_ENTRY(self.unwrap_widget()))
        }
    }

    fn set_input_hints(&self, hints: InputHints) -> () {
        unsafe {
            ffi::gtk_entry_set_input_hints(GTK_ENTRY(self.unwrap_widget()), hints)
        }
    }

    fn get_input_hints(&self) -> InputHints {
        unsafe {
            ffi::gtk_entry_get_input_hints(GTK_ENTRY(self.unwrap_widget()))
        }
    }
}
<commit_msg>Added missing functions for setting and getting completion<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use libc::{c_int, c_uint, c_float, c_double};
use glib::translate::{from_glib_none, from_glib_full, ToGlibPtr};

use {EntryCompletion, EntryIconPosition, FFIWidget, ImageType, InputPurpose, InputHints};
use cast::{GTK_ENTRY, GTK_ENTRY_COMPLETION};
use ffi;
use glib::{to_bool, to_gboolean};

pub trait EntryTrait: ::WidgetTrait {
    fn get_buffer(&self) -> ::EntryBuffer {
        let tmp_pointer = unsafe { ffi::gtk_entry_get_buffer(GTK_ENTRY(self.unwrap_widget())) };

        ::EntryBuffer::wrap_pointer(tmp_pointer)
    }

    fn set_buffer(&self, buffer: &::EntryBuffer) -> () {
        unsafe {
            ffi::gtk_entry_set_buffer(GTK_ENTRY(self.unwrap_widget()), buffer.unwrap_pointer())
        }
    }

    fn set_text(&self, text: &str) {
        unsafe {
            ffi::gtk_entry_set_text(GTK_ENTRY(self.unwrap_widget()), text.to_glib_none().0)
        }
    }

    fn get_text(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_text(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn get_text_length(&self) -> i16 {
        unsafe {
            ffi::gtk_entry_get_text_length(GTK_ENTRY(self.unwrap_widget())) as i16
        }
    }

    fn set_visibility(&self, visible: bool) -> () {
        unsafe { ffi::gtk_entry_set_visibility(GTK_ENTRY(self.unwrap_widget()), to_gboolean(visible)); }
    }

    fn set_invisible_char(&self, ch: char) -> () {
        unsafe {
            ffi::gtk_entry_set_invisible_char(GTK_ENTRY(self.unwrap_widget()), ch as c_uint);
        }
    }

    fn unset_invisible_char(&self) -> () {
        unsafe {
            ffi::gtk_entry_unset_invisible_char(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn set_max_length(&self, max_length: i32) -> () {
        unsafe {
            ffi::gtk_entry_set_max_length(GTK_ENTRY(self.unwrap_widget()), max_length as c_int);
        }
    }

    fn get_activates_default(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_activates_default(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn get_has_frame(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_has_frame(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn get_width_chars(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_width_chars(GTK_ENTRY(self.unwrap_widget()))
        }
    }

    fn set_activates_default(&self, setting: bool) {
        unsafe { ffi::gtk_entry_set_activates_default(GTK_ENTRY(self.unwrap_widget()), to_gboolean(setting)); }
    }

    fn set_has_frame(&self, setting: bool) {
        unsafe { ffi::gtk_entry_set_has_frame(GTK_ENTRY(self.unwrap_widget()), to_gboolean(setting)); }
    }

    fn set_width_chars(&self, n_chars: i32) -> () {
        unsafe {
            ffi::gtk_entry_set_width_chars(GTK_ENTRY(self.unwrap_widget()), n_chars as c_int);
        }
    }

    fn get_invisible_char(&self) -> u32 {
        unsafe {
            ffi::gtk_entry_get_invisible_char(GTK_ENTRY(self.unwrap_widget())) as u32
        }
    }

    fn set_alignment(&self, x_align: f32) -> () {
        unsafe {
            ffi::gtk_entry_set_alignment(GTK_ENTRY(self.unwrap_widget()), x_align as c_float);
        }
    }

    fn get_alignment(&self) -> f32 {
        unsafe {
            ffi::gtk_entry_get_alignment(GTK_ENTRY(self.unwrap_widget())) as f32
        }
    }

    fn set_placeholder(&self, text: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_placeholder_text(GTK_ENTRY(self.unwrap_widget()), text.to_glib_none().0)
        }
    }

    fn placeholder(&self) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_placeholder_text(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn get_overwrite_mode(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_overwrite_mode(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn set_overwrite_mode(&self, overwrite: bool) {
        unsafe { ffi::gtk_entry_set_overwrite_mode(GTK_ENTRY(self.unwrap_widget()), to_gboolean(overwrite)); }
    }

    fn get_layout_offsets(&self) -> (i32, i32) {
        let mut x = 0;
        let mut y = 0;

        unsafe {
            ffi::gtk_entry_get_layout_offsets(GTK_ENTRY(self.unwrap_widget()), &mut x, &mut y);
        }
        (x, y)
    }

    fn layout_index_to_text_index(&self, layout_index: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_layout_index_to_text_index(GTK_ENTRY(self.unwrap_widget()), layout_index as c_int) as i32
        }
    }

    fn text_index_to_layout_index(&self, text_index: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_text_index_to_layout_index(GTK_ENTRY(self.unwrap_widget()), text_index as c_int) as i32
        }
    }

    fn get_max_length(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_max_length(GTK_ENTRY(self.unwrap_widget())) as i32
        }
    }

    fn get_visibility(&self) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_visibility(GTK_ENTRY(self.unwrap_widget()))) }
    }

    fn set_completion(&self, completion: &EntryCompletion) -> () {
        unsafe {
            ffi::gtk_entry_set_completion(GTK_ENTRY(self.unwrap_widget()), GTK_ENTRY_COMPLETION(completion.unwrap_widget()));
        }
    }

    fn get_completion(&self) -> Option<EntryCompletion> {
        let tmp_pointer = unsafe { ffi::gtk_entry_get_completion(GTK_ENTRY(self.unwrap_widget())) };

        if tmp_pointer.is_null() {
            None
        } else {
            Some(EntryCompletion::wrap_widget(tmp_pointer as *mut ffi::GtkWidget))
        }
    }

    fn set_cursor_hadjustment(&self, adjustment: &::Adjustment) -> () {
        unsafe {
            ffi::gtk_entry_set_cursor_hadjustment(GTK_ENTRY(self.unwrap_widget()), adjustment.unwrap_pointer())
        }
    }

    fn get_cursor_hadjustment(&self) -> ::Adjustment {
        unsafe {
            ::Adjustment::wrap_pointer(ffi::gtk_entry_get_cursor_hadjustment(GTK_ENTRY(self.unwrap_widget())))
        }
    }

    fn set_progress_fraction(&self, fraction: f64) -> () {
        unsafe {
            ffi::gtk_entry_set_progress_fraction(GTK_ENTRY(self.unwrap_widget()), fraction as c_double);
        }
    }

    fn get_progress_fraction(&self) -> f64 {
        unsafe {
            ffi::gtk_entry_get_progress_fraction(GTK_ENTRY(self.unwrap_widget())) as f64
        }
    }

    fn set_progress_pulse_step(&self, pulse_step: f64) -> () {
        unsafe {
            ffi::gtk_entry_set_progress_pulse_step(GTK_ENTRY(self.unwrap_widget()), pulse_step as c_double);
        }
    }

    fn get_progress_pulse_step(&self) -> f64 {
        unsafe {
            ffi::gtk_entry_get_progress_pulse_step(GTK_ENTRY(self.unwrap_widget())) as f64
        }
    }

    fn progress_pulse(&self) -> () {
        unsafe {
            ffi::gtk_entry_progress_pulse(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn reset_im_context(&self) -> () {
        unsafe {
            ffi::gtk_entry_reset_im_context(GTK_ENTRY(self.unwrap_widget()));
        }
    }

    fn set_icon_from_stock(&self, icon_pos: EntryIconPosition, stock_id: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_from_stock(GTK_ENTRY(self.unwrap_widget()), icon_pos, stock_id.to_glib_none().0);
        }
    }

    fn set_icon_from_icon_name(&self, icon_pos: EntryIconPosition, icon_name: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_from_icon_name(GTK_ENTRY(self.unwrap_widget()), icon_pos, icon_name.to_glib_none().0)
        }
    }

    fn get_icon_storage_type(&self, icon_pos: EntryIconPosition) -> ImageType {
        unsafe {
            ffi::gtk_entry_get_icon_storage_type(GTK_ENTRY(self.unwrap_widget()), icon_pos)
        }
    }

    fn get_icon_stock(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_icon_stock(GTK_ENTRY(self.unwrap_widget()), icon_pos))
        }
    }

    fn get_icon_name(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_none(ffi::gtk_entry_get_icon_name(GTK_ENTRY(self.unwrap_widget()), icon_pos))
        }
    }

    fn get_icon_activatable(&self, icon_pos: EntryIconPosition) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_icon_activatable(GTK_ENTRY(self.unwrap_widget()), icon_pos)) }
    }

    fn set_icon_activatable(&self, icon_pos: EntryIconPosition, activatable: bool) {
        unsafe { ffi::gtk_entry_set_icon_activatable(GTK_ENTRY(self.unwrap_widget()), icon_pos, to_gboolean(activatable)); }
    }

    fn get_icon_sensitive(&self, icon_pos: EntryIconPosition) -> bool {
        unsafe { to_bool(ffi::gtk_entry_get_icon_sensitive(GTK_ENTRY(self.unwrap_widget()), icon_pos)) }
    }

    fn set_icon_sensitive(&self, icon_pos: EntryIconPosition, sensitive: bool) {
        unsafe { ffi::gtk_entry_set_icon_sensitive(GTK_ENTRY(self.unwrap_widget()), icon_pos, to_gboolean(sensitive)); }
    }

    fn get_icon_at_pos(&self, x: i32, y: i32) -> i32 {
        unsafe {
            ffi::gtk_entry_get_icon_at_pos(GTK_ENTRY(self.unwrap_widget()), x, y) as i32
        }
    }

    fn set_icon_tooltip_text(&self, icon_pos: EntryIconPosition, tooltip: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_tooltip_text(GTK_ENTRY(self.unwrap_widget()), icon_pos, tooltip.to_glib_none().0)
        }
    }

    fn get_icon_tooltip_text(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_entry_get_icon_tooltip_text(GTK_ENTRY(self.unwrap_widget()),
                                                     icon_pos))
        }
    }

    fn set_icon_tooltip_markup(&self, icon_pos: EntryIconPosition, tooltip: &str) -> () {
        unsafe {
            ffi::gtk_entry_set_icon_tooltip_markup(GTK_ENTRY(self.unwrap_widget()), icon_pos, tooltip.to_glib_none().0)
        }
    }

    fn get_icon_tooltip_markup(&self, icon_pos: EntryIconPosition) -> Option<String> {
        unsafe {
            from_glib_full(
                ffi::gtk_entry_get_icon_tooltip_markup(GTK_ENTRY(self.unwrap_widget()),
                                                       icon_pos))
        }
    }

    fn get_current_icon_draw_source(&self) -> i32 {
        unsafe {
            ffi::gtk_entry_get_current_icon_drag_source(GTK_ENTRY(self.unwrap_widget())) as i32
        }
    }

    fn set_input_purpose(&self, purpose: InputPurpose) -> () {
        unsafe {
            ffi::gtk_entry_set_input_purpose(GTK_ENTRY(self.unwrap_widget()), purpose)
        }
    }

    fn get_input_purpose(&self) -> InputPurpose {
        unsafe {
            ffi::gtk_entry_get_input_purpose(GTK_ENTRY(self.unwrap_widget()))
        }
    }

    fn set_input_hints(&self, hints: InputHints) -> () {
        unsafe {
            ffi::gtk_entry_set_input_hints(GTK_ENTRY(self.unwrap_widget()), hints)
        }
    }

    fn get_input_hints(&self) -> InputHints {
        unsafe {
            ffi::gtk_entry_get_input_hints(GTK_ENTRY(self.unwrap_widget()))
        }
    }
}
<|endoftext|>


<commit_before>//! Support for the DMABuf type

use wlroots_sys::{wl_display, wlr_linux_dmabuf_v1, wlr_linux_dmabuf_v1_create,
                wlr_linux_dmabuf_v1_destroy};
use {crate::compositor::Compositor,
    crate::render::GenericRenderer};

#[derive(Debug)]
pub struct Dmabuf {
    dmabuf: *mut wlr_linux_dmabuf_v1
}

impl Dmabuf {
    pub fn new(compositor: &Compositor) -> Option<Self> {
        unsafe {
            // Get the renderer from compositor
            let renderer: Option<&GenericRenderer> = compositor.renderer.as_ref();
            match renderer {
                Some(ref renderer) => {
                    let dmabuf_raw = wlr_linux_dmabuf_v1_create(compositor.display as *mut wl_display, renderer.as_ptr());
                    if !dmabuf_raw.is_null() {
                        Some(Dmabuf { dmabuf: dmabuf_raw })
                    } else {
                        None
                    }
                }
                None => None
            }
        }
    }
    // TODO wrap rest of dmabuf
}

impl Drop for Dmabuf {
    fn drop(&mut self) {
        unsafe { wlr_linux_dmabuf_v1_destroy(self.dmabuf) }
    }
}
<commit_msg>remove TODO<commit_after>//! Support for the DMABuf type

use wlroots_sys::{wl_display, wlr_linux_dmabuf_v1, wlr_linux_dmabuf_v1_create,
                wlr_linux_dmabuf_v1_destroy};
use {crate::compositor::Compositor,
    crate::render::GenericRenderer};

#[derive(Debug)]
pub struct Dmabuf {
    dmabuf: *mut wlr_linux_dmabuf_v1
}

impl Dmabuf {
    pub fn new(compositor: &Compositor) -> Option<Self> {
        unsafe {
            // Get the renderer from compositor
            let renderer: Option<&GenericRenderer> = compositor.renderer.as_ref();
            match renderer {
                Some(ref renderer) => {
                    let dmabuf_raw = wlr_linux_dmabuf_v1_create(compositor.display as *mut wl_display, renderer.as_ptr());
                    if !dmabuf_raw.is_null() {
                        Some(Dmabuf { dmabuf: dmabuf_raw })
                    } else {
                        None
                    }
                }
                None => None
            }
        }
    }
}

impl Drop for Dmabuf {
    fn drop(&mut self) {
        unsafe { wlr_linux_dmabuf_v1_destroy(self.dmabuf) }
    }
}
<|endoftext|>


<commit_before>use crate::value::de::{MapDeserializer, MapRefDeserializer, SeqDeserializer, SeqRefDeserializer};
use crate::value::Value;
use crate::Error;
use serde::de::value::{BorrowedStrDeserializer, StrDeserializer};
use serde::de::{
    Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, VariantAccess, Visitor,
};
use serde::ser::{Serialize, SerializeMap, Serializer};
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};

/// A representation of YAML's `!Tag` syntax, used for enums.
///
/// Refer to the example code on [`TaggedValue`] for an example of deserializing
/// tagged values.
#[derive(Clone)]
pub struct Tag {
    pub(crate) string: String,
}

/// A `Tag` + `Value` representing a tagged YAML scalar, sequence, or mapping.
///
/// ```
/// use serde_yaml::value::TaggedValue;
/// use std::collections::BTreeMap;
///
/// let yaml = "
///     scalar: !Thing x
///     sequence_flow: !Thing [first]
///     sequence_block: !Thing
///       - first
///     mapping_flow: !Thing {k: v}
///     mapping_block: !Thing
///       k: v
/// ";
///
/// let data: BTreeMap<String, TaggedValue> = serde_yaml::from_str(yaml).unwrap();
/// assert!(data["scalar"].tag == "Thing");
/// assert!(data["sequence_flow"].tag == "Thing");
/// assert!(data["sequence_block"].tag == "Thing");
/// assert!(data["mapping_flow"].tag == "Thing");
/// assert!(data["mapping_block"].tag == "Thing");
///
/// // The leading '!' in tags are not significant. The following is also true.
/// assert!(data["scalar"].tag == "!Thing");
/// ```
#[derive(Clone, PartialEq, PartialOrd, Hash, Debug)]
pub struct TaggedValue {
    #[allow(missing_docs)]
    pub tag: Tag,
    #[allow(missing_docs)]
    pub value: Value,
}

impl Tag {
    /// Create tag.
    ///
    /// The leading '!' is not significant. It may be provided, but does not
    /// have to be. The following are equivalent:
    ///
    /// ```
    /// use serde_yaml::value::Tag;
    ///
    /// assert_eq!(Tag::new("!Thing"), Tag::new("Thing"));
    ///
    /// let tag = Tag::new("Thing");
    /// assert!(tag == "Thing");
    /// assert!(tag == "!Thing");
    /// assert!(tag.to_string() == "!Thing");
    ///
    /// let tag = Tag::new("!Thing");
    /// assert!(tag == "Thing");
    /// assert!(tag == "!Thing");
    /// assert!(tag.to_string() == "!Thing");
    /// ```
    ///
    /// Such a tag would serialize to `!Thing` in YAML regardless of whether a
    /// '!' was included in the call to `Tag::new`.
    pub fn new(string: impl Into<String>) -> Self {
        Tag {
            string: string.into(),
        }
    }
}

impl Value {
    pub(crate) fn untag(self) -> Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = tagged.value;
        }
        cur
    }

    pub(crate) fn untag_ref(&self) -> &Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = &tagged.value;
        }
        cur
    }

    pub(crate) fn untag_mut(&mut self) -> &mut Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = &mut tagged.value;
        }
        cur
    }
}

pub(crate) fn nobang(maybe_banged: &str) -> &str {
    maybe_banged.strip_prefix('!').unwrap_or(maybe_banged)
}

impl Eq for Tag {}

impl PartialEq for Tag {
    fn eq(&self, other: &Tag) -> bool {
        PartialEq::eq(nobang(&self.string), nobang(&other.string))
    }
}

impl<T> PartialEq<T> for Tag
where
    T: ?Sized + AsRef<str>,
{
    fn eq(&self, other: &T) -> bool {
        PartialEq::eq(nobang(&self.string), nobang(other.as_ref()))
    }
}

impl Ord for Tag {
    fn cmp(&self, other: &Self) -> Ordering {
        Ord::cmp(nobang(&self.string), nobang(&other.string))
    }
}

impl PartialOrd for Tag {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        PartialOrd::partial_cmp(nobang(&self.string), nobang(&other.string))
    }
}

impl Hash for Tag {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        nobang(&self.string).hash(hasher);
    }
}

impl Debug for Tag {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "!{}", nobang(&self.string))
    }
}

impl Display for Tag {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "!{}", nobang(&self.string))
    }
}

impl Serialize for TaggedValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(1))?;
        map.serialize_entry(&format_args!("!{}", nobang(&self.tag.string)), &self.value)?;
        map.end()
    }
}

impl<'de> Deserialize<'de> for TaggedValue {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct TaggedValueVisitor;

        impl<'de> Visitor<'de> for TaggedValueVisitor {
            type Value = TaggedValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML value with a !Tag")
            }

            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
            where
                A: EnumAccess<'de>,
            {
                let (tag, contents) = data.variant::<String>()?;
                let tag = Tag::new(tag);
                let value = contents.newtype_variant()?;
                Ok(TaggedValue { tag, value })
            }
        }

        deserializer.deserialize_any(TaggedValueVisitor)
    }
}

impl<'de> EnumAccess<'de> for TaggedValue {
    type Error = Error;
    type Variant = Value;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
    where
        V: DeserializeSeed<'de>,
    {
        let tag = StrDeserializer::<Error>::new(nobang(&self.tag.string));
        let value = seed.deserialize(tag)?;
        Ok((value, self.value))
    }
}

impl<'de> VariantAccess<'de> for Value {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Error> {
        Deserialize::deserialize(self)
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
    where
        T: DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Sequence(v) = self {
            Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"tuple variant"))
        }
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Mapping(v) = self {
            Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"struct variant"))
        }
    }
}

impl<'de> EnumAccess<'de> for &'de TaggedValue {
    type Error = Error;
    type Variant = &'de Value;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
    where
        V: DeserializeSeed<'de>,
    {
        let tag = BorrowedStrDeserializer::<Error>::new(nobang(&self.tag.string));
        let value = seed.deserialize(tag)?;
        Ok((value, &self.value))
    }
}

impl<'de> VariantAccess<'de> for &'de Value {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Error> {
        Deserialize::deserialize(self)
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
    where
        T: DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Sequence(v) = self {
            Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"tuple variant"))
        }
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Mapping(v) = self {
            Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"struct variant"))
        }
    }
}
<commit_msg>Use Display for Tag to implement Debug<commit_after>use crate::value::de::{MapDeserializer, MapRefDeserializer, SeqDeserializer, SeqRefDeserializer};
use crate::value::Value;
use crate::Error;
use serde::de::value::{BorrowedStrDeserializer, StrDeserializer};
use serde::de::{
    Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error as _, VariantAccess, Visitor,
};
use serde::ser::{Serialize, SerializeMap, Serializer};
use std::cmp::Ordering;
use std::fmt::{self, Debug, Display};
use std::hash::{Hash, Hasher};

/// A representation of YAML's `!Tag` syntax, used for enums.
///
/// Refer to the example code on [`TaggedValue`] for an example of deserializing
/// tagged values.
#[derive(Clone)]
pub struct Tag {
    pub(crate) string: String,
}

/// A `Tag` + `Value` representing a tagged YAML scalar, sequence, or mapping.
///
/// ```
/// use serde_yaml::value::TaggedValue;
/// use std::collections::BTreeMap;
///
/// let yaml = "
///     scalar: !Thing x
///     sequence_flow: !Thing [first]
///     sequence_block: !Thing
///       - first
///     mapping_flow: !Thing {k: v}
///     mapping_block: !Thing
///       k: v
/// ";
///
/// let data: BTreeMap<String, TaggedValue> = serde_yaml::from_str(yaml).unwrap();
/// assert!(data["scalar"].tag == "Thing");
/// assert!(data["sequence_flow"].tag == "Thing");
/// assert!(data["sequence_block"].tag == "Thing");
/// assert!(data["mapping_flow"].tag == "Thing");
/// assert!(data["mapping_block"].tag == "Thing");
///
/// // The leading '!' in tags are not significant. The following is also true.
/// assert!(data["scalar"].tag == "!Thing");
/// ```
#[derive(Clone, PartialEq, PartialOrd, Hash, Debug)]
pub struct TaggedValue {
    #[allow(missing_docs)]
    pub tag: Tag,
    #[allow(missing_docs)]
    pub value: Value,
}

impl Tag {
    /// Create tag.
    ///
    /// The leading '!' is not significant. It may be provided, but does not
    /// have to be. The following are equivalent:
    ///
    /// ```
    /// use serde_yaml::value::Tag;
    ///
    /// assert_eq!(Tag::new("!Thing"), Tag::new("Thing"));
    ///
    /// let tag = Tag::new("Thing");
    /// assert!(tag == "Thing");
    /// assert!(tag == "!Thing");
    /// assert!(tag.to_string() == "!Thing");
    ///
    /// let tag = Tag::new("!Thing");
    /// assert!(tag == "Thing");
    /// assert!(tag == "!Thing");
    /// assert!(tag.to_string() == "!Thing");
    /// ```
    ///
    /// Such a tag would serialize to `!Thing` in YAML regardless of whether a
    /// '!' was included in the call to `Tag::new`.
    pub fn new(string: impl Into<String>) -> Self {
        Tag {
            string: string.into(),
        }
    }
}

impl Value {
    pub(crate) fn untag(self) -> Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = tagged.value;
        }
        cur
    }

    pub(crate) fn untag_ref(&self) -> &Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = &tagged.value;
        }
        cur
    }

    pub(crate) fn untag_mut(&mut self) -> &mut Self {
        let mut cur = self;
        while let Value::Tagged(tagged) = cur {
            cur = &mut tagged.value;
        }
        cur
    }
}

pub(crate) fn nobang(maybe_banged: &str) -> &str {
    maybe_banged.strip_prefix('!').unwrap_or(maybe_banged)
}

impl Eq for Tag {}

impl PartialEq for Tag {
    fn eq(&self, other: &Tag) -> bool {
        PartialEq::eq(nobang(&self.string), nobang(&other.string))
    }
}

impl<T> PartialEq<T> for Tag
where
    T: ?Sized + AsRef<str>,
{
    fn eq(&self, other: &T) -> bool {
        PartialEq::eq(nobang(&self.string), nobang(other.as_ref()))
    }
}

impl Ord for Tag {
    fn cmp(&self, other: &Self) -> Ordering {
        Ord::cmp(nobang(&self.string), nobang(&other.string))
    }
}

impl PartialOrd for Tag {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        PartialOrd::partial_cmp(nobang(&self.string), nobang(&other.string))
    }
}

impl Hash for Tag {
    fn hash<H: Hasher>(&self, hasher: &mut H) {
        nobang(&self.string).hash(hasher);
    }
}

impl Display for Tag {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "!{}", nobang(&self.string))
    }
}

impl Debug for Tag {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(self, formatter)
    }
}

impl Serialize for TaggedValue {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        let mut map = serializer.serialize_map(Some(1))?;
        map.serialize_entry(&format_args!("!{}", nobang(&self.tag.string)), &self.value)?;
        map.end()
    }
}

impl<'de> Deserialize<'de> for TaggedValue {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        struct TaggedValueVisitor;

        impl<'de> Visitor<'de> for TaggedValueVisitor {
            type Value = TaggedValue;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("a YAML value with a !Tag")
            }

            fn visit_enum<A>(self, data: A) -> Result<Self::Value, A::Error>
            where
                A: EnumAccess<'de>,
            {
                let (tag, contents) = data.variant::<String>()?;
                let tag = Tag::new(tag);
                let value = contents.newtype_variant()?;
                Ok(TaggedValue { tag, value })
            }
        }

        deserializer.deserialize_any(TaggedValueVisitor)
    }
}

impl<'de> EnumAccess<'de> for TaggedValue {
    type Error = Error;
    type Variant = Value;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
    where
        V: DeserializeSeed<'de>,
    {
        let tag = StrDeserializer::<Error>::new(nobang(&self.tag.string));
        let value = seed.deserialize(tag)?;
        Ok((value, self.value))
    }
}

impl<'de> VariantAccess<'de> for Value {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Error> {
        Deserialize::deserialize(self)
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
    where
        T: DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Sequence(v) = self {
            Deserializer::deserialize_any(SeqDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"tuple variant"))
        }
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Mapping(v) = self {
            Deserializer::deserialize_any(MapDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"struct variant"))
        }
    }
}

impl<'de> EnumAccess<'de> for &'de TaggedValue {
    type Error = Error;
    type Variant = &'de Value;

    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Error>
    where
        V: DeserializeSeed<'de>,
    {
        let tag = BorrowedStrDeserializer::<Error>::new(nobang(&self.tag.string));
        let value = seed.deserialize(tag)?;
        Ok((value, &self.value))
    }
}

impl<'de> VariantAccess<'de> for &'de Value {
    type Error = Error;

    fn unit_variant(self) -> Result<(), Error> {
        Deserialize::deserialize(self)
    }

    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Error>
    where
        T: DeserializeSeed<'de>,
    {
        seed.deserialize(self)
    }

    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Sequence(v) = self {
            Deserializer::deserialize_any(SeqRefDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"tuple variant"))
        }
    }

    fn struct_variant<V>(
        self,
        _fields: &'static [&'static str],
        visitor: V,
    ) -> Result<V::Value, Error>
    where
        V: Visitor<'de>,
    {
        if let Value::Mapping(v) = self {
            Deserializer::deserialize_any(MapRefDeserializer::new(v), visitor)
        } else {
            Err(Error::invalid_type(self.unexpected(), &"struct variant"))
        }
    }
}
<|endoftext|>


<commit_before>use core::convert::TryInto;

use crate::decoder::MAX_COMPONENTS;
use crate::error::Result;
use crate::idct::dequantize_and_idct_block;
use crate::parser::Component;

use std::sync::{Arc, Mutex};

use super::{RowData, Worker};

/// Technically similar to `immediate::ImmediateWorker` but we copy it since we may prefer
/// different style of managing the memory allocation, something that multiple actors can access in
/// parallel.
#[derive(Default)]
struct ImmediateWorker {
    offsets: [usize; MAX_COMPONENTS],
    results: [Vec<u8>; MAX_COMPONENTS],
    components: [Option<Component>; MAX_COMPONENTS],
    quantization_tables: [Option<Arc<[u16; 64]>>; MAX_COMPONENTS],
}

#[derive(Clone, Copy)]
struct ComponentMetadata {
    block_width: usize,
    block_count: usize,
    line_stride: usize,
    dct_scale: usize,
}

pub struct Scoped {
    inner: Mutex<ImmediateWorker>,
}

pub fn with_rayon<T>(f: impl FnOnce(&mut dyn Worker) -> T) -> T {
    let inner = ImmediateWorker::default();
    f(&mut Scoped {
        inner: Mutex::new(inner),
    })
}

impl ImmediateWorker {
    pub fn start_immediate(&mut self, data: RowData) {
        let elements = data.component.block_size.width as usize
            * data.component.block_size.height as usize
            * data.component.dct_scale
            * data.component.dct_scale;
        self.offsets[data.index] = 0;
        self.results[data.index].resize(elements, 0u8);
        self.components[data.index] = Some(data.component);
        self.quantization_tables[data.index] = Some(data.quantization_table);
    }

    pub fn get_result_immediate(&mut self, index: usize) -> Vec<u8> {
        core::mem::take(&mut self.results[index])
    }

    pub fn component_metadata(&self, index: usize) -> Option<ComponentMetadata> {
        let component = self.components[index].as_ref()?;
        let block_size = component.block_size;
        let block_width = block_size.width as usize;
        let block_count = block_size.width as usize * component.vertical_sampling_factor as usize;
        let line_stride = block_size.width as usize * component.dct_scale;
        let dct_scale = component.dct_scale;

        Some(ComponentMetadata {
            block_width,
            block_count,
            line_stride,
            dct_scale,
        })
    }

    pub fn append_row_locked(
        quantization_table: Arc<[u16; 64]>,
        metadata: ComponentMetadata,
        (index, data): (usize, Vec<i16>),
        result_offset: usize,
        result_block: &mut [u8],
    ) {
        // Convert coefficients from a MCU row to samples.
        let block_count;
        let line_stride;
        let block_width;
        let dct_scale;

        {
            let metadata = metadata;

            block_width = metadata.block_width;
            block_count = metadata.block_count;
            line_stride = metadata.line_stride;
            dct_scale = metadata.dct_scale;
        }

        assert_eq!(data.len(), block_count * 64);

        let mut output_buffer = [0; 64];
        for i in 0..block_count {
            let x = (i % block_width) * dct_scale;
            let y = (i / block_width) * dct_scale;

            let coefficients: &[i16; 64] = &data[i * 64..(i + 1) * 64].try_into().unwrap();

            // Write to a temporary intermediate buffer, a 8x8 'image'.
            dequantize_and_idct_block(
                dct_scale,
                coefficients,
                &*quantization_table,
                8,
                &mut output_buffer,
            );

            // Lock the mutex only for this write back, not the main computation.
            // FIXME: we are only copying image data. Can we use some atomic backing buffer and a
            // `Relaxed` write instead?
            let write_back = &mut result_block[y * line_stride + x..];

            let buffered_lines = output_buffer.chunks_mut(8);
            let back_lines = write_back.chunks_mut(line_stride);

            for (buf, back) in buffered_lines.zip(back_lines).take(dct_scale) {
                back[..dct_scale].copy_from_slice(&buf[..dct_scale]);
            }
        }
    }
}

impl super::Worker for Scoped {
    fn start(&mut self, row_data: RowData) -> Result<()> {
        self.inner.get_mut().unwrap().start_immediate(row_data);
        Ok(())
    }

    fn append_row(&mut self, row: (usize, Vec<i16>)) -> Result<()> {
        let quantization_table;
        let metadata;
        let (index, data) = row;
        let result_offset;
        let result_block;

        {
            let mut inner = self.inner.get_mut().unwrap();
            quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();
            metadata = inner.component_metadata(index).unwrap();

            result_offset = inner.offsets[index];
            result_block = &mut inner.results[index][inner.offsets[index]..];
            inner.offsets[index] += metadata.bytes_used();
        }

        ImmediateWorker::append_row_locked(
            quantization_table,
            metadata,
            (index, data),
            result_offset,
            result_block,
        );
        Ok(())
    }

    fn get_result(&mut self, index: usize) -> Result<Vec<u8>> {
        let result = self.inner.get_mut().unwrap().get_result_immediate(index);
        Ok(result)
    }

    // Magic sauce, these _may_ run in parallel.
    fn append_rows(&mut self, iter: &mut dyn Iterator<Item = (usize, Vec<i16>)>) -> Result<()> {
        let inner = self.inner.get_mut().unwrap();
        rayon::in_place_scope(|scope| {
            let metadatas = [
                inner.component_metadata(0),
                inner.component_metadata(1),
                inner.component_metadata(2),
                inner.component_metadata(3),
            ];

            let inner = &mut *inner;
            let [res0, res1, res2, res3] = &mut inner.results;

            // Lazily get the blocks. Note: if we've already collected results from a component
            // then the result vector has already been deallocated/taken. But no more tasks should
            // be created for it.
            let mut result_blocks = [
                res0.get_mut(inner.offsets[0]..).unwrap_or(&mut []),
                res1.get_mut(inner.offsets[1]..).unwrap_or(&mut []),
                res2.get_mut(inner.offsets[2]..).unwrap_or(&mut []),
                res3.get_mut(inner.offsets[3]..).unwrap_or(&mut []),
            ];

            // First we schedule everything, making sure their index is right etc.
            for (index, data) in iter {
                let metadata = metadatas[index].unwrap();
                let quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();

                let result_offset = inner.offsets[index];
                let (result_block, tail) = core::mem::replace(&mut result_blocks[index], &mut [])
                    .split_at_mut(metadata.bytes_used());
                result_blocks[index] = tail;
                inner.offsets[index] += metadata.bytes_used();

                scope.spawn(move |_| {
                    ImmediateWorker::append_row_locked(
                        quantization_table,
                        metadata,
                        (index, data),
                        result_offset,
                        result_block,
                    )
                });
            }

            // Then the mutex is released, allowing all tasks to run.
        });

        Ok(())
    }
}

impl ComponentMetadata {
    fn bytes_used(&self) -> usize {
        self.block_count * self.dct_scale * self.dct_scale
    }
}
<commit_msg>Cleanup: remove remnants of rayon locking<commit_after>use core::convert::TryInto;

use crate::decoder::MAX_COMPONENTS;
use crate::error::Result;
use crate::idct::dequantize_and_idct_block;
use crate::parser::Component;

use std::sync::Arc;

use super::{RowData, Worker};

/// Technically similar to `immediate::ImmediateWorker` but we copy it since we may prefer
/// different style of managing the memory allocation, something that multiple actors can access in
/// parallel.
#[derive(Default)]
struct ImmediateWorker {
    offsets: [usize; MAX_COMPONENTS],
    results: [Vec<u8>; MAX_COMPONENTS],
    components: [Option<Component>; MAX_COMPONENTS],
    quantization_tables: [Option<Arc<[u16; 64]>>; MAX_COMPONENTS],
}

#[derive(Clone, Copy)]
struct ComponentMetadata {
    block_width: usize,
    block_count: usize,
    line_stride: usize,
    dct_scale: usize,
}

pub struct Scoped {
    inner: ImmediateWorker,
}

pub fn with_rayon<T>(f: impl FnOnce(&mut dyn Worker) -> T) -> T {
    let inner = ImmediateWorker::default();
    f(&mut Scoped { inner })
}

impl ImmediateWorker {
    pub fn start_immediate(&mut self, data: RowData) {
        let elements = data.component.block_size.width as usize
            * data.component.block_size.height as usize
            * data.component.dct_scale
            * data.component.dct_scale;
        self.offsets[data.index] = 0;
        self.results[data.index].resize(elements, 0u8);
        self.components[data.index] = Some(data.component);
        self.quantization_tables[data.index] = Some(data.quantization_table);
    }

    pub fn get_result_immediate(&mut self, index: usize) -> Vec<u8> {
        core::mem::take(&mut self.results[index])
    }

    pub fn component_metadata(&self, index: usize) -> Option<ComponentMetadata> {
        let component = self.components[index].as_ref()?;
        let block_size = component.block_size;
        let block_width = block_size.width as usize;
        let block_count = block_size.width as usize * component.vertical_sampling_factor as usize;
        let line_stride = block_size.width as usize * component.dct_scale;
        let dct_scale = component.dct_scale;

        Some(ComponentMetadata {
            block_width,
            block_count,
            line_stride,
            dct_scale,
        })
    }

    pub fn append_row_locked(
        quantization_table: Arc<[u16; 64]>,
        metadata: ComponentMetadata,
        data: Vec<i16>,
        result_block: &mut [u8],
    ) {
        // Convert coefficients from a MCU row to samples.
        let ComponentMetadata {
            block_count,
            line_stride,
            block_width,
            dct_scale,
        } = metadata;

        assert_eq!(data.len(), block_count * 64);

        let mut output_buffer = [0; 64];
        for i in 0..block_count {
            let x = (i % block_width) * dct_scale;
            let y = (i / block_width) * dct_scale;

            let coefficients: &[i16; 64] = &data[i * 64..(i + 1) * 64].try_into().unwrap();

            // Write to a temporary intermediate buffer, a 8x8 'image'.
            dequantize_and_idct_block(
                dct_scale,
                coefficients,
                &*quantization_table,
                8,
                &mut output_buffer,
            );

            // Lock the mutex only for this write back, not the main computation.
            // FIXME: we are only copying image data. Can we use some atomic backing buffer and a
            // `Relaxed` write instead?
            let write_back = &mut result_block[y * line_stride + x..];

            let buffered_lines = output_buffer.chunks_mut(8);
            let back_lines = write_back.chunks_mut(line_stride);

            for (buf, back) in buffered_lines.zip(back_lines).take(dct_scale) {
                back[..dct_scale].copy_from_slice(&buf[..dct_scale]);
            }
        }
    }
}

impl super::Worker for Scoped {
    fn start(&mut self, row_data: RowData) -> Result<()> {
        self.inner.start_immediate(row_data);
        Ok(())
    }

    fn append_row(&mut self, row: (usize, Vec<i16>)) -> Result<()> {
        let ref mut inner = self.inner;
        let (index, data) = row;

        let quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();
        let metadata = inner.component_metadata(index).unwrap();
        let result_block = &mut inner.results[index][inner.offsets[index]..];
        inner.offsets[index] += metadata.bytes_used();

        ImmediateWorker::append_row_locked(quantization_table, metadata, data, result_block);
        Ok(())
    }

    fn get_result(&mut self, index: usize) -> Result<Vec<u8>> {
        let result = self.inner.get_result_immediate(index);
        Ok(result)
    }

    // Magic sauce, these _may_ run in parallel.
    fn append_rows(&mut self, iter: &mut dyn Iterator<Item = (usize, Vec<i16>)>) -> Result<()> {
        let ref mut inner = self.inner;
        rayon::in_place_scope(|scope| {
            let metadatas = [
                inner.component_metadata(0),
                inner.component_metadata(1),
                inner.component_metadata(2),
                inner.component_metadata(3),
            ];

            let inner = &mut *inner;
            let [res0, res1, res2, res3] = &mut inner.results;

            // Lazily get the blocks. Note: if we've already collected results from a component
            // then the result vector has already been deallocated/taken. But no more tasks should
            // be created for it.
            let mut result_blocks = [
                res0.get_mut(inner.offsets[0]..).unwrap_or(&mut []),
                res1.get_mut(inner.offsets[1]..).unwrap_or(&mut []),
                res2.get_mut(inner.offsets[2]..).unwrap_or(&mut []),
                res3.get_mut(inner.offsets[3]..).unwrap_or(&mut []),
            ];

            // First we schedule everything, making sure their index is right etc.
            for (index, data) in iter {
                let metadata = metadatas[index].unwrap();
                let quantization_table = inner.quantization_tables[index].as_ref().unwrap().clone();

                inner.offsets[index] += metadata.bytes_used();
                let (result_block, tail) = core::mem::take(&mut result_blocks[index])
                    .split_at_mut(metadata.bytes_used());
                result_blocks[index] = tail;

                scope.spawn(move |_| {
                    ImmediateWorker::append_row_locked(
                        quantization_table,
                        metadata,
                        data,
                        result_block,
                    )
                });
            }

            // Then the mutex is released, allowing all tasks to run.
        });

        Ok(())
    }
}

impl ComponentMetadata {
    fn bytes_used(&self) -> usize {
        self.block_count * self.dct_scale * self.dct_scale
    }
}
<|endoftext|>