<commit_before>//! RAII wrapper for a dynamically allocated CSpace slot.

#![cfg_attr(not(test), no_std)]
#![allow(non_snake_case)]

use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_CNode_Copy;
use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Move;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_WordBits;

extern "C" {
    static SELF_CNODE: seL4_CPtr;
}

pub struct CSpaceSlot {
    pub slot: seL4_CPtr,
}
impl CSpaceSlot {
    pub fn new() -> Self {
        CSpaceSlot {
            slot: unsafe { KATA_CSPACE_SLOTS.alloc(1) }.expect("CSpaceSlot"),
        }
    }

    // Release ownership of the slot; this inhibits the normal cleanup
    // done by drop.
    pub fn release(&mut self) {
        self.slot = seL4_CPtr::MAX;
    }

    // Returns the (root, index, depth) seL4 path for the slot.
    pub fn get_path(&self) -> (seL4_CPtr, seL4_CPtr, u8) {
        (unsafe { SELF_CNODE }, self.slot, seL4_WordBits as u8)
    }

    // Sets the receive path used for receiving a capability attached
    // to an seL4 IPC message.
    pub fn set_recv_path(&self) {
        unsafe { seL4_SetCapReceivePath(SELF_CNODE, self.slot, seL4_WordBits) };
    }

    // Copies the specified path to our slot.
    pub fn copy_to(
        &self,
        src_root: seL4_CPtr,
        src_index: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        let seL4_AllRights = seL4_CapRights::new(
            /*grant_reply=*/ 1, /*grant=*/ 1, /*read=*/ 1, /*write=*/ 1,
        );
        unsafe {
            seL4_CNode_Copy(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_index,
                src_depth,
                seL4_AllRights,
            )
        }
    }

    // Moves the specified path to our slot.
    pub fn move_to(
        &self,
        src_root: seL4_CPtr,
        src_slot: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_slot,
                src_depth,
            )
        }
    }

    // Moves our slot to the specified path.
    pub fn move_from(
        &self,
        dest_root: seL4_CPtr,
        dest_slot: seL4_CPtr,
        dest_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                dest_root,
                dest_slot,
                dest_depth,
                /*src_root=*/ SELF_CNODE,
                /*src_index= */ self.slot,
                /*src_depth=*/ seL4_WordBits as u8,
            )
        }
    }
}
impl Drop for CSpaceSlot {
    fn drop(&mut self) {
        if self.slot != seL4_CPtr::MAX {
            unsafe {
                seL4_CNode_Delete(SELF_CNODE, self.slot, seL4_WordBits as u8)
                    .expect("CSpaceSlot");
                KATA_CSPACE_SLOTS.free(self.slot, 1);
            }
        }
    }
}
<commit_msg>kata-os-common: add delete support to CSpaceSlot.<commit_after>//! RAII wrapper for a dynamically allocated CSpace slot.

#![cfg_attr(not(test), no_std)]
#![allow(non_snake_case)]

use slot_allocator::KATA_CSPACE_SLOTS;

use sel4_sys::seL4_CapRights;
use sel4_sys::seL4_CNode_Copy;
use sel4_sys::seL4_CNode_Delete;
use sel4_sys::seL4_CNode_Move;
use sel4_sys::seL4_CPtr;
use sel4_sys::seL4_Result;
use sel4_sys::seL4_SetCapReceivePath;
use sel4_sys::seL4_WordBits;

extern "C" {
    static SELF_CNODE: seL4_CPtr;
}

pub struct CSpaceSlot {
    pub slot: seL4_CPtr,
}
impl CSpaceSlot {
    pub fn new() -> Self {
        CSpaceSlot {
            slot: unsafe { KATA_CSPACE_SLOTS.alloc(1) }.expect("CSpaceSlot"),
        }
    }

    // Release ownership of the slot; this inhibits the normal cleanup
    // done by drop.
    pub fn release(&mut self) {
        self.slot = seL4_CPtr::MAX;
    }

    // Returns the (root, index, depth) seL4 path for the slot.
    pub fn get_path(&self) -> (seL4_CPtr, seL4_CPtr, u8) {
        (unsafe { SELF_CNODE }, self.slot, seL4_WordBits as u8)
    }

    // Sets the receive path used for receiving a capability attached
    // to an seL4 IPC message.
    pub fn set_recv_path(&self) {
        unsafe { seL4_SetCapReceivePath(SELF_CNODE, self.slot, seL4_WordBits) };
    }

    // Copies the specified path to our slot.
    pub fn copy_to(
        &self,
        src_root: seL4_CPtr,
        src_index: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        let seL4_AllRights = seL4_CapRights::new(
            /*grant_reply=*/ 1, /*grant=*/ 1, /*read=*/ 1, /*write=*/ 1,
        );
        unsafe {
            seL4_CNode_Copy(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_index,
                src_depth,
                seL4_AllRights,
            )
        }
    }

    // Moves the specified path to our slot.
    pub fn move_to(
        &self,
        src_root: seL4_CPtr,
        src_slot: seL4_CPtr,
        src_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                /*dest_root=*/ SELF_CNODE,
                /*dest_index= */ self.slot,
                /*dest_depth=*/ seL4_WordBits as u8,
                src_root,
                src_slot,
                src_depth,
            )
        }
    }

    // Moves our slot to the specified path.
    pub fn move_from(
        &self,
        dest_root: seL4_CPtr,
        dest_slot: seL4_CPtr,
        dest_depth: u8,
    ) -> seL4_Result {
        unsafe {
            seL4_CNode_Move(
                dest_root,
                dest_slot,
                dest_depth,
                /*src_root=*/ SELF_CNODE,
                /*src_index= */ self.slot,
                /*src_depth=*/ seL4_WordBits as u8,
            )
        }
    }

    // Delete any cap in our slot.
    // NB: deleting an empty slot is a noop to seL4
    pub fn delete(&self) -> seL4_Result {
        unsafe {
            seL4_CNode_Delete(SELF_CNODE, self.slot, seL4_WordBits as u8)
        }
    }
}
impl Drop for CSpaceSlot {
    fn drop(&mut self) {
        if self.slot != seL4_CPtr::MAX {
            unsafe {
                self.delete().expect("CSpaceSlot");
                KATA_CSPACE_SLOTS.free(self.slot, 1);
            }
        }
    }
}
<|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::io::Write;
use std::fs::File;
use std::path;
use std::fs;

use bindgen::config::{Config, Language};
use bindgen::ir::{Constant, ItemContainer, Function, Static};
use bindgen::writer::{Source, SourceWriter};

/// A bindings header that can be written.
pub struct Bindings {
    config: Config,
    globals: Vec<Static>,
    constants: Vec<Constant>,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
}

impl Bindings {
    pub(crate) fn new(config: Config,
                      constants: Vec<Constant>,
                      globals: Vec<Static>,
                      items: Vec<ItemContainer>,
                      functions: Vec<Function>) -> Bindings {
        Bindings {
            config: config,
            globals: globals,
            constants: constants,
            items: items,
            functions: functions,
        }
    }

    pub fn write_to_file(&self, path: &str) {
        if let Some(parent) = path::Path::new(path).parent() {
            fs::create_dir_all(parent).unwrap();
        }

        self.write(File::create(path).unwrap());
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, &self.config);

        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            write!(out, "#ifndef {}", f);
            out.new_line();
            write!(out, "#define {}", f);
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            write!(out, "/* Generated with cbindgen:{} */",
                        ::bindgen::config::VERSION);
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        out.new_line_if_not_start();
        if self.config.language == Language::C {
            out.write("#include <stdint.h>");
            out.new_line();
            out.write("#include <stdlib.h>");
            out.new_line();
            out.write("#include <stdbool.h>");
        } else {
            out.write("#include <cstdint>");
            out.new_line();
            out.write("#include <cstdlib>");
        }
        out.new_line();

        if self.config.language == Language::Cxx {
            self.open_namespaces(&mut out);
        }

        for constant in &self.constants {
            out.new_line_if_not_start();
            constant.write(&self.config, &mut out);
            out.new_line();
        }

        for item in &self.items {
            if item.deref().annotations().bool("no-export").unwrap_or(false) {
                continue;
            }

            out.new_line_if_not_start();
            match item {
                &ItemContainer::Constant(..) => unreachable!(),
                &ItemContainer::Static(..) => unreachable!(),
                &ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Union(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
            }
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            out.new_line_if_not_start();
            out.write("extern \"C\" {");
            out.new_line();
        }

        for global in &self.globals {
            out.new_line_if_not_start();
            global.write(&self.config, &mut out);
            out.new_line();
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        for function in &self.functions {
            out.new_line_if_not_start();
            function.write(&self.config, &mut out);
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            self.close_namespaces(&mut out);

            out.new_line_if_not_start();
            out.write("} // extern \"C\"");
            out.new_line();
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                write!(out, "#endif /* {} */", f);
            } else {
                write!(out, "#endif // {}", f);
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
    }

    pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line();
            write!(out, "namespace {} {{", namespace);
        }
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;
            for namespace in namespaces {
                out.new_line();
                write!(out, "namespace {} {{", namespace);
            }
        }
        if wrote_namespace {
            out.new_line();
        }
    }

    pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;

            for namespace in namespaces.iter().rev() {
                out.new_line_if_not_start();
                write!(out, "}} // namespace {}", namespace);
            }
        }
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line_if_not_start();
            write!(out, "}} // namespace {}", namespace);
        }
        if wrote_namespace {
            out.new_line();
        }
    }
}
<commit_msg>Fix order of closing namespaces and extern<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::io::Write;
use std::fs::File;
use std::path;
use std::fs;

use bindgen::config::{Config, Language};
use bindgen::ir::{Constant, ItemContainer, Function, Static};
use bindgen::writer::{Source, SourceWriter};

/// A bindings header that can be written.
pub struct Bindings {
    config: Config,
    globals: Vec<Static>,
    constants: Vec<Constant>,
    items: Vec<ItemContainer>,
    functions: Vec<Function>,
}

impl Bindings {
    pub(crate) fn new(config: Config,
                      constants: Vec<Constant>,
                      globals: Vec<Static>,
                      items: Vec<ItemContainer>,
                      functions: Vec<Function>) -> Bindings {
        Bindings {
            config: config,
            globals: globals,
            constants: constants,
            items: items,
            functions: functions,
        }
    }

    pub fn write_to_file(&self, path: &str) {
        if let Some(parent) = path::Path::new(path).parent() {
            fs::create_dir_all(parent).unwrap();
        }

        self.write(File::create(path).unwrap());
    }

    pub fn write<F: Write>(&self, file: F) {
        let mut out = SourceWriter::new(file, &self.config);

        if let Some(ref f) = self.config.header {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            write!(out, "#ifndef {}", f);
            out.new_line();
            write!(out, "#define {}", f);
            out.new_line();
        }
        if self.config.include_version {
            out.new_line_if_not_start();
            write!(out, "/* Generated with cbindgen:{} */",
                        ::bindgen::config::VERSION);
            out.new_line();
        }
        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        out.new_line_if_not_start();
        if self.config.language == Language::C {
            out.write("#include <stdint.h>");
            out.new_line();
            out.write("#include <stdlib.h>");
            out.new_line();
            out.write("#include <stdbool.h>");
        } else {
            out.write("#include <cstdint>");
            out.new_line();
            out.write("#include <cstdlib>");
        }
        out.new_line();

        if self.config.language == Language::Cxx {
            self.open_namespaces(&mut out);
        }

        for constant in &self.constants {
            out.new_line_if_not_start();
            constant.write(&self.config, &mut out);
            out.new_line();
        }

        for item in &self.items {
            if item.deref().annotations().bool("no-export").unwrap_or(false) {
                continue;
            }

            out.new_line_if_not_start();
            match item {
                &ItemContainer::Constant(..) => unreachable!(),
                &ItemContainer::Static(..) => unreachable!(),
                &ItemContainer::Enum(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Struct(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Union(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::OpaqueItem(ref x) => x.write(&self.config, &mut out),
                &ItemContainer::Typedef(ref x) => x.write(&self.config, &mut out),
            }
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            out.new_line_if_not_start();
            out.write("extern \"C\" {");
            out.new_line();
        }

        for global in &self.globals {
            out.new_line_if_not_start();
            global.write(&self.config, &mut out);
            out.new_line();
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }

        for function in &self.functions {
            out.new_line_if_not_start();
            function.write(&self.config, &mut out);
            out.new_line();
        }

        if self.config.language == Language::Cxx {
            out.new_line_if_not_start();
            out.write("} // extern \"C\"");
            out.new_line();

            self.close_namespaces(&mut out);
        }

        if let Some(ref f) = self.config.autogen_warning {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
        if let Some(ref f) = self.config.include_guard {
            out.new_line_if_not_start();
            if self.config.language == Language::C {
                write!(out, "#endif /* {} */", f);
            } else {
                write!(out, "#endif // {}", f);
            }
            out.new_line();
        }
        if let Some(ref f) = self.config.trailer {
            out.new_line_if_not_start();
            write!(out, "{}", f);
            out.new_line();
        }
    }

    pub(crate) fn open_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line();
            write!(out, "namespace {} {{", namespace);
        }
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;
            for namespace in namespaces {
                out.new_line();
                write!(out, "namespace {} {{", namespace);
            }
        }
        if wrote_namespace {
            out.new_line();
        }
    }

    pub(crate) fn close_namespaces<F: Write>(&self, out: &mut SourceWriter<F>) {
        let mut wrote_namespace: bool = false;
        if let Some(ref namespaces) = self.config.namespaces {
            wrote_namespace = true;

            for namespace in namespaces.iter().rev() {
                out.new_line_if_not_start();
                write!(out, "}} // namespace {}", namespace);
            }
        }
        if let Some(ref namespace) = self.config.namespace {
            wrote_namespace = true;

            out.new_line_if_not_start();
            write!(out, "}} // namespace {}", namespace);
        }
        if wrote_namespace {
            out.new_line();
        }
    }
}
<|endoftext|>


<commit_before>use std::any::Any;
use std::any::TypeId;
use std::fmt;
use std::io::Read;
use std::io::Write;

#[cfg(feature = "bytes")]
use bytes::Bytes;

use crate::clear::Clear;
use crate::error::ProtobufError;
use crate::error::ProtobufResult;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::MessageDescriptor;
use crate::reflect::ProtobufValue;
use crate::stream::CodedInputStream;
use crate::stream::CodedOutputStream;
use crate::stream::WithCodedOutputStream;
use crate::unknown::UnknownFields;

/// Trait implemented for all generated structs for protobuf messages.
///
/// Also, generated messages implement `Clone + Default + PartialEq`
pub trait Message: fmt::Debug + Clear + Send + Sync + ProtobufValue {
    /// Message descriptor for this message, used for reflection.
    fn descriptor(&self) -> &'static MessageDescriptor;

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Update this message object with fields read from given stream.
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    /// Parse message from stream.
    fn parse_from(is: &mut CodedInputStream) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut r: Self = Message::new();
        r.merge_from(is)?;
        r.check_initialized()?;
        Ok(r)
    }

    /// Write message to the stream.
    ///
    /// Sizes of this messages and nested messages must be cached
    /// by calling `compute_size` prior to this call.
    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    /// Compute and cache size of this message and all nested messages
    fn compute_size(&self) -> u32;

    /// Get size previously computed by `compute_size`.
    fn get_cached_size(&self) -> u32;

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    fn parse_from_reader(reader: &mut dyn Read) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::new(reader);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    fn parse_from_bytes(bytes: &[u8]) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from `Bytes` object.
    /// Resulting message may share references to the passed bytes object.
    #[cfg(feature = "bytes")]
    fn parse_from_carllerche_bytes(bytes: &Bytes) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_carllerche_bytes(bytes);
        let r = parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor().name(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`parse_from_bytes`](crate::parse_from_bytes)
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Create an empty message object.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m = MyMessage::new();
    /// # }
    /// ```
    fn new() -> Self
    where
        Self: Sized;

    /// Get message descriptor for message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let descriptor = MyMessage::descriptor_static();
    /// assert_eq!("MyMessage", descriptor.name());
    /// # }
    /// ```
    fn descriptor_static() -> &'static MessageDescriptor
    where
        Self: Sized,
    {
        panic!(
            "descriptor_static is not implemented for message, \
             LITE_RUNTIME must be used"
        );
    }

    /// Return a pointer to default immutable message with static lifetime.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m: &MyMessage = MyMessage::default_instance();
    /// # }
    /// ```
    fn default_instance() -> &'static Self
    where
        Self: Sized;
}

impl dyn Message {
    /// Downcast `Box<dyn Message>` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: Box<dyn Message>) {
    /// let m: Box<dyn Message> = message;
    /// let m: Box<MyMessage> = Message::downcast_box(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_box<T: Any>(self: Box<dyn Message>) -> Result<Box<T>, Box<dyn Message>> {
        if Any::type_id(&*self) == TypeId::of::<T>() {
            unsafe {
                let raw: *mut dyn Message = Box::into_raw(self);
                Ok(Box::from_raw(raw as *mut T))
            }
        } else {
            Err(self)
        }
    }

    /// Downcast `&dyn Message` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: &dyn Message) {
    /// let m: &dyn Message = message;
    /// let m: &MyMessage = Message::downcast_ref(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_ref<'a, M: Message + 'a>(&'a self) -> Option<&'a M> {
        if Any::type_id(&*self) == TypeId::of::<M>() {
            unsafe { Some(&*(self as *const dyn Message as *const M)) }
        } else {
            None
        }
    }

    /// Downcast `&mut dyn Message` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: &mut dyn Message) {
    /// let m: &mut dyn Message = message;
    /// let m: &mut MyMessage = Message::downcast_mut(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_mut<'a, M: Message + 'a>(&'a mut self) -> Option<&'a mut M> {
        if Any::type_id(&*self) == TypeId::of::<M>() {
            unsafe { Some(&mut *(self as *mut dyn Message as *mut M)) }
        } else {
            None
        }
    }

    /// Check two messages for equality.
    ///
    /// Messages of different types are not equal,
    /// `NaN` values are considered equal (useful for tests).
    pub fn reflect_eq(&self, other: &dyn Message) -> bool {
        let d = self.descriptor();
        if d != other.descriptor() {
            return false;
        }
        d.reflect_eq(self, other, &ReflectEqMode { nan_equal: true })
    }

    /// Clone from a `dyn Message` reference.
    pub fn clone_box(&self) -> Box<dyn Message> {
        self.descriptor().clone(self)
    }
}

impl Clone for Box<dyn Message> {
    fn clone(&self) -> Self {
        (*self).clone_box()
    }
}

#[cfg(off)] // don't need it
impl PartialEq for Box<dyn Message> {
    fn eq(&self, other: &Box<dyn Message>) -> bool {
        use std::ops::Deref;
        self.descriptor() == other.descriptor() && self.descriptor().eq(self.deref(), other.deref())
    }
}
<commit_msg>Fix test compilation<commit_after>use std::any::Any;
use std::any::TypeId;
use std::fmt;
use std::io::Read;
use std::io::Write;

#[cfg(feature = "bytes")]
use bytes::Bytes;

use crate::clear::Clear;
use crate::error::ProtobufError;
use crate::error::ProtobufResult;
use crate::reflect::reflect_eq::ReflectEqMode;
use crate::reflect::MessageDescriptor;
use crate::reflect::ProtobufValue;
use crate::stream::CodedInputStream;
use crate::stream::CodedOutputStream;
use crate::stream::WithCodedOutputStream;
use crate::unknown::UnknownFields;

/// Trait implemented for all generated structs for protobuf messages.
///
/// Also, generated messages implement `Clone + Default + PartialEq`
pub trait Message: fmt::Debug + Clear + Send + Sync + ProtobufValue {
    /// Message descriptor for this message, used for reflection.
    fn descriptor(&self) -> &'static MessageDescriptor;

    /// True iff all required fields are initialized.
    /// Always returns `true` for protobuf 3.
    fn is_initialized(&self) -> bool;

    /// Update this message object with fields read from given stream.
    fn merge_from(&mut self, is: &mut CodedInputStream) -> ProtobufResult<()>;

    /// Parse message from stream.
    fn parse_from(is: &mut CodedInputStream) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut r: Self = Message::new();
        r.merge_from(is)?;
        r.check_initialized()?;
        Ok(r)
    }

    /// Write message to the stream.
    ///
    /// Sizes of this messages and nested messages must be cached
    /// by calling `compute_size` prior to this call.
    fn write_to_with_cached_sizes(&self, os: &mut CodedOutputStream) -> ProtobufResult<()>;

    /// Compute and cache size of this message and all nested messages
    fn compute_size(&self) -> u32;

    /// Get size previously computed by `compute_size`.
    fn get_cached_size(&self) -> u32;

    /// Write the message to the stream.
    ///
    /// Results in error if message is not fully initialized.
    fn write_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        self.check_initialized()?;

        // cache sizes
        self.compute_size();
        // TODO: reserve additional
        self.write_to_with_cached_sizes(os)?;

        Ok(())
    }

    /// Write the message to the stream prepending the message with message length
    /// encoded as varint.
    fn write_length_delimited_to(&self, os: &mut CodedOutputStream) -> ProtobufResult<()> {
        let size = self.compute_size();
        os.write_raw_varint32(size)?;
        self.write_to_with_cached_sizes(os)?;

        // TODO: assert we've written same number of bytes as computed

        Ok(())
    }

    /// Write the message to the vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_vec(&self, vec: &mut Vec<u8>) -> ProtobufResult<()> {
        let mut os = CodedOutputStream::vec(vec);
        self.write_length_delimited_to(&mut os)?;
        os.flush()?;
        Ok(())
    }

    /// Update this message object with fields read from given stream.
    fn merge_from_bytes(&mut self, bytes: &[u8]) -> ProtobufResult<()> {
        let mut is = CodedInputStream::from_bytes(bytes);
        self.merge_from(&mut is)
    }

    /// Parse message from reader.
    /// Parse stops on EOF or when error encountered.
    fn parse_from_reader(reader: &mut dyn Read) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::new(reader);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from byte array.
    fn parse_from_bytes(bytes: &[u8]) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_bytes(bytes);
        let r = Message::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Parse message from `Bytes` object.
    /// Resulting message may share references to the passed bytes object.
    #[cfg(feature = "bytes")]
    fn parse_from_carllerche_bytes(bytes: &Bytes) -> ProtobufResult<Self>
    where
        Self: Sized,
    {
        let mut is = CodedInputStream::from_carllerche_bytes(bytes);
        let r = Self::parse_from(&mut is)?;
        is.check_eof()?;
        Ok(r)
    }

    /// Check if all required fields of this object are initialized.
    fn check_initialized(&self) -> ProtobufResult<()> {
        if !self.is_initialized() {
            Err(ProtobufError::MessageNotInitialized(
                self.descriptor().name(),
            ))
        } else {
            Ok(())
        }
    }

    /// Write the message to the writer.
    fn write_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    fn write_to_vec(&self, v: &mut Vec<u8>) -> ProtobufResult<()> {
        v.with_coded_output_stream(|os| self.write_to(os))
    }

    /// Write the message to bytes vec.
    ///
    /// > **Note**: You can use [`parse_from_bytes`](crate::parse_from_bytes)
    /// to do the reverse.
    fn write_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        self.check_initialized()?;

        let size = self.compute_size() as usize;
        let mut v = Vec::with_capacity(size);
        // skip zerofill
        unsafe {
            v.set_len(size);
        }
        {
            let mut os = CodedOutputStream::bytes(&mut v);
            self.write_to_with_cached_sizes(&mut os)?;
            os.check_eof();
        }
        Ok(v)
    }

    /// Write the message to the writer, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_writer(&self, w: &mut dyn Write) -> ProtobufResult<()> {
        w.with_coded_output_stream(|os| self.write_length_delimited_to(os))
    }

    /// Write the message to the bytes vec, prepend the message with message length
    /// encoded as varint.
    fn write_length_delimited_to_bytes(&self) -> ProtobufResult<Vec<u8>> {
        let mut v = Vec::new();
        v.with_coded_output_stream(|os| self.write_length_delimited_to(os))?;
        Ok(v)
    }

    /// Get a reference to unknown fields.
    fn get_unknown_fields(&self) -> &UnknownFields;
    /// Get a mutable reference to unknown fields.
    fn mut_unknown_fields(&mut self) -> &mut UnknownFields;

    /// Create an empty message object.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m = MyMessage::new();
    /// # }
    /// ```
    fn new() -> Self
    where
        Self: Sized;

    /// Get message descriptor for message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let descriptor = MyMessage::descriptor_static();
    /// assert_eq!("MyMessage", descriptor.name());
    /// # }
    /// ```
    fn descriptor_static() -> &'static MessageDescriptor
    where
        Self: Sized,
    {
        panic!(
            "descriptor_static is not implemented for message, \
             LITE_RUNTIME must be used"
        );
    }

    /// Return a pointer to default immutable message with static lifetime.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>() {
    /// let m: &MyMessage = MyMessage::default_instance();
    /// # }
    /// ```
    fn default_instance() -> &'static Self
    where
        Self: Sized;
}

impl dyn Message {
    /// Downcast `Box<dyn Message>` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: Box<dyn Message>) {
    /// let m: Box<dyn Message> = message;
    /// let m: Box<MyMessage> = Message::downcast_box(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_box<T: Any>(self: Box<dyn Message>) -> Result<Box<T>, Box<dyn Message>> {
        if Any::type_id(&*self) == TypeId::of::<T>() {
            unsafe {
                let raw: *mut dyn Message = Box::into_raw(self);
                Ok(Box::from_raw(raw as *mut T))
            }
        } else {
            Err(self)
        }
    }

    /// Downcast `&dyn Message` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: &dyn Message) {
    /// let m: &dyn Message = message;
    /// let m: &MyMessage = Message::downcast_ref(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_ref<'a, M: Message + 'a>(&'a self) -> Option<&'a M> {
        if Any::type_id(&*self) == TypeId::of::<M>() {
            unsafe { Some(&*(self as *const dyn Message as *const M)) }
        } else {
            None
        }
    }

    /// Downcast `&mut dyn Message` to specific message type.
    ///
    /// ```
    /// # use protobuf::Message;
    /// # fn foo<MyMessage: Message>(message: &mut dyn Message) {
    /// let m: &mut dyn Message = message;
    /// let m: &mut MyMessage = Message::downcast_mut(m).unwrap();
    /// # }
    /// ```
    pub fn downcast_mut<'a, M: Message + 'a>(&'a mut self) -> Option<&'a mut M> {
        if Any::type_id(&*self) == TypeId::of::<M>() {
            unsafe { Some(&mut *(self as *mut dyn Message as *mut M)) }
        } else {
            None
        }
    }

    /// Check two messages for equality.
    ///
    /// Messages of different types are not equal,
    /// `NaN` values are considered equal (useful for tests).
    pub fn reflect_eq(&self, other: &dyn Message) -> bool {
        let d = self.descriptor();
        if d != other.descriptor() {
            return false;
        }
        d.reflect_eq(self, other, &ReflectEqMode { nan_equal: true })
    }

    /// Clone from a `dyn Message` reference.
    pub fn clone_box(&self) -> Box<dyn Message> {
        self.descriptor().clone(self)
    }
}

impl Clone for Box<dyn Message> {
    fn clone(&self) -> Self {
        (*self).clone_box()
    }
}

#[cfg(off)] // don't need it
impl PartialEq for Box<dyn Message> {
    fn eq(&self, other: &Box<dyn Message>) -> bool {
        use std::ops::Deref;
        self.descriptor() == other.descriptor() && self.descriptor().eq(self.deref(), other.deref())
    }
}
<|endoftext|>


<commit_before>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;
extern crate native;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {

}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, proc() super::$main());
            }
        }
    )
)

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2(app: *mut (), main_function: proc(): Send) {
    use native::NativeTaskBuilder;
    use std::task::TaskBuilder;
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // starting the runtime
    native::start(1, &b"".as_ptr(), proc() {
        // creating the context that will be passed to the callback
        let context = Context { senders: Mutex::new(Vec::new()) };
        app.onAppCmd = commands_callback;
        app.onInputEvent = inputs_callback;

        // executing the main function in parallel
        TaskBuilder::new().native().spawn(proc() {
            std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
            std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
            main_function()
        });

        // polling for events forever
        // note that this must be done in the same thread as android_main because ALooper are
        //  thread-local
        unsafe {
            loop {
                let mut events = mem::uninitialized();
                let mut source = mem::uninitialized();

                // passing -1 means that we are blocking
                let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                    &mut source);

                // processing the event
                if !source.is_null() {
                    let source: *mut ffi::android_poll_source = mem::transmute(source);
                    ((*source).process)(ANDROID_APP, source);
                }
            }
        }
    });

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        buf.with_c_str(|message| {
            b"RustAndroidGlueStdouterr".with_c_str(|tag| {
                unsafe { ffi::__android_log_write(3, tag, message) };
            });
        });
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    let context = get_context();
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        fail!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<commit_msg>fail! -> panic!<commit_after>#![feature(macro_rules)]
#![feature(phase)]

#![unstable]

#[phase(plugin)]
extern crate compile_msg;

extern crate libc;
extern crate native;

use std::sync::Mutex;

#[doc(hidden)]
pub mod ffi;

/// This static variable  will store the android_app* on creation, and set it back to 0 at
///  destruction.
/// Apart from this, the static is never written, so there is no risk of race condition.
static mut ANDROID_APP: *mut ffi::android_app = 0 as *mut ffi::android_app;

/// This is the structure that serves as user data in the android_app*
#[doc(hidden)]
struct Context {
    senders: Mutex<Vec<Sender<Event>>>,
}

/// An event triggered by the Android environment.
pub enum Event {

}

#[cfg(not(target_os = "android"))]
compile_note!("You are not compiling for Android")

#[macro_export]
macro_rules! android_start(
    ($main: ident) => (
        pub mod __android_start {
            extern crate android_glue;

            // this function is here because we are sure that it will be included by the linker
            // so we call app_dummy in it, in order to be sure that the native glue will be included
            #[start]
            pub fn start(_: int, _: *const *const u8) -> int {
                unsafe { android_glue::ffi::app_dummy() };
                1
            }

            #[no_mangle]
            #[inline(never)]
            #[allow(non_snake_case)]
            pub extern "C" fn android_main(app: *mut ()) {
                android_glue::android_main2(app, proc() super::$main());
            }
        }
    )
)

/// This is the function that must be called by `android_main`
#[doc(hidden)]
pub fn android_main2(app: *mut (), main_function: proc(): Send) {
    use native::NativeTaskBuilder;
    use std::task::TaskBuilder;
    use std::{mem, ptr};

    write_log("Entering android_main");

    unsafe { ANDROID_APP = std::mem::transmute(app) };
    let app: &mut ffi::android_app = unsafe { std::mem::transmute(app) };

    // starting the runtime
    native::start(1, &b"".as_ptr(), proc() {
        // creating the context that will be passed to the callback
        let context = Context { senders: Mutex::new(Vec::new()) };
        app.onAppCmd = commands_callback;
        app.onInputEvent = inputs_callback;

        // executing the main function in parallel
        TaskBuilder::new().native().spawn(proc() {
            std::io::stdio::set_stdout(box std::io::LineBufferedWriter::new(ToLogWriter));
            std::io::stdio::set_stderr(box std::io::LineBufferedWriter::new(ToLogWriter));
            main_function()
        });

        // polling for events forever
        // note that this must be done in the same thread as android_main because ALooper are
        //  thread-local
        unsafe {
            loop {
                let mut events = mem::uninitialized();
                let mut source = mem::uninitialized();

                // passing -1 means that we are blocking
                let ident = ffi::ALooper_pollAll(-1, ptr::null_mut(), &mut events,
                    &mut source);

                // processing the event
                if !source.is_null() {
                    let source: *mut ffi::android_poll_source = mem::transmute(source);
                    ((*source).process)(ANDROID_APP, source);
                }
            }
        }
    });

    // terminating the application
    unsafe { ANDROID_APP = 0 as *mut ffi::android_app };
}

/// Writer that will redirect what is written to it to the logs.
struct ToLogWriter;

impl Writer for ToLogWriter {
    fn write(&mut self, buf: &[u8]) -> std::io::IoResult<()> {
        buf.with_c_str(|message| {
            b"RustAndroidGlueStdouterr".with_c_str(|tag| {
                unsafe { ffi::__android_log_write(3, tag, message) };
            });
        });
        Ok(())
    }
}

/// The callback for inputs.
pub extern fn inputs_callback(_: *mut ffi::android_app, event: *const ffi::AInputEvent)
    -> libc::int32_t
{
    let context = get_context();
    0
}

/// The callback for commands.
#[doc(hidden)]
pub extern fn commands_callback(_: *mut ffi::android_app, command: libc::int32_t) {
    let context = get_context();

    match command {
        ffi::APP_CMD_INIT_WINDOW => {

        },

        ffi::APP_CMD_SAVE_STATE => {

        },

        ffi::APP_CMD_TERM_WINDOW => {

        },

        ffi::APP_CMD_GAINED_FOCUS => {

        },

        ffi::APP_CMD_LOST_FOCUS => {

        },

        _ => ()
    }
}

/// Returns the current Context.
fn get_context() -> &'static Context {
    let context = unsafe { (*ANDROID_APP).userData };
    unsafe { std::mem::transmute(context) }
}

/// Adds a sender where events will be sent to.
pub fn add_sender(sender: Sender<Event>) {
    get_context().senders.lock().push(sender);
}

/// Returns a handle to the native window.
pub unsafe fn get_native_window() -> ffi::NativeWindowType {
    if ANDROID_APP.is_null() {
        panic!("The application was not initialized from android_main");
    }

    loop {
        let value = (*ANDROID_APP).window;
        if !value.is_null() {
            return value;
        }

        // spin-locking
        std::io::timer::sleep(std::time::Duration::milliseconds(10));
    }
}

///
pub fn write_log(message: &str) {
    message.with_c_str(|message| {
        b"RustAndroidGlue".with_c_str(|tag| {
            unsafe { ffi::__android_log_write(3, tag, message) };
        });
    });
}
<|endoftext|>


<commit_before>use serde_json::from_str;
use spaceapi::Status;

fn main() {
    let input = r#"{"api":"0.13","space":"coredump","logo":"https://www.coredump.ch/logo.png","url":"https://www.coredump.ch/","location":{"lat":47.22936,"lon":8.82949},"contact":{"irc":"irc://freenode.net/#coredump","twitter":"@coredump_ch","foursquare":"525c20e5498e875d8231b1e5","email":"danilo@coredump.ch"},"issue_report_channels":["email","twitter"],"state":{"open":null},"ext_ccc":"chaostreff"}"#;
    let status: Result<Status, _> = from_str(input);
    match status {
        Ok(status) => println!("{:?}", status),
        Err(err) => println!("Could not parse status: {}", err),
    };
}
<commit_msg>Add a v14 deserialization example (#88)<commit_after>use serde_json::from_str;
use spaceapi::Status;

fn main() {
    let v13_input = r#"{"api":"0.13","space":"coredump","logo":"https://www.coredump.ch/logo.png","url":"https://www.coredump.ch/","location":{"lat":47.22936,"lon":8.82949},"contact":{"irc":"irc://freenode.net/#coredump","twitter":"@coredump_ch","foursquare":"525c20e5498e875d8231b1e5","email":"danilo@coredump.ch"},"issue_report_channels":["email","twitter"],"state":{"open":null},"ext_ccc":"chaostreff"}"#;
    let status: Result<Status, _> = from_str(v13_input);
    match status {
        Ok(status) => println!("{:?}", status),
        Err(err) => println!("Could not parse status: {}", err),
    };

    let v14_input = r#"{"api_compatibility":["14"],"space":"coredump","logo":"https://www.coredump.ch/logo.png","url":"https://www.coredump.ch/","location":{"lat":47.22936,"lon":8.82949},"contact":{"irc":"irc://freenode.net/#coredump","twitter":"@coredump_ch","foursquare":"525c20e5498e875d8231b1e5","email":"danilo@coredump.ch"},"ext_ccc":"chaostreff"}"#;
    let status: Result<Status, _> = from_str(v14_input);
    match status {
        Ok(status) => println!("{:?}", status),
        Err(err) => println!("Could not parse status: {}", err),
    };
}
<|endoftext|>


<commit_before>//! [GET /_matrix/federation/v1/version](https://matrix.org/docs/spec/server_server/r0.1.4#get-matrix-federation-v1-version)

use ruma_api::ruma_api;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata: {
        description: "Get the implementation name and version of this homeserver.",
        method: GET,
        name: "discover_homeserver",
        path: "/.well-known/matrix/server",
        rate_limited: false,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    #[derive(Default)]
    response: {
        /// Information about the homeserver implementation
        #[serde(skip_serializing_if = "Option::is_none")]
        pub server: Option<Server>,
    }
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self {}
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Default::default()
    }
}

/// Arbitrary values that identify this implementation.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Server {
    /// Arbitrary name that identifies this implementation.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// Version of this implementation.
    ///
    /// The version format depends on the implementation.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
}

impl Server {
    /// Creates an empty `Server`.
    pub fn new() -> Self {
        Default::default()
    }
}
<commit_msg>federation-api: Fix version discovery endpoint<commit_after>//! [GET /_matrix/federation/v1/version](https://matrix.org/docs/spec/server_server/r0.1.4#get-matrix-federation-v1-version)

use ruma_api::ruma_api;
use serde::{Deserialize, Serialize};

ruma_api! {
    metadata: {
        description: "Get the implementation name and version of this homeserver.",
        method: GET,
        name: "get_server_version",
        path: "/_matrix/federation/v1/version",
        rate_limited: false,
        authentication: None,
    }

    #[derive(Default)]
    request: {}

    #[derive(Default)]
    response: {
        /// Information about the homeserver implementation
        #[serde(skip_serializing_if = "Option::is_none")]
        pub server: Option<Server>,
    }
}

impl Request {
    /// Creates an empty `Request`.
    pub fn new() -> Self {
        Self {}
    }
}

impl Response {
    /// Creates an empty `Response`.
    pub fn new() -> Self {
        Default::default()
    }
}

/// Arbitrary values that identify this implementation.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct Server {
    /// Arbitrary name that identifies this implementation.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// Version of this implementation.
    ///
    /// The version format depends on the implementation.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub version: Option<String>,
}

impl Server {
    /// Creates an empty `Server`.
    pub fn new() -> Self {
        Default::default()
    }
}
<|endoftext|>


<commit_before>// run-pass
#![feature(format_args_capture)]

fn main() {
    named_argument_takes_precedence_to_captured();
    panic_with_single_argument_does_not_get_formatted();
    panic_with_multiple_arguments_is_formatted();
    formatting_parameters_can_be_captured();
}

fn named_argument_takes_precedence_to_captured() {
    let foo = "captured";
    let s = format!("{foo}", foo="named");
    assert_eq!(&s, "named");

    let s = format!("{foo}-{foo}-{foo}", foo="named");
    assert_eq!(&s, "named-named-named");

    let s = format!("{}-{bar}-{foo}", "positional", bar="named");
    assert_eq!(&s, "positional-named-captured");
}

fn panic_with_single_argument_does_not_get_formatted() {
    // panic! with a single argument does not perform string formatting.
    // RFC #2795 suggests that this may need to change so that captured arguments are formatted.
    // For stability reasons this will need to part of an edition change.

    let msg = std::panic::catch_unwind(|| {
        panic!("{foo}");
    }).unwrap_err();

    assert_eq!(msg.downcast_ref::<&str>(), Some(&"{foo}"))
}

fn panic_with_multiple_arguments_is_formatted() {
    let foo = "captured";

    let msg = std::panic::catch_unwind(|| {
        panic!("{}-{bar}-{foo}", "positional", bar="named");
    }).unwrap_err();

    assert_eq!(msg.downcast_ref::<String>(), Some(&"positional-named-captured".to_string()))
}

fn formatting_parameters_can_be_captured() {
    let width = 9;
    let precision = 3;

    let x = 7.0;

    let s = format!("{x:width$}");
    assert_eq!(&s, "        7");

    let s = format!("{x:<width$}");
    assert_eq!(&s, "7        ");

    let s = format!("{x:-^width$}");
    assert_eq!(&s, "----7----");

    let s = format!("{x:-^width$.precision$}");
    assert_eq!(&s, "--7.000--");
}
<commit_msg>Ignore test with panic on wasm targets<commit_after>// run-pass
// ignore-wasm32
// ignore-wasm64
#![feature(format_args_capture)]

fn main() {
    named_argument_takes_precedence_to_captured();
    panic_with_single_argument_does_not_get_formatted();
    panic_with_multiple_arguments_is_formatted();
    formatting_parameters_can_be_captured();
}

fn named_argument_takes_precedence_to_captured() {
    let foo = "captured";
    let s = format!("{foo}", foo="named");
    assert_eq!(&s, "named");

    let s = format!("{foo}-{foo}-{foo}", foo="named");
    assert_eq!(&s, "named-named-named");

    let s = format!("{}-{bar}-{foo}", "positional", bar="named");
    assert_eq!(&s, "positional-named-captured");
}

fn panic_with_single_argument_does_not_get_formatted() {
    // panic! with a single argument does not perform string formatting.
    // RFC #2795 suggests that this may need to change so that captured arguments are formatted.
    // For stability reasons this will need to part of an edition change.

    let msg = std::panic::catch_unwind(|| {
        panic!("{foo}");
    }).unwrap_err();

    assert_eq!(msg.downcast_ref::<&str>(), Some(&"{foo}"))
}

fn panic_with_multiple_arguments_is_formatted() {
    let foo = "captured";

    let msg = std::panic::catch_unwind(|| {
        panic!("{}-{bar}-{foo}", "positional", bar="named");
    }).unwrap_err();

    assert_eq!(msg.downcast_ref::<String>(), Some(&"positional-named-captured".to_string()))
}

fn formatting_parameters_can_be_captured() {
    let width = 9;
    let precision = 3;

    let x = 7.0;

    let s = format!("{x:width$}");
    assert_eq!(&s, "        7");

    let s = format!("{x:<width$}");
    assert_eq!(&s, "7        ");

    let s = format!("{x:-^width$}");
    assert_eq!(&s, "----7----");

    let s = format!("{x:-^width$.precision$}");
    assert_eq!(&s, "--7.000--");
}
<|endoftext|>


<commit_before>use futures::stable::block_on_stable;
use futures::executor::{block_on, ThreadPool};
use futures::prelude::*;

#[async]
fn foo() -> Result<i32, i32> {
    Ok(1)
}

#[async]
fn bar(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async]
fn baz(x: i32) -> Result<i32, i32> {
    await!(bar(&x))
}

#[async_move]
fn qux(x: i32) -> Result<i32, i32> {
    await!(baz(x).pin())
}

// This test is to check that the internal __await macro generated in each
// function does not leak across function boundaries. If it did then calling
// the #[async] version of __await in the #[async_move] function should cause
// a 'borrow may still be in use when generator yields' error, while calling
// the #[async_move] version in the #[async] function should fail because `bar`
// does not implement `Future`.
#[async_move]
fn qux2(x: i32) -> Result<i32, i32> {
    #[async]
    fn baz2(x: i32) -> Result<i32, i32> {
        await!(bar(&x))
    }
    await!(baz2(x).pin())
}

#[async(pinned)]
fn boxed(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned)]
fn boxed_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn boxed_send(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned_send)]
fn boxed_send_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn spawnable() -> Result<(), Never> {
    Ok(())
}

#[async_stream(item = u64)]
fn _stream1() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async_stream(pinned, item = u64)]
fn _stream_boxed() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async]
pub fn uses_async_for() -> Result<Vec<u64>, i32> {
    let mut v = vec![];
    #[async]
    for i in _stream1() {
        v.push(i);
    }
    Ok(v)
}

#[test]
fn main() {
    assert_eq!(block_on_stable(foo()), Ok(1));
    assert_eq!(block_on_stable(bar(&1)), Ok(1));
    assert_eq!(block_on_stable(baz(17)), Ok(17));
    assert_eq!(block_on_stable(qux(17)), Ok(17));
    assert_eq!(block_on_stable(qux2(17)), Ok(17));
    assert_eq!(block_on(boxed(17)), Ok(17));
    assert_eq!(block_on(boxed_send(17)), Ok(17));
    assert_eq!(block_on_stable(uses_async_for()), Ok(vec![0, 1]));
}

#[test]
fn run_pinned_future_in_thread_pool() {
    let mut pool = ThreadPool::new();
    pool.spawn_pinned(spawnable()).unwrap();
}
<commit_msg>Fix test of pinned async function with thread pool<commit_after>use futures::stable::block_on_stable;
use futures::executor::{block_on, ThreadPool};
use futures::prelude::*;

#[async]
fn foo() -> Result<i32, i32> {
    Ok(1)
}

#[async]
fn bar(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async]
fn baz(x: i32) -> Result<i32, i32> {
    await!(bar(&x))
}

#[async_move]
fn qux(x: i32) -> Result<i32, i32> {
    await!(baz(x).pin())
}

// This test is to check that the internal __await macro generated in each
// function does not leak across function boundaries. If it did then calling
// the #[async] version of __await in the #[async_move] function should cause
// a 'borrow may still be in use when generator yields' error, while calling
// the #[async_move] version in the #[async] function should fail because `bar`
// does not implement `Future`.
#[async_move]
fn qux2(x: i32) -> Result<i32, i32> {
    #[async]
    fn baz2(x: i32) -> Result<i32, i32> {
        await!(bar(&x))
    }
    await!(baz2(x).pin())
}

#[async(pinned)]
fn boxed(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned)]
fn boxed_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn boxed_send(x: i32) -> Result<i32, i32> {
    Ok(x)
}

#[async(pinned_send)]
fn boxed_send_borrow(x: &i32) -> Result<i32, i32> {
    Ok(*x)
}

#[async(pinned_send)]
fn spawnable() -> Result<(), Never> {
    Ok(())
}

#[async_stream(item = u64)]
fn _stream1() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async_stream(pinned, item = u64)]
fn _stream_boxed() -> Result<(), i32> {
    fn integer() -> u64 { 1 }
    let x = &integer();
    stream_yield!(0);
    stream_yield!(*x);
    Ok(())
}

#[async]
pub fn uses_async_for() -> Result<Vec<u64>, i32> {
    let mut v = vec![];
    #[async]
    for i in _stream1() {
        v.push(i);
    }
    Ok(v)
}

#[test]
fn main() {
    assert_eq!(block_on_stable(foo()), Ok(1));
    assert_eq!(block_on_stable(bar(&1)), Ok(1));
    assert_eq!(block_on_stable(baz(17)), Ok(17));
    assert_eq!(block_on_stable(qux(17)), Ok(17));
    assert_eq!(block_on_stable(qux2(17)), Ok(17));
    assert_eq!(block_on(boxed(17)), Ok(17));
    assert_eq!(block_on(boxed_send(17)), Ok(17));
    assert_eq!(block_on_stable(uses_async_for()), Ok(vec![0, 1]));
}

#[test]
fn run_pinned_future_in_thread_pool() {
    let mut pool = ThreadPool::new().unwrap();
    pool.spawn_pinned(spawnable()).unwrap();
}
<|endoftext|>


<commit_before>// This file provides functions to create a libxml2 xmlParserCtxtPtr, configured
// to read from a gio::InputStream, and to maintain its loading data in an XmlState.

use gio;
use gio::prelude::*;
use gio_sys;
use glib_sys;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

use glib::translate::*;

use error::{set_gerror, RsvgError};
use property_bag::PropertyBag;
use util::utf8_cstr;
use xml::XmlState;
use xml2::*;

extern "C" {
    fn rsvg_sax_error_cb(data: *mut libc::c_void);
}

fn get_xml2_sax_handler() -> xmlSAXHandler {
    let mut h: xmlSAXHandler = unsafe { mem::zeroed() };

    h.getEntity = Some(sax_get_entity_cb);
    h.entityDecl = Some(sax_entity_decl_cb);
    h.unparsedEntityDecl = Some(sax_unparsed_entity_decl_cb);
    h.getParameterEntity = Some(sax_get_parameter_entity_cb);
    h.characters = Some(sax_characters_cb);
    h.cdataBlock = Some(sax_characters_cb);
    h.startElement = Some(sax_start_element_cb);
    h.endElement = Some(sax_end_element_cb);
    h.processingInstruction = Some(sax_processing_instruction_cb);

    // This one is defined in the C code, because the prototype has varargs
    // and we can't handle those from Rust :(
    h.error = rsvg_sax_error_cb as *mut _;

    h
}

fn free_xml_parser_and_doc(parser: xmlParserCtxtPtr) {
    unsafe {
        if !parser.is_null() {
            let rparser = &mut *parser;

            if !rparser.myDoc.is_null() {
                xmlFreeDoc(rparser.myDoc);
                rparser.myDoc = ptr::null_mut();
            }

            xmlFreeParserCtxt(parser);
        }
    }
}

unsafe extern "C" fn sax_get_entity_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
) -> xmlEntityPtr {
    let xml = &*(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    xml.entity_lookup(name).unwrap_or(ptr::null_mut())
}

unsafe extern "C" fn sax_entity_decl_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    type_: libc::c_int,
    _public_id: *const libc::c_char,
    _system_id: *const libc::c_char,
    content: *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());

    if type_ != XML_INTERNAL_GENERAL_ENTITY {
        // We don't allow loading external entities; we don't support
        // defining parameter entities in the DTD, and libxml2 should
        // handle internal predefined entities by itself (e.g. "&").
        return;
    }

    let entity = xmlNewEntity(
        ptr::null_mut(),
        name,
        type_,
        ptr::null(),
        ptr::null(),
        content,
    );
    assert!(!entity.is_null());

    let name = utf8_cstr(name);
    xml.entity_insert(name, entity);
}

unsafe extern "C" fn sax_unparsed_entity_decl_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    public_id: *const libc::c_char,
    system_id: *const libc::c_char,
    _notation_name: *const libc::c_char,
) {
    sax_entity_decl_cb(
        ctx,
        name,
        XML_INTERNAL_GENERAL_ENTITY,
        public_id,
        system_id,
        ptr::null(),
    );
}

unsafe extern "C" fn sax_start_element_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    atts: *const *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    let pbag = PropertyBag::new_from_key_value_pairs(atts);

    xml.start_element(name, &pbag);
}

unsafe extern "C" fn sax_end_element_cb(ctx: *mut libc::c_void, name: *const libc::c_char) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    xml.end_element(name);
}

unsafe extern "C" fn sax_characters_cb(
    ctx: *mut libc::c_void,
    unterminated_text: *const libc::c_char,
    len: libc::c_int,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!unterminated_text.is_null());
    assert!(len >= 0);

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = std::slice::from_raw_parts(unterminated_text as *const u8, len as usize);
    let utf8 = str::from_utf8_unchecked(bytes);

    xml.characters(utf8);
}

unsafe extern "C" fn sax_processing_instruction_cb(
    ctx: *mut libc::c_void,
    target: *const libc::c_char,
    data: *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!target.is_null());
    let target = utf8_cstr(target);

    assert!(!data.is_null());
    let data = utf8_cstr(data);

    xml.processing_instruction(target, data);
}

unsafe extern "C" fn sax_get_parameter_entity_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
) -> xmlEntityPtr {
    sax_get_entity_cb(ctx, name)
}

fn set_xml_parse_options(parser: xmlParserCtxtPtr, unlimited_size: bool) {
    let mut options: libc::c_int = XML_PARSE_NONET | XML_PARSE_BIG_LINES;

    if unlimited_size {
        options |= XML_PARSE_HUGE;
    }

    unsafe {
        xmlCtxtUseOptions(parser, options);

        // If false, external entities work, but internal ones don't. if
        // true, internal entities work, but external ones don't. favor
        // internal entities, in order to not cause a regression
        (*parser).replaceEntities = 1;
    }
}

// Struct used as closure data for xmlCreateIOParserCtxt().  In conjunction
// with stream_ctx_read() and stream_ctx_close(), this struct provides the
// I/O callbacks and their context for libxml2.
//
// We call I/O methods on the stream, and as soon as we get an error
// we store it in the gio_error field.  Libxml2 just allows us to
// return -1 from the I/O callbacks in that case; it doesn't actually
// see the error code.
//
// The gio_error field comes from the place that constructs the
// StreamCtx.  That place is later responsible for seeing if the error
// is set; if it is, it means that there was an I/O error.  Otherwise,
// there were no I/O errors but the caller must then ask libxml2 for
// XML parsing errors.
struct StreamCtx {
    stream: gio::InputStream,
    cancellable: Option<gio::Cancellable>,
    gio_error: *mut *mut glib_sys::GError,
}

// read() callback from xmlCreateIOParserCtxt()
unsafe extern "C" fn stream_ctx_read(
    context: *mut libc::c_void,
    buffer: *mut libc::c_char,
    len: libc::c_int,
) -> libc::c_int {
    let ctx = &mut *(context as *mut StreamCtx);

    // has the error been set already?
    if !(*ctx.gio_error).is_null() {
        return -1;
    }

    let buf: &mut [u8] = slice::from_raw_parts_mut(buffer as *mut u8, len as usize);

    match ctx.stream.read(buf, ctx.cancellable.as_ref()) {
        Ok(size) => size as libc::c_int,

        Err(e) => {
            let e: *const glib_sys::GError = e.to_glib_full();
            *ctx.gio_error = e as *mut _;
            -1
        }
    }
}

// close() callback from xmlCreateIOParserCtxt()
unsafe extern "C" fn stream_ctx_close(context: *mut libc::c_void) -> libc::c_int {
    let ctx = &mut *(context as *mut StreamCtx);

    let ret = match ctx.stream.close(ctx.cancellable.as_ref()) {
        Ok(()) => 0,

        Err(e) => {
            // don't overwrite a previous error
            if (*ctx.gio_error).is_null() {
                let e: *const glib_sys::GError = e.to_glib_full();
                *ctx.gio_error = e as *mut _;
            }

            -1
        }
    };

    Box::from_raw(ctx);

    ret
}

fn create_xml_stream_parser(
    xml: &mut XmlState,
    unlimited_size: bool,
    stream: gio::InputStream,
    cancellable: Option<gio::Cancellable>,
    gio_error: *mut *mut glib_sys::GError,
) -> Result<xmlParserCtxtPtr, glib::Error> {
    let ctx = Box::new(StreamCtx {
        stream,
        cancellable,
        gio_error,
    });

    let mut sax_handler = get_xml2_sax_handler();

    unsafe {
        let parser = xmlCreateIOParserCtxt(
            &mut sax_handler,
            xml as *mut _ as *mut _,
            Some(stream_ctx_read),
            Some(stream_ctx_close),
            Box::into_raw(ctx) as *mut _,
            XML_CHAR_ENCODING_NONE,
        );

        if parser.is_null() {
            // on error, xmlCreateIOParserCtxt() frees our context via the
            // stream_ctx_close function
            Err(glib::Error::new(RsvgError, "Error creating XML parser"))
        } else {
            set_xml_parse_options(parser, unlimited_size);
            Ok(parser)
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_create_xml_push_parser(
    xml: *mut XmlState,
    unlimited_size: glib_sys::gboolean,
    base_uri: *const libc::c_char,
    error: *mut *mut glib_sys::GError,
) -> xmlParserCtxtPtr {
    let mut sax_handler = get_xml2_sax_handler();

    let parser = xmlCreatePushParserCtxt(&mut sax_handler, xml as *mut _, ptr::null(), 0, base_uri);

    if parser.is_null() {
        set_gerror(error, 0, "Error creating XML parser");
    } else {
        set_xml_parse_options(parser, from_glib(unlimited_size));
    }

    parser
}

fn xml2_error_to_string(xerr: xmlErrorPtr) -> String {
    unsafe {
        if !xerr.is_null() {
            let xerr = &*xerr;

            let file = if xerr.file.is_null() {
                "data".to_string()
            } else {
                from_glib_none(xerr.file)
            };

            let message = if xerr.message.is_null() {
                "-".to_string()
            } else {
                from_glib_none(xerr.message)
            };

            format!(
                "Error domain {} code {} on line {} column {} of {}: {}",
                xerr.domain, xerr.code, xerr.line, xerr.int2, file, message
            )
        } else {
            // The error is not set?  Return a generic message :(
            "Error parsing XML data".to_string()
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_set_error_from_xml(
    error: *mut *mut glib_sys::GError,
    ctxt: xmlParserCtxtPtr,
) {
    let xerr = xmlCtxtGetLastError(ctxt as *mut _);

    set_gerror(error, 0, &xml2_error_to_string(xerr));
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_xml_state_parse_from_stream(
    xml: *mut XmlState,
    unlimited_size: glib_sys::gboolean,
    stream: *mut gio_sys::GInputStream,
    cancellable: *mut gio_sys::GCancellable,
    error: *mut *mut glib_sys::GError,
) -> glib_sys::gboolean {
    assert!(!xml.is_null());
    let xml = &mut *xml;

    let unlimited_size = from_glib(unlimited_size);

    let stream = from_glib_none(stream);
    let cancellable = from_glib_none(cancellable);

    let mut gio_err: *mut glib_sys::GError = ptr::null_mut();

    match create_xml_stream_parser(xml, unlimited_size, stream, cancellable, &mut gio_err) {
        Ok(parser) => {
            let xml_parse_success = xmlParseDocument(parser) == 0;

            let io_success = gio_err.is_null();

            if !io_success {
                if !error.is_null() {
                    *error = gio_err;
                }
            } else if !xml_parse_success {
                let xerr = xmlCtxtGetLastError(parser as *mut _);
                set_gerror(error, 0, &xml2_error_to_string(xerr));
            }

            free_xml_parser_and_doc(parser);

            (io_success && xml_parse_success).to_glib()
        }

        Err(e) => {
            if !error.is_null() {
                *error = e.to_glib_full() as *mut _;
            }

            false.to_glib()
        }
    }
}
<commit_msg>xml_state_parse_from_stream(): Extract; also introduce ParseFromStreamError<commit_after>// This file provides functions to create a libxml2 xmlParserCtxtPtr, configured
// to read from a gio::InputStream, and to maintain its loading data in an XmlState.

use gio;
use gio::prelude::*;
use gio_sys;
use glib_sys;
use std::mem;
use std::ptr;
use std::slice;
use std::str;

use glib::translate::*;

use error::{set_gerror, RsvgError};
use property_bag::PropertyBag;
use util::utf8_cstr;
use xml::XmlState;
use xml2::*;

extern "C" {
    fn rsvg_sax_error_cb(data: *mut libc::c_void);
}

fn get_xml2_sax_handler() -> xmlSAXHandler {
    let mut h: xmlSAXHandler = unsafe { mem::zeroed() };

    h.getEntity = Some(sax_get_entity_cb);
    h.entityDecl = Some(sax_entity_decl_cb);
    h.unparsedEntityDecl = Some(sax_unparsed_entity_decl_cb);
    h.getParameterEntity = Some(sax_get_parameter_entity_cb);
    h.characters = Some(sax_characters_cb);
    h.cdataBlock = Some(sax_characters_cb);
    h.startElement = Some(sax_start_element_cb);
    h.endElement = Some(sax_end_element_cb);
    h.processingInstruction = Some(sax_processing_instruction_cb);

    // This one is defined in the C code, because the prototype has varargs
    // and we can't handle those from Rust :(
    h.error = rsvg_sax_error_cb as *mut _;

    h
}

fn free_xml_parser_and_doc(parser: xmlParserCtxtPtr) {
    unsafe {
        if !parser.is_null() {
            let rparser = &mut *parser;

            if !rparser.myDoc.is_null() {
                xmlFreeDoc(rparser.myDoc);
                rparser.myDoc = ptr::null_mut();
            }

            xmlFreeParserCtxt(parser);
        }
    }
}

unsafe extern "C" fn sax_get_entity_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
) -> xmlEntityPtr {
    let xml = &*(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    xml.entity_lookup(name).unwrap_or(ptr::null_mut())
}

unsafe extern "C" fn sax_entity_decl_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    type_: libc::c_int,
    _public_id: *const libc::c_char,
    _system_id: *const libc::c_char,
    content: *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());

    if type_ != XML_INTERNAL_GENERAL_ENTITY {
        // We don't allow loading external entities; we don't support
        // defining parameter entities in the DTD, and libxml2 should
        // handle internal predefined entities by itself (e.g. "&").
        return;
    }

    let entity = xmlNewEntity(
        ptr::null_mut(),
        name,
        type_,
        ptr::null(),
        ptr::null(),
        content,
    );
    assert!(!entity.is_null());

    let name = utf8_cstr(name);
    xml.entity_insert(name, entity);
}

unsafe extern "C" fn sax_unparsed_entity_decl_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    public_id: *const libc::c_char,
    system_id: *const libc::c_char,
    _notation_name: *const libc::c_char,
) {
    sax_entity_decl_cb(
        ctx,
        name,
        XML_INTERNAL_GENERAL_ENTITY,
        public_id,
        system_id,
        ptr::null(),
    );
}

unsafe extern "C" fn sax_start_element_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
    atts: *const *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    let pbag = PropertyBag::new_from_key_value_pairs(atts);

    xml.start_element(name, &pbag);
}

unsafe extern "C" fn sax_end_element_cb(ctx: *mut libc::c_void, name: *const libc::c_char) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!name.is_null());
    let name = utf8_cstr(name);

    xml.end_element(name);
}

unsafe extern "C" fn sax_characters_cb(
    ctx: *mut libc::c_void,
    unterminated_text: *const libc::c_char,
    len: libc::c_int,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!unterminated_text.is_null());
    assert!(len >= 0);

    // libxml2 already validated the incoming string as UTF-8.  Note that
    // it is *not* nul-terminated; this is why we create a byte slice first.
    let bytes = std::slice::from_raw_parts(unterminated_text as *const u8, len as usize);
    let utf8 = str::from_utf8_unchecked(bytes);

    xml.characters(utf8);
}

unsafe extern "C" fn sax_processing_instruction_cb(
    ctx: *mut libc::c_void,
    target: *const libc::c_char,
    data: *const libc::c_char,
) {
    let xml = &mut *(ctx as *mut XmlState);

    assert!(!target.is_null());
    let target = utf8_cstr(target);

    assert!(!data.is_null());
    let data = utf8_cstr(data);

    xml.processing_instruction(target, data);
}

unsafe extern "C" fn sax_get_parameter_entity_cb(
    ctx: *mut libc::c_void,
    name: *const libc::c_char,
) -> xmlEntityPtr {
    sax_get_entity_cb(ctx, name)
}

fn set_xml_parse_options(parser: xmlParserCtxtPtr, unlimited_size: bool) {
    let mut options: libc::c_int = XML_PARSE_NONET | XML_PARSE_BIG_LINES;

    if unlimited_size {
        options |= XML_PARSE_HUGE;
    }

    unsafe {
        xmlCtxtUseOptions(parser, options);

        // If false, external entities work, but internal ones don't. if
        // true, internal entities work, but external ones don't. favor
        // internal entities, in order to not cause a regression
        (*parser).replaceEntities = 1;
    }
}

// Struct used as closure data for xmlCreateIOParserCtxt().  In conjunction
// with stream_ctx_read() and stream_ctx_close(), this struct provides the
// I/O callbacks and their context for libxml2.
//
// We call I/O methods on the stream, and as soon as we get an error
// we store it in the gio_error field.  Libxml2 just allows us to
// return -1 from the I/O callbacks in that case; it doesn't actually
// see the error code.
//
// The gio_error field comes from the place that constructs the
// StreamCtx.  That place is later responsible for seeing if the error
// is set; if it is, it means that there was an I/O error.  Otherwise,
// there were no I/O errors but the caller must then ask libxml2 for
// XML parsing errors.
struct StreamCtx {
    stream: gio::InputStream,
    cancellable: Option<gio::Cancellable>,
    gio_error: *mut *mut glib_sys::GError,
}

// read() callback from xmlCreateIOParserCtxt()
unsafe extern "C" fn stream_ctx_read(
    context: *mut libc::c_void,
    buffer: *mut libc::c_char,
    len: libc::c_int,
) -> libc::c_int {
    let ctx = &mut *(context as *mut StreamCtx);

    // has the error been set already?
    if !(*ctx.gio_error).is_null() {
        return -1;
    }

    let buf: &mut [u8] = slice::from_raw_parts_mut(buffer as *mut u8, len as usize);

    match ctx.stream.read(buf, ctx.cancellable.as_ref()) {
        Ok(size) => size as libc::c_int,

        Err(e) => {
            let e: *const glib_sys::GError = e.to_glib_full();
            *ctx.gio_error = e as *mut _;
            -1
        }
    }
}

// close() callback from xmlCreateIOParserCtxt()
unsafe extern "C" fn stream_ctx_close(context: *mut libc::c_void) -> libc::c_int {
    let ctx = &mut *(context as *mut StreamCtx);

    let ret = match ctx.stream.close(ctx.cancellable.as_ref()) {
        Ok(()) => 0,

        Err(e) => {
            // don't overwrite a previous error
            if (*ctx.gio_error).is_null() {
                let e: *const glib_sys::GError = e.to_glib_full();
                *ctx.gio_error = e as *mut _;
            }

            -1
        }
    };

    Box::from_raw(ctx);

    ret
}

fn create_xml_stream_parser(
    xml: &mut XmlState,
    unlimited_size: bool,
    stream: gio::InputStream,
    cancellable: Option<gio::Cancellable>,
    gio_error: *mut *mut glib_sys::GError,
) -> Result<xmlParserCtxtPtr, glib::Error> {
    let ctx = Box::new(StreamCtx {
        stream,
        cancellable,
        gio_error,
    });

    let mut sax_handler = get_xml2_sax_handler();

    unsafe {
        let parser = xmlCreateIOParserCtxt(
            &mut sax_handler,
            xml as *mut _ as *mut _,
            Some(stream_ctx_read),
            Some(stream_ctx_close),
            Box::into_raw(ctx) as *mut _,
            XML_CHAR_ENCODING_NONE,
        );

        if parser.is_null() {
            // on error, xmlCreateIOParserCtxt() frees our context via the
            // stream_ctx_close function
            Err(glib::Error::new(RsvgError, "Error creating XML parser"))
        } else {
            set_xml_parse_options(parser, unlimited_size);
            Ok(parser)
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_create_xml_push_parser(
    xml: *mut XmlState,
    unlimited_size: glib_sys::gboolean,
    base_uri: *const libc::c_char,
    error: *mut *mut glib_sys::GError,
) -> xmlParserCtxtPtr {
    let mut sax_handler = get_xml2_sax_handler();

    let parser = xmlCreatePushParserCtxt(&mut sax_handler, xml as *mut _, ptr::null(), 0, base_uri);

    if parser.is_null() {
        set_gerror(error, 0, "Error creating XML parser");
    } else {
        set_xml_parse_options(parser, from_glib(unlimited_size));
    }

    parser
}

fn xml2_error_to_string(xerr: xmlErrorPtr) -> String {
    unsafe {
        if !xerr.is_null() {
            let xerr = &*xerr;

            let file = if xerr.file.is_null() {
                "data".to_string()
            } else {
                from_glib_none(xerr.file)
            };

            let message = if xerr.message.is_null() {
                "-".to_string()
            } else {
                from_glib_none(xerr.message)
            };

            format!(
                "Error domain {} code {} on line {} column {} of {}: {}",
                xerr.domain, xerr.code, xerr.line, xerr.int2, file, message
            )
        } else {
            // The error is not set?  Return a generic message :(
            "Error parsing XML data".to_string()
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_set_error_from_xml(
    error: *mut *mut glib_sys::GError,
    ctxt: xmlParserCtxtPtr,
) {
    let xerr = xmlCtxtGetLastError(ctxt as *mut _);

    set_gerror(error, 0, &xml2_error_to_string(xerr));
}

// Error returned when parsing an XML stream
pub enum ParseFromStreamError {
    // GIO error from the I/O callbacks
    IoError(glib::Error),

    // XML parsing error from libxml2
    XmlParseError(String),
}

// Parses XML from a stream into an XmlState.
//
// This can be called "in the middle" of an XmlState's processing status,
// for example, when including another XML file via xi:include.
pub fn xml_state_parse_from_stream(
    xml: &mut XmlState,
    unlimited_size: bool,
    stream: gio::InputStream,
    cancellable: Option<gio::Cancellable>,
) -> Result<(), ParseFromStreamError> {
    let mut gio_err: *mut glib_sys::GError = ptr::null_mut();

    match create_xml_stream_parser(xml, unlimited_size, stream, cancellable, &mut gio_err) {
        Ok(parser) => unsafe {
            let xml_parse_success = xmlParseDocument(parser) == 0;

            let io_success = gio_err.is_null();

            let res;

            if !io_success {
                res = Err(ParseFromStreamError::IoError(from_glib_full(gio_err)));
            } else if !xml_parse_success {
                let xerr = xmlCtxtGetLastError(parser as *mut _);
                res = Err(ParseFromStreamError::XmlParseError(xml2_error_to_string(
                    xerr,
                )));
            } else {
                res = Ok(());
            }

            free_xml_parser_and_doc(parser);

            res
        },

        Err(e) => Err(ParseFromStreamError::IoError(e)),
    }
}

#[no_mangle]
pub unsafe extern "C" fn rsvg_xml_state_parse_from_stream(
    xml: *mut XmlState,
    unlimited_size: glib_sys::gboolean,
    stream: *mut gio_sys::GInputStream,
    cancellable: *mut gio_sys::GCancellable,
    error: *mut *mut glib_sys::GError,
) -> glib_sys::gboolean {
    assert!(!xml.is_null());
    let xml = &mut *xml;

    let unlimited_size = from_glib(unlimited_size);

    let stream = from_glib_none(stream);
    let cancellable = from_glib_none(cancellable);

    match xml_state_parse_from_stream(xml, unlimited_size, stream, cancellable) {
        Ok(()) => true.to_glib(),

        Err(e) => {
            match e {
                ParseFromStreamError::IoError(e) => {
                    if !error.is_null() {
                        *error = e.to_glib_full() as *mut _;
                    }
                }

                ParseFromStreamError::XmlParseError(s) => {
                    set_gerror(error, 0, &s);
                }
            }

            false.to_glib()
        }
    }
}
<|endoftext|>