<commit_before>#![allow(dead_code)]
// This file contains the memory allocator used by the rust_alloc module
//
// The implementation in this file is a simple first-fit allocator.
//
// Invariants:
// * All blocks will be a multiple of 16B
// * All blocks will be 16B-aligned
//
// TODO: lock free list

extern crate core;
use core::mem::{transmute_copy, size_of};

static mut START: usize = 0;
static mut END: usize = 0;

static mut free_list: *mut Block = (0 as *mut Block);

// memory block
// the last word of every block is its allocation size
#[repr(C, packed)]
struct Block {
    magic: usize, // If this is a free block, then it is magical: 0xCAFEFACE
    size: usize, // Includes the size of the footer
    next: *mut Block,
    prev: *mut Block,
}

impl Block {
    // METHODS FOR ALL BLOCKS

    // returns true if this is a valid free block
    fn is_free(&self) -> bool {
        self.magic == 0xCAFEFACE && self.size % 0x10 == 0
    }

    // get the prev block in memory
    //
    // note: this is distinct from the prev block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_prev(&self) -> *mut Block {
        //TODO: deal with first block corner case
        // get the addr of previous block's size
        let prev_foot: *const usize = (self.this() - core::mem::size_of::<usize>()) as *const usize;
        let prev_size = *prev_foot;

        // get previous block's addr
        let prev: *mut Block = (self.this() - prev_size) as *mut Block;
    }

    // get the next block in memory
    //
    // note: this is distinct from the next block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_next(&self) -> *mut Block {
        //TODO: deal with last block corner case
        (self.this() + self.size) as *mut Block
    }

    // Set the footer for this block. This method does not error checking, so
    // be careful!
    unsafe fn set_footer(&mut self, size: usize) {
        let footer = (self.this() + self.size - core::mem::size_of::<usize>()) as *mut Block
        *footer = size;
    }

    #[inline]
    unsafe fn this(&self) -> usize {
        self as *const Block as usize;
    }

    // METHODS FOR ONLY FREE BLOCKS

    // split the block into two blocks. The first block will be of the
    // given size. The block must be free
    unsafe fn split(&mut self, size: usize) {
        // check that the math works out
        if !self.is_free() {
            panic!("Attempt to split non-free block 0x{:X}",
                   (self as *const Block) as usize);
        }
        if round_to_16(size + core::mem::size_of::<usize>) >= self.size {
            panic!("Splitting block that is too small: 0x{:X}, size {}",
                   (self as *const Block) as usize, size);
        }

        // get new block addr
        let new_size = round_to_16(size + core::mem::size_of::<usize>);
        let new_addr = (self.this() + new_size) as *const Block;

        // create new block and set magic bits
        let mut block: Block = core::mem::transmute_copy(&*new_addr);
        block.magic = 0xCAFEFACE;
        block.size = self.size - new_size;

        // adjust this block's metadata
        self.size = new_size;

        // insert at tail of free list
        block.insert();
    }

    // coalesce this block with the next one. The two blocks must be free
    unsafe fn combine(&mut self) {
        // check that both are free!
        if !self.is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   (self as *const Block) as usize);
        } else if !(*self.get_next()).is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   self.get_next() as *const Block as usize);
        }

        let next = self.get_next();

       // increase the size of this block
       self.size += (*next).size + core::mem::size_of::<usize>();

       // remove next block from free list
       (*next).remove();
    }

    // remove this block from the free list and return it. The block
    // must be free. After this operation, the block's magic word is
    // set to 0xDEADBEEF. The block must be free.
    unsafe fn remove(&mut self) {
        // TODO
    }

    // METHODS FOR ONLY USED BLOCKS

    // inserts the given block at the tail of the free list and sets
    // the magic bits. The block cannot already be free.
    unsafe fn insert(&mut self) {
        //TODO
    }
}

// Init the heap
pub fn init(start: usize, end: usize) {
    // Round to nearest multiple of 16
    unsafe {
        // round START up
        START = if (start & 0xF) == 0 {start} else {(start & !0xF) + 0x10};

        // round END down
        END = end & !0xF;

        // bounds check
        if END <= START {
            panic!("No heap space");
        }

        printf! ("In heap init\nstart addr: {:x}, end addr: {:x}\n", START, END);
    }

    // TODO: create first block and free list
}

/// Return a pointer to `size` bytes of memory aligned to `align`.
///
/// On failure, return a null pointer.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
    0 as *mut u8 // TODO
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
pub unsafe fn free(ptr: *mut u8, old_size: usize) {

}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
pub fn usable_size(size: usize, align: usize) -> usize {
    0 // TODO
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
pub fn print_stats() {

}
<commit_msg>Implementing heap<commit_after>#![allow(dead_code)]
// This file contains the memory allocator used by the rust_alloc module
//
// The implementation in this file is a simple first-fit allocator.
//
// Invariants:
// * All blocks will be a multiple of 16B
// * All blocks will be 16B-aligned
//
// TODO: lock free list

extern crate core;
use core::mem::{transmute_copy, size_of};

static mut START: usize = 0;
static mut END: usize = 0;

static mut free_list: *mut Block = (0 as *mut Block);

// memory block
// the last word of every block is its allocation size
#[repr(C, packed)]
struct Block {
    magic: usize, // If this is a free block, then it is magical: 0xCAFEFACE
    size: usize, // Includes the size of the footer
    next: *mut Block,
    prev: *mut Block,
}

impl Block {
    // METHODS FOR ALL BLOCKS

    // returns true if this is a valid free block
    fn is_free(&self) -> bool {
        self.magic == 0xCAFEFACE && self.size % 0x10 == 0
    }

    // get the prev block in memory
    //
    // note: this is distinct from the prev block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_prev(&self) -> *mut Block {
        // check for corner cases
        if self.this() == START {
            panic!("Free block has no previous block: {}", self.this());
        }

        // get the addr of previous block's size
        let prev_foot: *const usize = (self.this() - core::mem::size_of::<usize>()) as *const usize;
        let prev_size = *prev_foot;

        // get previous block's addr
        (self.this() - prev_size) as *mut Block
    }

    // get the next block in memory
    //
    // note: this is distinct from the next block in the free list
    // behavior is undefined if this is the last block.
    unsafe fn get_next(&self) -> *mut Block {
        // check for corner cases
        if self.this() + self.size == END {
            panic!("Free block has no next block: {}", self.this());
        }

        (self.this() + self.size) as *mut Block
    }

    // Set the footer for this block. This method does not error checking, so
    // be careful!
    unsafe fn set_footer(&mut self, size: usize) {
        let footer = (self.this() + self.size - core::mem::size_of::<usize>()) as *mut usize;
        *footer = size;
    }

    #[inline]
    unsafe fn this(&self) -> usize {
        self as *const Block as usize
    }

    // METHODS FOR ONLY FREE BLOCKS

    // split the block into two blocks. The first block will be of the
    // given size. The block must be free
    unsafe fn split(&mut self, size: usize) {
        // check that the math works out
        if !self.is_free() {
            panic!("Attempt to split non-free block 0x{:X}",
                   (self as *const Block) as usize);
        }
        if round_to_16(size + core::mem::size_of::<usize>()) >= self.size {
            panic!("Splitting block that is too small: 0x{:X}, size {}",
                   (self as *const Block) as usize, size);
        }

        // get new block addr
        let new_size = round_to_16(size + core::mem::size_of::<usize>());
        let new_addr = (self.this() + new_size) as *const Block;

        // create new block and set magic bits
        let mut block: Block = core::mem::transmute_copy(&*new_addr);
        block.magic = 0xCAFEFACE;
        block.size = self.size - new_size;

        // adjust this block's metadata
        self.size = new_size;

        // insert at tail of free list
        block.insert();
    }

    // coalesce this block with the next one. The two blocks must be free
    unsafe fn combine(&mut self) {
        // check that both are free!
        if !self.is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   (self as *const Block) as usize);
        } else if !(*self.get_next()).is_free() {
            panic!("Attempt to coalesce non-free block 0x{:X}",
                   self.get_next() as *const Block as usize);
        }

        let next = self.get_next();

       // increase the size of this block
       self.size += (*next).size + core::mem::size_of::<usize>();

       // remove next block from free list
       (*next).remove();
    }

    // remove this block from the free list. The block
    // must be free. After this operation, the block's magic word is
    // set to 0xDEADBEEF.
    unsafe fn remove(&mut self) {
        if !self.is_free() {
            panic!("Attempt to remove non-free block from free list: {}", self.this());
        }

        // Set magic, so that this is definitely not a free block
        self.magic = 0xDEADBEEF;

        // get prev and next in free list
        // corner cases:
        // - if this is the head, prev = NULL
        // - if this is the tail, next = NULL

        if self.prev != (0 as *mut Block) {
            (*self.prev).next = self.next;
        } else {
            // remove the head of the list
            free_list = self.next;
        }

        if self.next != (0 as *mut Block) {
            // not the tail
            (*self.next).prev = self.prev;
        }
    }

    // METHODS FOR ONLY USED BLOCKS

    // inserts the given block at the head of the free list and sets
    // the magic bits. The block cannot already be free.
    unsafe fn insert(&mut self) {
        if self.is_free() {
            panic!("Attempt to insert a free block: {}", self.this());
        }

        // set magic bits
        self.magic = 0xCAFEFACE;

        // insert at head
        let next = free_list;

        self.next = free_list;

        if next != (0 as *mut Block) {
            (*next).prev = self.this() as *mut Block;
        }
    }
}

// round up to the nearest multiple of 16
fn round_to_16(size: usize) -> usize {

}

// Init the heap
pub fn init(start: usize, end: usize) {
    // Round to nearest multiple of 16
    unsafe {
        // round START up
        START = if (start & 0xF) == 0 {start} else {(start & !0xF) + 0x10};

        // round END down
        END = end & !0xF;

        // bounds check
        if END <= START {
            panic!("No heap space");
        }

        printf! ("In heap init\nstart addr: {:x}, end addr: {:x}\n", START, END);
    }

    // TODO: create first block and free list
}

/// Return a pointer to `size` bytes of memory aligned to `align`.
///
/// On failure, return a null pointer.
///
/// Behavior is undefined if the requested size is 0 or the alignment is not a
/// power of 2. The alignment must be no larger than the largest supported page
/// size on the platform.
pub unsafe fn malloc(size: usize, align: usize) -> *mut u8 {
    0 as *mut u8 // TODO
}

/// Deallocates the memory referenced by `ptr`.
///
/// The `ptr` parameter must not be null.
///
/// The `old_size` and `align` parameters are the parameters that were used to
/// create the allocation referenced by `ptr`. The `old_size` parameter may be
/// any value in range_inclusive(requested_size, usable_size).
pub unsafe fn free(ptr: *mut u8, old_size: usize) {

}

/// Returns the usable size of an allocation created with the specified the
/// `size` and `align`.
pub fn usable_size(size: usize, align: usize) -> usize {
    0 // TODO
}

/// Prints implementation-defined allocator statistics.
///
/// These statistics may be inconsistent if other threads use the allocator
/// during the call.
pub fn print_stats() {

}
<|endoftext|>


<commit_before>static version: uint = 1u;

fn main()
{
}
<commit_msg>adding Kissdb struct<commit_after>static version: uint = 1u;

struct Kissdb {
  hash_table_size : u8,
  key_size : u8,
  value_size : u8,
  hash_table_size_bytes : u8,
  hash_tables : ~u8,
  f : std::rt::io::file::FileWriter
}

fn main()
{
}
<|endoftext|>


<commit_before>//! OTEL metric exporter
//!
//! Defines a [Exporter] to send metric data to backend via OTEL protocol.
//!
//! Currently, OTEL metrics exporter only support GRPC connection via tonic on tokio runtime.

use crate::exporter::{
    tonic::{TonicConfig, TonicExporterBuilder},
    ExportConfig,
};
#[cfg(feature = "tonic")]
use crate::proto::collector::metrics::v1::{
    metrics_service_client::MetricsServiceClient, ExportMetricsServiceRequest,
};
use crate::transform::{record_to_metric, sink, CheckpointedMetrics};
use crate::{Error, OtlpPipeline};
use futures::Stream;
use opentelemetry::metrics::{Descriptor, Result};
use opentelemetry::sdk::export::metrics::{AggregatorSelector, ExportKindSelector};
use opentelemetry::sdk::metrics::{PushController, PushControllerWorker};
use opentelemetry::sdk::{
    export::metrics::{CheckpointSet, ExportKind, ExportKindFor, Exporter},
    metrics::selectors,
    InstrumentationLibrary, Resource,
};
use opentelemetry::{global, KeyValue};
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use std::sync::Mutex;
use std::time;
use tonic::metadata::KeyAndValueRef;
#[cfg(feature = "tonic")]
use tonic::transport::Channel;
#[cfg(feature = "tonic")]
use tonic::Request;

impl OtlpPipeline {
    /// Create a OTLP metrics pipeline.
    pub fn metrics<SP, SO, I, IO>(
        self,
        spawn: SP,
        interval: I,
    ) -> OtlpMetricPipeline<selectors::simple::Selector, ExportKindSelector, SP, SO, I, IO>
    where
        SP: Fn(PushControllerWorker) -> SO,
        I: Fn(time::Duration) -> IO,
    {
        OtlpMetricPipeline {
            aggregator_selector: selectors::simple::Selector::Inexpensive,
            export_selector: ExportKindSelector::Cumulative,
            spawn,
            interval,
            exporter_pipeline: None,
            resource: None,
            stateful: None,
            period: None,
            timeout: None,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
pub enum MetricsExporterBuilder {
    #[cfg(feature = "tonic")]
    Tonic(TonicExporterBuilder),
}

impl MetricsExporterBuilder {
    /// Build a OTLP metrics exporter with given configuration.
    fn build_metrics_exporter<ES>(self, export_selector: ES) -> Result<MetricsExporter>
    where
        ES: ExportKindFor + Sync + Send + 'static,
    {
        match self {
            #[cfg(feature = "tonic")]
            MetricsExporterBuilder::Tonic(builder) => Ok(MetricsExporter::new(
                builder.exporter_config,
                builder.tonic_config,
                export_selector,
            )?),
        }
    }
}

impl From<TonicExporterBuilder> for MetricsExporterBuilder {
    fn from(exporter: TonicExporterBuilder) -> Self {
        MetricsExporterBuilder::Tonic(exporter)
    }
}

/// Pipeline to build OTLP metrics exporter
///
/// Note that currently the OTLP metrics exporter only supports tonic as it's grpc layer and tokio as
/// runtime.
#[derive(Debug)]
pub struct OtlpMetricPipeline<AS, ES, SP, SO, I, IO>
where
    AS: AggregatorSelector + Send + Sync + 'static,
    ES: ExportKindFor + Send + Sync + Clone + 'static,
    SP: Fn(PushControllerWorker) -> SO,
    I: Fn(time::Duration) -> IO,
{
    aggregator_selector: AS,
    export_selector: ES,
    spawn: SP,
    interval: I,
    exporter_pipeline: Option<MetricsExporterBuilder>,
    resource: Option<Resource>,
    stateful: Option<bool>,
    period: Option<time::Duration>,
    timeout: Option<time::Duration>,
}

impl<AS, ES, SP, SO, I, IO, IOI> OtlpMetricPipeline<AS, ES, SP, SO, I, IO>
where
    AS: AggregatorSelector + Send + Sync + 'static,
    ES: ExportKindFor + Send + Sync + Clone + 'static,
    SP: Fn(PushControllerWorker) -> SO,
    I: Fn(time::Duration) -> IO,
    IO: Stream<Item = IOI> + Send + 'static,
{
    /// Build with resource key value pairs.
    pub fn with_resource<T: IntoIterator<Item = R>, R: Into<KeyValue>>(self, resource: T) -> Self {
        OtlpMetricPipeline {
            resource: Some(Resource::new(resource.into_iter().map(Into::into))),
            ..self
        }
    }

    /// Build with the exporter
    pub fn with_exporter<B: Into<MetricsExporterBuilder>>(self, pipeline: B) -> Self {
        OtlpMetricPipeline {
            exporter_pipeline: Some(pipeline.into()),
            ..self
        }
    }

    /// Build with the aggregator selector
    pub fn with_aggregator_selector<T>(
        self,
        aggregator_selector: T,
    ) -> OtlpMetricPipeline<T, ES, SP, SO, I, IO>
    where
        T: AggregatorSelector + Send + Sync + 'static,
    {
        OtlpMetricPipeline {
            aggregator_selector,
            export_selector: self.export_selector,
            spawn: self.spawn,
            interval: self.interval,
            exporter_pipeline: None,
            resource: self.resource,
            stateful: self.stateful,
            period: self.period,
            timeout: self.timeout,
        }
    }

    /// Build with spawn function
    pub fn with_spawn(self, spawn: SP) -> Self {
        OtlpMetricPipeline { spawn, ..self }
    }

    /// Build with timeout
    pub fn with_timeout(self, timeout: time::Duration) -> Self {
        OtlpMetricPipeline {
            timeout: Some(timeout),
            ..self
        }
    }

    /// Build with period, your metrics will be exported with this period
    pub fn with_period(self, period: time::Duration) -> Self {
        OtlpMetricPipeline {
            period: Some(period),
            ..self
        }
    }

    /// Build a stateful push controller or not
    pub fn with_stateful(self, stateful: bool) -> Self {
        OtlpMetricPipeline {
            stateful: Some(stateful),
            ..self
        }
    }

    /// Build with interval function
    pub fn with_interval(self, interval: I) -> Self {
        OtlpMetricPipeline { interval, ..self }
    }

    /// Build with export kind selector
    pub fn with_export_kind<E>(self, export_selector: E) -> OtlpMetricPipeline<AS, E, SP, SO, I, IO>
    where
        E: ExportKindFor + Send + Sync + Clone + 'static,
    {
        OtlpMetricPipeline {
            aggregator_selector: self.aggregator_selector,
            export_selector,
            spawn: self.spawn,
            interval: self.interval,
            exporter_pipeline: self.exporter_pipeline,
            resource: self.resource,
            stateful: self.stateful,
            period: self.period,
            timeout: self.timeout,
        }
    }

    /// Build push controller
    pub fn build(self) -> Result<PushController> {
        let exporter = self
            .exporter_pipeline
            .ok_or(Error::NoExporterBuilder)?
            .build_metrics_exporter(self.export_selector.clone())?;

        let mut builder = opentelemetry::sdk::metrics::controllers::push(
            self.aggregator_selector,
            self.export_selector,
            exporter,
            self.spawn,
            self.interval,
        );
        if let Some(period) = self.period {
            builder = builder.with_period(period);
        }
        if let Some(resource) = self.resource {
            builder = builder.with_resource(resource);
        }
        if let Some(stateful) = self.stateful {
            builder = builder.with_stateful(stateful);
        }
        if let Some(timeout) = self.timeout {
            builder = builder.with_timeout(timeout)
        }
        let controller = builder.build();
        global::set_meter_provider(controller.provider());
        Ok(controller)
    }
}

enum ExportMsg {
    #[cfg(feature = "tonic")]
    Export(tonic::Request<ExportMetricsServiceRequest>),
    Shutdown,
}

/// Export metrics in OTEL format.
pub struct MetricsExporter {
    #[cfg(feature = "tokio")]
    sender: Arc<Mutex<tokio::sync::mpsc::Sender<ExportMsg>>>,
    export_kind_selector: Arc<dyn ExportKindFor + Send + Sync>,
}

impl Debug for MetricsExporter {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        #[cfg(feature = "tonic")]
        f.debug_struct("OTLP Metric Exporter")
            .field("grpc_client", &"tonic")
            .finish()
    }
}

impl ExportKindFor for MetricsExporter {
    fn export_kind_for(&self, descriptor: &Descriptor) -> ExportKind {
        self.export_kind_selector.export_kind_for(descriptor)
    }
}

impl MetricsExporter {
    /// Create a new OTLP metrics exporter.
    #[cfg(feature = "tonic")]
    pub fn new<T: ExportKindFor + Send + Sync + 'static>(
        config: ExportConfig,
        tonic_config: TonicConfig,
        export_selector: T,
    ) -> Result<MetricsExporter> {
        let endpoint =
            Channel::from_shared(config.endpoint).map_err::<crate::Error, _>(Into::into)?;

        #[cfg(all(feature = "tls"))]
        let channel = match tonic_config.tls_config {
            Some(tls_config) => endpoint
                .tls_config(tls_config)
                .map_err::<crate::Error, _>(Into::into)?,
            None => endpoint,
        }
        .timeout(config.timeout)
        .connect_lazy()
        .map_err::<crate::Error, _>(Into::into)?;

        #[cfg(not(feature = "tls"))]
        let channel = endpoint
            .timeout(config.timeout)
            .connect_lazy()
            .map_err::<crate::Error, _>(Into::into)?;

        let client = match tonic_config.metadata.to_owned() {
            None => MetricsServiceClient::new(channel),
            Some(metadata) => {
                MetricsServiceClient::with_interceptor(channel, move |mut req: Request<()>| {
                    for key_and_value in metadata.iter() {
                        match key_and_value {
                            KeyAndValueRef::Ascii(key, value) => {
                                req.metadata_mut().append(key, value.to_owned())
                            }
                            KeyAndValueRef::Binary(key, value) => {
                                req.metadata_mut().append_bin(key, value.to_owned())
                            }
                        };
                    }

                    Ok(req)
                })
            }
        };

        let (sender, mut receiver) = tokio::sync::mpsc::channel::<ExportMsg>(2);
        tokio::spawn(Box::pin(async move {
            while let Some(msg) = receiver.recv().await {
                match msg {
                    ExportMsg::Shutdown => {
                        break;
                    }
                    ExportMsg::Export(req) => {
                        let _ = client.to_owned().export(req).await;
                    }
                }
            }
        }));

        Ok(MetricsExporter {
            sender: Arc::new(Mutex::new(sender)),
            export_kind_selector: Arc::new(export_selector),
        })
    }
}

impl Exporter for MetricsExporter {
    fn export(&self, checkpoint_set: &mut dyn CheckpointSet) -> Result<()> {
        let mut resource_metrics: Vec<CheckpointedMetrics> = Vec::default();
        // transform the metrics into proto. Append the resource and instrumentation library information into it.
        checkpoint_set.try_for_each(self.export_kind_selector.as_ref(), &mut |record| {
            let metric_result = record_to_metric(record, self.export_kind_selector.as_ref());
            match metric_result {
                Ok(metrics) => {
                    resource_metrics.push((
                        record.resource().clone().into(),
                        InstrumentationLibrary::new(
                            record.descriptor().instrumentation_name(),
                            record.descriptor().instrumentation_version(),
                        ),
                        metrics,
                    ));
                    Ok(())
                }
                Err(err) => Err(err),
            }
        })?;
        let request = Request::new(sink(resource_metrics));
        self.sender
            .lock()
            .map(|sender| {
                let _ = sender.try_send(ExportMsg::Export(request));
            })
            .map_err(|_| Error::PoisonedLock("otlp metric exporter's tonic sender"))?;
        Ok(())
    }
}

impl Drop for MetricsExporter {
    fn drop(&mut self) {
        let _sender_lock_guard = self.sender.lock().map(|sender| {
            let _ = sender.try_send(ExportMsg::Shutdown);
        });
    }
}
<commit_msg>MetricsExporterBuilder drops exporter_pipeline (#590)<commit_after>//! OTEL metric exporter
//!
//! Defines a [Exporter] to send metric data to backend via OTEL protocol.
//!
//! Currently, OTEL metrics exporter only support GRPC connection via tonic on tokio runtime.

use crate::exporter::{
    tonic::{TonicConfig, TonicExporterBuilder},
    ExportConfig,
};
#[cfg(feature = "tonic")]
use crate::proto::collector::metrics::v1::{
    metrics_service_client::MetricsServiceClient, ExportMetricsServiceRequest,
};
use crate::transform::{record_to_metric, sink, CheckpointedMetrics};
use crate::{Error, OtlpPipeline};
use futures::Stream;
use opentelemetry::metrics::{Descriptor, Result};
use opentelemetry::sdk::export::metrics::{AggregatorSelector, ExportKindSelector};
use opentelemetry::sdk::metrics::{PushController, PushControllerWorker};
use opentelemetry::sdk::{
    export::metrics::{CheckpointSet, ExportKind, ExportKindFor, Exporter},
    metrics::selectors,
    InstrumentationLibrary, Resource,
};
use opentelemetry::{global, KeyValue};
use std::fmt::{Debug, Formatter};
use std::sync::Arc;
use std::sync::Mutex;
use std::time;
use tonic::metadata::KeyAndValueRef;
#[cfg(feature = "tonic")]
use tonic::transport::Channel;
#[cfg(feature = "tonic")]
use tonic::Request;

impl OtlpPipeline {
    /// Create a OTLP metrics pipeline.
    pub fn metrics<SP, SO, I, IO>(
        self,
        spawn: SP,
        interval: I,
    ) -> OtlpMetricPipeline<selectors::simple::Selector, ExportKindSelector, SP, SO, I, IO>
    where
        SP: Fn(PushControllerWorker) -> SO,
        I: Fn(time::Duration) -> IO,
    {
        OtlpMetricPipeline {
            aggregator_selector: selectors::simple::Selector::Inexpensive,
            export_selector: ExportKindSelector::Cumulative,
            spawn,
            interval,
            exporter_pipeline: None,
            resource: None,
            stateful: None,
            period: None,
            timeout: None,
        }
    }
}

#[derive(Debug)]
#[non_exhaustive]
pub enum MetricsExporterBuilder {
    #[cfg(feature = "tonic")]
    Tonic(TonicExporterBuilder),
}

impl MetricsExporterBuilder {
    /// Build a OTLP metrics exporter with given configuration.
    fn build_metrics_exporter<ES>(self, export_selector: ES) -> Result<MetricsExporter>
    where
        ES: ExportKindFor + Sync + Send + 'static,
    {
        match self {
            #[cfg(feature = "tonic")]
            MetricsExporterBuilder::Tonic(builder) => Ok(MetricsExporter::new(
                builder.exporter_config,
                builder.tonic_config,
                export_selector,
            )?),
        }
    }
}

impl From<TonicExporterBuilder> for MetricsExporterBuilder {
    fn from(exporter: TonicExporterBuilder) -> Self {
        MetricsExporterBuilder::Tonic(exporter)
    }
}

/// Pipeline to build OTLP metrics exporter
///
/// Note that currently the OTLP metrics exporter only supports tonic as it's grpc layer and tokio as
/// runtime.
#[derive(Debug)]
pub struct OtlpMetricPipeline<AS, ES, SP, SO, I, IO>
where
    AS: AggregatorSelector + Send + Sync + 'static,
    ES: ExportKindFor + Send + Sync + Clone + 'static,
    SP: Fn(PushControllerWorker) -> SO,
    I: Fn(time::Duration) -> IO,
{
    aggregator_selector: AS,
    export_selector: ES,
    spawn: SP,
    interval: I,
    exporter_pipeline: Option<MetricsExporterBuilder>,
    resource: Option<Resource>,
    stateful: Option<bool>,
    period: Option<time::Duration>,
    timeout: Option<time::Duration>,
}

impl<AS, ES, SP, SO, I, IO, IOI> OtlpMetricPipeline<AS, ES, SP, SO, I, IO>
where
    AS: AggregatorSelector + Send + Sync + 'static,
    ES: ExportKindFor + Send + Sync + Clone + 'static,
    SP: Fn(PushControllerWorker) -> SO,
    I: Fn(time::Duration) -> IO,
    IO: Stream<Item = IOI> + Send + 'static,
{
    /// Build with resource key value pairs.
    pub fn with_resource<T: IntoIterator<Item = R>, R: Into<KeyValue>>(self, resource: T) -> Self {
        OtlpMetricPipeline {
            resource: Some(Resource::new(resource.into_iter().map(Into::into))),
            ..self
        }
    }

    /// Build with the exporter
    pub fn with_exporter<B: Into<MetricsExporterBuilder>>(self, pipeline: B) -> Self {
        OtlpMetricPipeline {
            exporter_pipeline: Some(pipeline.into()),
            ..self
        }
    }

    /// Build with the aggregator selector
    pub fn with_aggregator_selector<T>(
        self,
        aggregator_selector: T,
    ) -> OtlpMetricPipeline<T, ES, SP, SO, I, IO>
    where
        T: AggregatorSelector + Send + Sync + 'static,
    {
        OtlpMetricPipeline {
            aggregator_selector,
            export_selector: self.export_selector,
            spawn: self.spawn,
            interval: self.interval,
            exporter_pipeline: self.exporter_pipeline,
            resource: self.resource,
            stateful: self.stateful,
            period: self.period,
            timeout: self.timeout,
        }
    }

    /// Build with spawn function
    pub fn with_spawn(self, spawn: SP) -> Self {
        OtlpMetricPipeline { spawn, ..self }
    }

    /// Build with timeout
    pub fn with_timeout(self, timeout: time::Duration) -> Self {
        OtlpMetricPipeline {
            timeout: Some(timeout),
            ..self
        }
    }

    /// Build with period, your metrics will be exported with this period
    pub fn with_period(self, period: time::Duration) -> Self {
        OtlpMetricPipeline {
            period: Some(period),
            ..self
        }
    }

    /// Build a stateful push controller or not
    pub fn with_stateful(self, stateful: bool) -> Self {
        OtlpMetricPipeline {
            stateful: Some(stateful),
            ..self
        }
    }

    /// Build with interval function
    pub fn with_interval(self, interval: I) -> Self {
        OtlpMetricPipeline { interval, ..self }
    }

    /// Build with export kind selector
    pub fn with_export_kind<E>(self, export_selector: E) -> OtlpMetricPipeline<AS, E, SP, SO, I, IO>
    where
        E: ExportKindFor + Send + Sync + Clone + 'static,
    {
        OtlpMetricPipeline {
            aggregator_selector: self.aggregator_selector,
            export_selector,
            spawn: self.spawn,
            interval: self.interval,
            exporter_pipeline: self.exporter_pipeline,
            resource: self.resource,
            stateful: self.stateful,
            period: self.period,
            timeout: self.timeout,
        }
    }

    /// Build push controller
    pub fn build(self) -> Result<PushController> {
        let exporter = self
            .exporter_pipeline
            .ok_or(Error::NoExporterBuilder)?
            .build_metrics_exporter(self.export_selector.clone())?;

        let mut builder = opentelemetry::sdk::metrics::controllers::push(
            self.aggregator_selector,
            self.export_selector,
            exporter,
            self.spawn,
            self.interval,
        );
        if let Some(period) = self.period {
            builder = builder.with_period(period);
        }
        if let Some(resource) = self.resource {
            builder = builder.with_resource(resource);
        }
        if let Some(stateful) = self.stateful {
            builder = builder.with_stateful(stateful);
        }
        if let Some(timeout) = self.timeout {
            builder = builder.with_timeout(timeout)
        }
        let controller = builder.build();
        global::set_meter_provider(controller.provider());
        Ok(controller)
    }
}

enum ExportMsg {
    #[cfg(feature = "tonic")]
    Export(tonic::Request<ExportMetricsServiceRequest>),
    Shutdown,
}

/// Export metrics in OTEL format.
pub struct MetricsExporter {
    #[cfg(feature = "tokio")]
    sender: Arc<Mutex<tokio::sync::mpsc::Sender<ExportMsg>>>,
    export_kind_selector: Arc<dyn ExportKindFor + Send + Sync>,
}

impl Debug for MetricsExporter {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        #[cfg(feature = "tonic")]
        f.debug_struct("OTLP Metric Exporter")
            .field("grpc_client", &"tonic")
            .finish()
    }
}

impl ExportKindFor for MetricsExporter {
    fn export_kind_for(&self, descriptor: &Descriptor) -> ExportKind {
        self.export_kind_selector.export_kind_for(descriptor)
    }
}

impl MetricsExporter {
    /// Create a new OTLP metrics exporter.
    #[cfg(feature = "tonic")]
    pub fn new<T: ExportKindFor + Send + Sync + 'static>(
        config: ExportConfig,
        tonic_config: TonicConfig,
        export_selector: T,
    ) -> Result<MetricsExporter> {
        let endpoint =
            Channel::from_shared(config.endpoint).map_err::<crate::Error, _>(Into::into)?;

        #[cfg(all(feature = "tls"))]
        let channel = match tonic_config.tls_config {
            Some(tls_config) => endpoint
                .tls_config(tls_config)
                .map_err::<crate::Error, _>(Into::into)?,
            None => endpoint,
        }
        .timeout(config.timeout)
        .connect_lazy()
        .map_err::<crate::Error, _>(Into::into)?;

        #[cfg(not(feature = "tls"))]
        let channel = endpoint
            .timeout(config.timeout)
            .connect_lazy()
            .map_err::<crate::Error, _>(Into::into)?;

        let client = match tonic_config.metadata.to_owned() {
            None => MetricsServiceClient::new(channel),
            Some(metadata) => {
                MetricsServiceClient::with_interceptor(channel, move |mut req: Request<()>| {
                    for key_and_value in metadata.iter() {
                        match key_and_value {
                            KeyAndValueRef::Ascii(key, value) => {
                                req.metadata_mut().append(key, value.to_owned())
                            }
                            KeyAndValueRef::Binary(key, value) => {
                                req.metadata_mut().append_bin(key, value.to_owned())
                            }
                        };
                    }

                    Ok(req)
                })
            }
        };

        let (sender, mut receiver) = tokio::sync::mpsc::channel::<ExportMsg>(2);
        tokio::spawn(Box::pin(async move {
            while let Some(msg) = receiver.recv().await {
                match msg {
                    ExportMsg::Shutdown => {
                        break;
                    }
                    ExportMsg::Export(req) => {
                        let _ = client.to_owned().export(req).await;
                    }
                }
            }
        }));

        Ok(MetricsExporter {
            sender: Arc::new(Mutex::new(sender)),
            export_kind_selector: Arc::new(export_selector),
        })
    }
}

impl Exporter for MetricsExporter {
    fn export(&self, checkpoint_set: &mut dyn CheckpointSet) -> Result<()> {
        let mut resource_metrics: Vec<CheckpointedMetrics> = Vec::default();
        // transform the metrics into proto. Append the resource and instrumentation library information into it.
        checkpoint_set.try_for_each(self.export_kind_selector.as_ref(), &mut |record| {
            let metric_result = record_to_metric(record, self.export_kind_selector.as_ref());
            match metric_result {
                Ok(metrics) => {
                    resource_metrics.push((
                        record.resource().clone().into(),
                        InstrumentationLibrary::new(
                            record.descriptor().instrumentation_name(),
                            record.descriptor().instrumentation_version(),
                        ),
                        metrics,
                    ));
                    Ok(())
                }
                Err(err) => Err(err),
            }
        })?;
        let request = Request::new(sink(resource_metrics));
        self.sender
            .lock()
            .map(|sender| {
                let _ = sender.try_send(ExportMsg::Export(request));
            })
            .map_err(|_| Error::PoisonedLock("otlp metric exporter's tonic sender"))?;
        Ok(())
    }
}

impl Drop for MetricsExporter {
    fn drop(&mut self) {
        let _sender_lock_guard = self.sender.lock().map(|sender| {
            let _ = sender.try_send(ExportMsg::Shutdown);
        });
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::convert::Into;
use std::fmt::{Display, Formatter, Error as FmtError};

use chrono::naive::datetime::NaiveDateTime;
use chrono::naive::time::NaiveTime;
use chrono::naive::date::NaiveDate;
use chrono::Datelike;
use chrono::Timelike;

use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Result as StoreResult;

use error::DiaryError as DE;
use error::DiaryErrorKind as DEK;

use module_path::ModuleEntryPath;

#[derive(Debug, Clone)]
pub struct DiaryId {
    name: String,
    year: i32,
    month: u32,
    day: u32,
    hour: u32,
    minute: u32,
}

impl DiaryId {

    pub fn new(name: String, y: i32, m: u32, d: u32, h: u32, min: u32) -> DiaryId {
        DiaryId {
            name: name,
            year: y,
            month: m,
            day: d,
            hour: h,
            minute: min,
        }
    }

    pub fn from_datetime<DT: Datelike + Timelike>(diary_name: String, dt: DT) -> DiaryId {
        DiaryId::new(diary_name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
    }

    pub fn diary_name(&self) -> &String {
        &self.name
    }

    pub fn year(&self) -> i32 {
        self.year
    }

    pub fn month(&self) -> u32 {
        self.month
    }

    pub fn day(&self) -> u32 {
        self.day
    }

    pub fn hour(&self) -> u32 {
        self.hour
    }

    pub fn minute(&self) -> u32 {
        self.minute
    }

    pub fn with_diary_name(mut self, name: String) -> DiaryId {
        self.name = name;
        self
    }

    pub fn with_year(mut self, year: i32) -> DiaryId {
        self.year = year;
        self
    }

    pub fn with_month(mut self, month: u32) -> DiaryId {
        self.month = month;
        self
    }

    pub fn with_day(mut self, day: u32) -> DiaryId {
        self.day = day;
        self
    }

    pub fn with_hour(mut self, hour: u32) -> DiaryId {
        self.hour = hour;
        self
    }

    pub fn with_minute(mut self, minute: u32) -> DiaryId {
        self.minute = minute;
        self
    }

    pub fn now(name: String) -> DiaryId {
        use chrono::offset::local::Local;

        let now = Local::now();
        let now_date = now.date().naive_local();
        let now_time = now.time();
        let dt = NaiveDateTime::new(now_date, now_time);

        DiaryId::new(name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
    }

}

impl Default for DiaryId {

    /// Create a default DiaryId which is a diaryid for a diary named "default" with
    /// time = 0000-00-00 00:00:00
    fn default() -> DiaryId {
        let dt = NaiveDateTime::new(NaiveDate::from_ymd(0, 0, 0), NaiveTime::from_hms(0, 0, 0));
        DiaryId::from_datetime(String::from("default"), dt)
    }
}

impl IntoStoreId for DiaryId {

    fn into_storeid(self) -> StoreResult<StoreId> {
        let s : String = self.into();
        ModuleEntryPath::new(s).into_storeid()
    }

}

impl Into<String> for DiaryId {

    fn into(self) -> String {
        format!("{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
                self.name, self.year, self.month, self.day, self.hour, self.minute)
    }

}

impl Display for DiaryId {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
                self.name, self.year, self.month, self.day, self.hour, self.minute)
    }

}

impl Into<NaiveDateTime> for DiaryId {

    fn into(self) -> NaiveDateTime {
        let d = NaiveDate::from_ymd(self.year, self.month, self.day);
        let t = NaiveTime::from_hms(self.hour, self.minute, 0);
        NaiveDateTime::new(d, t)
    }

}

pub trait FromStoreId : Sized {

    fn from_storeid(&StoreId) -> Result<Self, DE>;

}

use std::path::Component;

fn component_to_str<'a>(com: Component<'a>) -> Option<&'a str> {
    match com {
        Component::Normal(s) => Some(s),
        _ => None
    }.and_then(|s| s.to_str())
}

impl FromStoreId for DiaryId {

    fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> {
        use std::str::FromStr;

        let mut cmps   = s.components().rev();
        let (hour, minute) = match cmps.next().and_then(component_to_str)
            .and_then(|time| {
                let mut time = time.split(":");
                let hour     = time.next().and_then(|s| FromStr::from_str(s).ok());
                let minute   = time.next()
                    .and_then(|s| s.split("~").next())
                    .and_then(|s| FromStr::from_str(s).ok());

                debug!("Hour   = {:?}", hour);
                debug!("Minute = {:?}", minute);

                match (hour, minute) {
                    (Some(h), Some(m)) => Some((h, m)),
                    _ => None,
                }
            })
        {
            Some(s) => s,
            None => return Err(DE::new(DEK::ParseError, None)),
        };

        let day: Result<u32,_> = cmps.next().and_then(component_to_str)
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(|s| s.parse::<u32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let month: Result<u32,_> = cmps.next().and_then(component_to_str)
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(|s| s.parse::<u32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let year: Result<i32,_> = cmps.next().and_then(component_to_str)
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(|s| s.parse::<i32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let name = cmps.next().and_then(component_to_str).map(String::from);

        debug!("Day   = {:?}", day);
        debug!("Month = {:?}", month);
        debug!("Year  = {:?}", year);
        debug!("Name  = {:?}", name);

        let day    = try!(day);
        let month  = try!(month);
        let year   = try!(year);
        let name   = try!(name.ok_or(DE::new(DEK::ParseError, None)));

        Ok(DiaryId::new(name, year, month, day, hour, minute))
    }

}

<commit_msg>Return Result from component_to_str<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::convert::Into;
use std::fmt::{Display, Formatter, Error as FmtError};

use chrono::naive::datetime::NaiveDateTime;
use chrono::naive::time::NaiveTime;
use chrono::naive::date::NaiveDate;
use chrono::Datelike;
use chrono::Timelike;

use libimagstore::storeid::StoreId;
use libimagstore::storeid::IntoStoreId;
use libimagstore::store::Result as StoreResult;

use error::DiaryError as DE;
use error::DiaryErrorKind as DEK;

use module_path::ModuleEntryPath;

#[derive(Debug, Clone)]
pub struct DiaryId {
    name: String,
    year: i32,
    month: u32,
    day: u32,
    hour: u32,
    minute: u32,
}

impl DiaryId {

    pub fn new(name: String, y: i32, m: u32, d: u32, h: u32, min: u32) -> DiaryId {
        DiaryId {
            name: name,
            year: y,
            month: m,
            day: d,
            hour: h,
            minute: min,
        }
    }

    pub fn from_datetime<DT: Datelike + Timelike>(diary_name: String, dt: DT) -> DiaryId {
        DiaryId::new(diary_name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
    }

    pub fn diary_name(&self) -> &String {
        &self.name
    }

    pub fn year(&self) -> i32 {
        self.year
    }

    pub fn month(&self) -> u32 {
        self.month
    }

    pub fn day(&self) -> u32 {
        self.day
    }

    pub fn hour(&self) -> u32 {
        self.hour
    }

    pub fn minute(&self) -> u32 {
        self.minute
    }

    pub fn with_diary_name(mut self, name: String) -> DiaryId {
        self.name = name;
        self
    }

    pub fn with_year(mut self, year: i32) -> DiaryId {
        self.year = year;
        self
    }

    pub fn with_month(mut self, month: u32) -> DiaryId {
        self.month = month;
        self
    }

    pub fn with_day(mut self, day: u32) -> DiaryId {
        self.day = day;
        self
    }

    pub fn with_hour(mut self, hour: u32) -> DiaryId {
        self.hour = hour;
        self
    }

    pub fn with_minute(mut self, minute: u32) -> DiaryId {
        self.minute = minute;
        self
    }

    pub fn now(name: String) -> DiaryId {
        use chrono::offset::local::Local;

        let now = Local::now();
        let now_date = now.date().naive_local();
        let now_time = now.time();
        let dt = NaiveDateTime::new(now_date, now_time);

        DiaryId::new(name, dt.year(), dt.month(), dt.day(), dt.hour(), dt.minute())
    }

}

impl Default for DiaryId {

    /// Create a default DiaryId which is a diaryid for a diary named "default" with
    /// time = 0000-00-00 00:00:00
    fn default() -> DiaryId {
        let dt = NaiveDateTime::new(NaiveDate::from_ymd(0, 0, 0), NaiveTime::from_hms(0, 0, 0));
        DiaryId::from_datetime(String::from("default"), dt)
    }
}

impl IntoStoreId for DiaryId {

    fn into_storeid(self) -> StoreResult<StoreId> {
        let s : String = self.into();
        ModuleEntryPath::new(s).into_storeid()
    }

}

impl Into<String> for DiaryId {

    fn into(self) -> String {
        format!("{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
                self.name, self.year, self.month, self.day, self.hour, self.minute)
    }

}

impl Display for DiaryId {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        write!(fmt, "{}/{:0>4}/{:0>2}/{:0>2}/{:0>2}:{:0>2}",
                self.name, self.year, self.month, self.day, self.hour, self.minute)
    }

}

impl Into<NaiveDateTime> for DiaryId {

    fn into(self) -> NaiveDateTime {
        let d = NaiveDate::from_ymd(self.year, self.month, self.day);
        let t = NaiveTime::from_hms(self.hour, self.minute, 0);
        NaiveDateTime::new(d, t)
    }

}

pub trait FromStoreId : Sized {

    fn from_storeid(&StoreId) -> Result<Self, DE>;

}

use std::path::Component;

fn component_to_str<'a>(com: Component<'a>) -> Result<&'a str, DE> {
    match com {
        Component::Normal(s) => Some(s),
        _ => None,
    }.and_then(|s| s.to_str())
    .ok_or(DE::new(DEK::ParseError, None))
}

impl FromStoreId for DiaryId {

    fn from_storeid(s: &StoreId) -> Result<DiaryId, DE> {
        use std::str::FromStr;

        let mut cmps   = s.components().rev();
        let (hour, minute) = try!(cmps.next()
                                  .ok_or(DE::new(DEK::ParseError, None))
                                  .and_then(component_to_str)
                                  .and_then(|time| {
                                      let mut time = time.split(":");
                                      let hour     = time.next().and_then(|s| FromStr::from_str(s).ok());
                                      let minute   = time.next()
                                          .and_then(|s| s.split("~").next())
                                          .and_then(|s| FromStr::from_str(s).ok());

                                      debug!("Hour   = {:?}", hour);
                                      debug!("Minute = {:?}", minute);

                                      match (hour, minute) {
                                          (Some(h), Some(m)) => Ok((h, m)),
                                          _ => return Err(DE::new(DEK::ParseError, None)),
                                      }
                                  }));

        let day: Result<u32,_> = cmps.next()
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(component_to_str)
            .and_then(|s| s.parse::<u32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let month: Result<u32,_> = cmps.next()
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(component_to_str)
            .and_then(|s| s.parse::<u32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let year: Result<i32,_> = cmps.next()
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(component_to_str)
            .and_then(|s| s.parse::<i32>()
                      .map_err(|e| DE::new(DEK::ParseError, Some(Box::new(e)))));

        let name = cmps.next()
            .ok_or(DE::new(DEK::ParseError, None))
            .and_then(component_to_str).map(String::from);

        debug!("Day   = {:?}", day);
        debug!("Month = {:?}", month);
        debug!("Year  = {:?}", year);
        debug!("Name  = {:?}", name);

        let day    = try!(day);
        let month  = try!(month);
        let year   = try!(year);
        let name   = try!(name);

        Ok(DiaryId::new(name, year, month, day, hour, minute))
    }

}

<|endoftext|>


<commit_before>/* Copyright (c) 2015 The Robigalia Project Developers
 * Licensed under the Apache License, Version 2.0
 * <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT
 * license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
 * at your option. All files in the project carrying such
 * notice may not be copied, modified, or distributed except
 * according to those terms.
 */
#![no_std]
#![feature(asm)]
#![feature(thread_local)]
#![allow(bad_style, unused_parens, unused_assignments)]

// NB: this mimics the logic in build.rs
#[cfg(not(any(
    all(target_arch = "arm", target_pointer_width = "32"),
    all(target_arch = "riscv32"),
    all(target_arch = "x86"),
    all(target_arch = "x86_64"),
)))]
use architecture_not_supported_sorry;

pub use seL4_BreakpointAccess::*;
pub use seL4_BreakpointType::*;
pub use seL4_Error::*;
pub use seL4_LookupFailureType::*;
pub use seL4_ObjectType::*;

use core::mem::size_of;

// XXX: These can't be repr(C), but it needs to "match an int" according to the comments on
// SEL4_FORCE_LONG_ENUM. There's no single type that matches in Rust, so it needs to be
// per-architecture. We use a macro to define them all in one whack, with the invoker providing
// only what the size of the enums ought to be. Each arch then invokes it.
macro_rules! error_types {
    ($int_width:ident) => {
        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_Error {
            seL4_NoError = 0,
            seL4_InvalidArgument,
            seL4_InvalidCapability,
            seL4_IllegalOperation,
            seL4_RangeError,
            seL4_AlignmentError,
            seL4_FailedLookup,
            seL4_TruncatedMessage,
            seL4_DeleteFirst,
            seL4_RevokeFirst,
            seL4_NotEnoughMemory,
            // NB: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_LookupFailureType {
            seL4_NoFailure = 0,
            seL4_InvalidRoot,
            seL4_MissingCapability,
            seL4_DepthMismatch,
            seL4_GuardMismatch,
            // XXX: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointType {
            seL4_DataBreakpoint = 0,
            seL4_InstructionBreakpoint,
            seL4_SingleStep,
            seL4_SoftwareBreakRequest,
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointAccess {
            seL4_BreakOnRead = 0,
            seL4_BreakOnWrite,
            seL4_BreakOnReadWrite,
        }
    };
}

// NB: potentially arch-dependent
pub type seL4_Word = usize;
pub type seL4_CPtr = usize;

#[cfg(target_arch = "x86")]
include!("arch/x86.rs");

#[cfg(target_arch = "x86_64")]
include!("arch/x86_64.rs");

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!("arch/arm.rs");

#[cfg(target_arch = "riscv32")]
include!("arch/riscv.rs");

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_invocation.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_invocation.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_invocation.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_invocation.rs"));

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_syscall_stub.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_syscall_stub.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_syscall_stub.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_syscall_stub.rs"));

#[cfg(target_pointer_width = "32")]
include!(concat!(env!("OUT_DIR"), "/types32.rs"));

#[cfg(target_pointer_width = "64")]
include!(concat!(env!("OUT_DIR"), "/types64.rs"));

include!(concat!(env!("OUT_DIR"), "/syscalls.rs"));

// Well-known types from libsel4/include/sel4/types.h

pub type seL4_NodeId = seL4_Word;
pub type seL4_PAddr = seL4_Word;
pub type seL4_Domain = seL4_Word;

pub type seL4_CNode = seL4_CPtr;
pub type seL4_IRQHandler = seL4_CPtr;
pub type seL4_IRQControl = seL4_CPtr;
pub type seL4_TCB = seL4_CPtr;
pub type seL4_Untyped = seL4_CPtr;
pub type seL4_DomainSet = seL4_CPtr;
pub type seL4_SchedContext = seL4_CPtr;
pub type seL4_SchedControl = seL4_CPtr;

// TODO(sleffler): seL4 uses seL4_Uint64 but it's not defined for us
pub type seL4_Time = u64;

pub const seL4_MsgLengthBits: usize = 7;
pub const seL4_MsgMaxLength: usize = 120;
pub const seL4_MsgExtraCapBits: usize = 2;
pub const seL4_MsgMaxExtraCaps: usize = (1usize << seL4_MsgExtraCapBits) - 1;

// Syscall stubs are generated to return seL4_Result unless they return
// an APi struct with an embedded error code. The latter should be replaced
// too but for now we leave it as-is.
pub type seL4_Result = Result<(), seL4_Error>;

// NB: these traits are used by syscall stubs.
impl From<seL4_Error> for seL4_Result {
    fn from(err: seL4_Error) -> seL4_Result {
        if err == seL4_NoError {
            Ok(())
        } else {
            Err(err)
        }
    }
}
// NB: usize works for both 32- and 64-bit architectures
impl From<usize> for seL4_Error {
    fn from(val: usize) -> seL4_Error {
        // TODO(sleffler): 10 is seL4_NotEnoughMemory
        debug_assert!(val <= 10, "Invalid seL4_Error");
        unsafe { ::core::mem::transmute(val) }
    }
}

#[repr(C)]
#[derive(Copy, Debug)]
/// Buffer used to store received IPC messages
pub struct seL4_IPCBuffer {
    /// Message tag
    ///
    /// The kernel does not initialize this.
    pub tag: seL4_MessageInfo,
    /// Message contents
    ///
    /// The kernel only initializes the bytes which were not able to fit into physical registers.
    pub msg: [seL4_Word; seL4_MsgMaxLength],
    /// Arbitrary user data.
    ///
    /// The seL4 C libraries expect this to be a pointer to the IPC buffer in the thread's VSpace.,
    /// but this doesn't really matter.
    pub userData: seL4_Word,
    /// Capabilities to transfer (if sending) or unwrapped badges
    pub caps_or_badges: [seL4_Word; seL4_MsgMaxExtraCaps],
    /// CPtr to a CNode in the thread's CSpace from which to find the receive slot
    pub receiveCNode: seL4_CPtr,
    /// CPtr to the receive slot, relative to receiveCNode
    pub receiveIndex: seL4_CPtr,
    /// Number of bits of receiveIndex to use
    pub receiveDepth: seL4_Word,
}

impl ::core::clone::Clone for seL4_IPCBuffer {
    fn clone(&self) -> Self {
        *self
    }
}

// Bootinfo

// Fixed cap slots for root thread.
pub const seL4_CapNull: seL4_Word = 0; // null cap
pub const seL4_CapInitThreadTCB: seL4_Word = 1; // initial thread's TCB
pub const seL4_CapInitThreadCNode: seL4_Word = 2; // initial thread's root CNode
pub const seL4_CapInitThreadVSpace: seL4_Word = 3; // initial thread's VSpace
pub const seL4_CapIRQControl: seL4_Word = 4; // global IRQ controller
pub const seL4_CapASIDControl: seL4_Word = 5; // global ASID controller
pub const seL4_CapInitThreadASIDPool: seL4_Word = 6; // initial thread's ASID pool
pub const seL4_CapIOPort: seL4_Word = 7; // global IO port (null if not supported)
pub const seL4_CapIOSpace: seL4_Word = 8; // global IO space (null if no IOMMU support)
pub const seL4_CapBootInfoFrame: seL4_Word = 9; // bootinfo frame
pub const seL4_CapInitThreadIPCBuffer: seL4_Word = 10; // initial thread's IPC buffer frame
pub const seL4_CapDomain: seL4_Word = 11; // global domain controller

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// A half-open [start..end) range of slots
pub struct seL4_SlotRegion {
    /// First CNode slot position of the region
    pub start: seL4_Word,
    /// First CNode slot position after the region
    pub end: seL4_Word, /* first CNode slot position AFTER region */
}

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct seL4_UntypedDesc {
    /// Physical address corresponding of the untyped object's backing memory
    pub paddr: seL4_Word,
    pub padding1: u8,
    pub padding2: u8,
    /// log2 size of the region of memory backing the untyped object
    pub sizeBits: u8,
    /// Whether the backing memory corresponds to some device memory
    pub isDevice: u8,
}

// explicitly *not* Copy. the array at the end is tricky to handle.

#[repr(C, packed)]
// #[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
//#[derive(Debug, PartialEq, Eq)]
pub struct seL4_BootInfo {
    /// Length of any additional bootinfo information
    pub extraLen: seL4_Word,
    /// ID [0..numNodes-1] of the current node (0 if uniprocessor)
    pub nodeID: seL4_Word,
    /// Number of seL4 nodes (1 if uniprocessor)
    pub numNodes: seL4_Word,
    /// Number of IOMMU PT levels (0 if no IOMMU support)
    pub numIOPTLevels: seL4_Word,
    /// pointer to root task's IPC buffer */
    pub ipcBuffer: *mut seL4_IPCBuffer,
    /// Empty slots (null caps)
    pub empty: seL4_SlotRegion,
    /// Frames shared between nodes
    pub sharedFrames: seL4_SlotRegion,
    /// Frame caps used for the loaded ELF image of the root task
    pub userImageFrames: seL4_SlotRegion,
    /// PD caps used for the loaded ELF image of the root task
    pub userImagePaging: seL4_SlotRegion,
    /// IOSpace caps for ARM SMMU
    pub ioSpaceCaps: seL4_SlotRegion,
    /// Caps fr anypages used to back the additional bootinfo information
    pub extraBIPages: seL4_SlotRegion,
    /// log2 size of root task's CNode
    pub initThreadCNodeSizeBits: u8,
    /// Root task's domain ID
    pub initThreadDomain: u32,

    #[cfg(feature = "SEL4_CONFIG_KERNEL_MCS")]
    // Caps to sched_control for each node
    pub schedcontrol: seL4_SlotRegion,

    /// Untyped object caps
    pub untyped: seL4_SlotRegion,
    /// Information about each untyped cap
    ///
    /// *Note*! This is actually an array! The actual length depends on kernel configuration which
    /// we have no way of knowing at this point. Use the `untyped_descs` method.
    pub untypedList: seL4_UntypedDesc,
}

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct seL4_BootInfoHeader {
    /// Identifier of the following chunk
    pub id: seL4_Word,
    /// Length of the chunk
    pub len: seL4_Word,
}

impl seL4_BootInfo {
    /// This is safe if you don't mutate the `untyped` field and corrupt its length.
    pub unsafe fn untyped_descs(&self) -> &[seL4_UntypedDesc] {
        let len = self.untyped.end - self.untyped.start;
        // sanity check that the number of untypeds doesn't extend past the end of the page
        debug_assert!(
            len <= (4096 - size_of::<seL4_BootInfo>() + size_of::<seL4_UntypedDesc>())
                / size_of::<seL4_UntypedDesc>()
        );
        core::slice::from_raw_parts(&self.untypedList, len)
    }
}
<commit_msg>sel4-sys: add helper for seL4_UntypedDesc<commit_after>/* Copyright (c) 2015 The Robigalia Project Developers
 * Licensed under the Apache License, Version 2.0
 * <LICENSE-APACHE or
 * http://www.apache.org/licenses/LICENSE-2.0> or the MIT
 * license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
 * at your option. All files in the project carrying such
 * notice may not be copied, modified, or distributed except
 * according to those terms.
 */
#![no_std]
#![feature(asm)]
#![feature(thread_local)]
#![allow(bad_style, unused_parens, unused_assignments)]

// NB: this mimics the logic in build.rs
#[cfg(not(any(
    all(target_arch = "arm", target_pointer_width = "32"),
    all(target_arch = "riscv32"),
    all(target_arch = "x86"),
    all(target_arch = "x86_64"),
)))]
use architecture_not_supported_sorry;

pub use seL4_BreakpointAccess::*;
pub use seL4_BreakpointType::*;
pub use seL4_Error::*;
pub use seL4_LookupFailureType::*;
pub use seL4_ObjectType::*;

use core::mem::size_of;

// XXX: These can't be repr(C), but it needs to "match an int" according to the comments on
// SEL4_FORCE_LONG_ENUM. There's no single type that matches in Rust, so it needs to be
// per-architecture. We use a macro to define them all in one whack, with the invoker providing
// only what the size of the enums ought to be. Each arch then invokes it.
macro_rules! error_types {
    ($int_width:ident) => {
        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_Error {
            seL4_NoError = 0,
            seL4_InvalidArgument,
            seL4_InvalidCapability,
            seL4_IllegalOperation,
            seL4_RangeError,
            seL4_AlignmentError,
            seL4_FailedLookup,
            seL4_TruncatedMessage,
            seL4_DeleteFirst,
            seL4_RevokeFirst,
            seL4_NotEnoughMemory,
            // NB: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_LookupFailureType {
            seL4_NoFailure = 0,
            seL4_InvalidRoot,
            seL4_MissingCapability,
            seL4_DepthMismatch,
            seL4_GuardMismatch,
            // XXX: Code depends on this being the last variant
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointType {
            seL4_DataBreakpoint = 0,
            seL4_InstructionBreakpoint,
            seL4_SingleStep,
            seL4_SoftwareBreakRequest,
        }

        #[repr($int_width)]
        #[derive(Debug, Copy, Clone, PartialEq, Eq)]
        pub enum seL4_BreakpointAccess {
            seL4_BreakOnRead = 0,
            seL4_BreakOnWrite,
            seL4_BreakOnReadWrite,
        }
    };
}

// NB: potentially arch-dependent
pub type seL4_Word = usize;
pub type seL4_CPtr = usize;

#[cfg(target_arch = "x86")]
include!("arch/x86.rs");

#[cfg(target_arch = "x86_64")]
include!("arch/x86_64.rs");

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!("arch/arm.rs");

#[cfg(target_arch = "riscv32")]
include!("arch/riscv.rs");

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_invocation.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_invocation.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_invocation.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_invocation.rs"));

#[cfg(all(target_arch = "x86"))]
include!(concat!(env!("OUT_DIR"), "/ia32_syscall_stub.rs"));

#[cfg(all(target_arch = "x86_64"))]
include!(concat!(env!("OUT_DIR"), "/x86_64_syscall_stub.rs"));

#[cfg(all(target_arch = "arm", target_pointer_width = "32"))]
include!(concat!(env!("OUT_DIR"), "/aarch32_syscall_stub.rs"));

#[cfg(target_arch = "riscv32")]
include!(concat!(env!("OUT_DIR"), "/riscv32_syscall_stub.rs"));

#[cfg(target_pointer_width = "32")]
include!(concat!(env!("OUT_DIR"), "/types32.rs"));

#[cfg(target_pointer_width = "64")]
include!(concat!(env!("OUT_DIR"), "/types64.rs"));

include!(concat!(env!("OUT_DIR"), "/syscalls.rs"));

// Well-known types from libsel4/include/sel4/types.h

pub type seL4_NodeId = seL4_Word;
pub type seL4_PAddr = seL4_Word;
pub type seL4_Domain = seL4_Word;

pub type seL4_CNode = seL4_CPtr;
pub type seL4_IRQHandler = seL4_CPtr;
pub type seL4_IRQControl = seL4_CPtr;
pub type seL4_TCB = seL4_CPtr;
pub type seL4_Untyped = seL4_CPtr;
pub type seL4_DomainSet = seL4_CPtr;
pub type seL4_SchedContext = seL4_CPtr;
pub type seL4_SchedControl = seL4_CPtr;

// TODO(sleffler): seL4 uses seL4_Uint64 but it's not defined for us
pub type seL4_Time = u64;

pub const seL4_MsgLengthBits: usize = 7;
pub const seL4_MsgMaxLength: usize = 120;
pub const seL4_MsgExtraCapBits: usize = 2;
pub const seL4_MsgMaxExtraCaps: usize = (1usize << seL4_MsgExtraCapBits) - 1;

// Syscall stubs are generated to return seL4_Result unless they return
// an APi struct with an embedded error code. The latter should be replaced
// too but for now we leave it as-is.
pub type seL4_Result = Result<(), seL4_Error>;

// NB: these traits are used by syscall stubs.
impl From<seL4_Error> for seL4_Result {
    fn from(err: seL4_Error) -> seL4_Result {
        if err == seL4_NoError {
            Ok(())
        } else {
            Err(err)
        }
    }
}
// NB: usize works for both 32- and 64-bit architectures
impl From<usize> for seL4_Error {
    fn from(val: usize) -> seL4_Error {
        // TODO(sleffler): 10 is seL4_NotEnoughMemory
        debug_assert!(val <= 10, "Invalid seL4_Error");
        unsafe { ::core::mem::transmute(val) }
    }
}

#[repr(C)]
#[derive(Copy, Debug)]
/// Buffer used to store received IPC messages
pub struct seL4_IPCBuffer {
    /// Message tag
    ///
    /// The kernel does not initialize this.
    pub tag: seL4_MessageInfo,
    /// Message contents
    ///
    /// The kernel only initializes the bytes which were not able to fit into physical registers.
    pub msg: [seL4_Word; seL4_MsgMaxLength],
    /// Arbitrary user data.
    ///
    /// The seL4 C libraries expect this to be a pointer to the IPC buffer in the thread's VSpace.,
    /// but this doesn't really matter.
    pub userData: seL4_Word,
    /// Capabilities to transfer (if sending) or unwrapped badges
    pub caps_or_badges: [seL4_Word; seL4_MsgMaxExtraCaps],
    /// CPtr to a CNode in the thread's CSpace from which to find the receive slot
    pub receiveCNode: seL4_CPtr,
    /// CPtr to the receive slot, relative to receiveCNode
    pub receiveIndex: seL4_CPtr,
    /// Number of bits of receiveIndex to use
    pub receiveDepth: seL4_Word,
}

impl ::core::clone::Clone for seL4_IPCBuffer {
    fn clone(&self) -> Self {
        *self
    }
}

// Bootinfo

// Fixed cap slots for root thread.
pub const seL4_CapNull: seL4_Word = 0; // null cap
pub const seL4_CapInitThreadTCB: seL4_Word = 1; // initial thread's TCB
pub const seL4_CapInitThreadCNode: seL4_Word = 2; // initial thread's root CNode
pub const seL4_CapInitThreadVSpace: seL4_Word = 3; // initial thread's VSpace
pub const seL4_CapIRQControl: seL4_Word = 4; // global IRQ controller
pub const seL4_CapASIDControl: seL4_Word = 5; // global ASID controller
pub const seL4_CapInitThreadASIDPool: seL4_Word = 6; // initial thread's ASID pool
pub const seL4_CapIOPort: seL4_Word = 7; // global IO port (null if not supported)
pub const seL4_CapIOSpace: seL4_Word = 8; // global IO space (null if no IOMMU support)
pub const seL4_CapBootInfoFrame: seL4_Word = 9; // bootinfo frame
pub const seL4_CapInitThreadIPCBuffer: seL4_Word = 10; // initial thread's IPC buffer frame
pub const seL4_CapDomain: seL4_Word = 11; // global domain controller

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// A half-open [start..end) range of slots
pub struct seL4_SlotRegion {
    /// First CNode slot position of the region
    pub start: seL4_Word,
    /// First CNode slot position after the region
    pub end: seL4_Word, /* first CNode slot position AFTER region */
}

#[repr(C, packed)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct seL4_UntypedDesc {
    /// Physical address corresponding of the untyped object's backing memory
    pub paddr: seL4_Word,
    pub padding1: u8,
    pub padding2: u8,
    /// log2 size of the region of memory backing the untyped object
    pub sizeBits: u8,
    /// Whether the backing memory corresponds to some device memory
    pub isDevice: u8,
}
impl seL4_UntypedDesc {
    pub fn is_device(&self) -> bool { self.isDevice != 0 }
    pub fn size_bits(&self) -> usize { self.sizeBits as usize }
}

// explicitly *not* Copy. the array at the end is tricky to handle.
// #[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)

#[repr(C, packed)]
pub struct seL4_BootInfo {
    /// Length of any additional bootinfo information
    pub extraLen: seL4_Word,
    /// ID [0..numNodes-1] of the current node (0 if uniprocessor)
    pub nodeID: seL4_Word,
    /// Number of seL4 nodes (1 if uniprocessor)
    pub numNodes: seL4_Word,
    /// Number of IOMMU PT levels (0 if no IOMMU support)
    pub numIOPTLevels: seL4_Word,
    /// pointer to root task's IPC buffer */
    pub ipcBuffer: *mut seL4_IPCBuffer,
    /// Empty slots (null caps)
    pub empty: seL4_SlotRegion,
    /// Frames shared between nodes
    pub sharedFrames: seL4_SlotRegion,
    /// Frame caps used for the loaded ELF image of the root task
    pub userImageFrames: seL4_SlotRegion,
    /// PD caps used for the loaded ELF image of the root task
    pub userImagePaging: seL4_SlotRegion,
    /// IOSpace caps for ARM SMMU
    pub ioSpaceCaps: seL4_SlotRegion,
    /// Caps fr anypages used to back the additional bootinfo information
    pub extraBIPages: seL4_SlotRegion,
    /// log2 size of root task's CNode
    pub initThreadCNodeSizeBits: u8,
    /// Root task's domain ID
    pub initThreadDomain: u32,

    #[cfg(feature = "SEL4_CONFIG_KERNEL_MCS")]
    // Caps to sched_control for each node
    pub schedcontrol: seL4_SlotRegion,

    /// Untyped object caps
    pub untyped: seL4_SlotRegion,
    /// Information about each untyped cap
    ///
    /// *Note*! This is actually an array! The actual length depends on kernel configuration which
    /// we have no way of knowing at this point. Use the `untyped_descs` method.
    pub untypedList: seL4_UntypedDesc,
}

#[repr(C, packed)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct seL4_BootInfoHeader {
    /// Identifier of the following chunk
    pub id: seL4_Word,
    /// Length of the chunk
    pub len: seL4_Word,
}

impl seL4_BootInfo {
    /// This is safe if you don't mutate the `untyped` field and corrupt its length.
    pub unsafe fn untyped_descs(&self) -> &[seL4_UntypedDesc] {
        let len = self.untyped.end - self.untyped.start;
        // sanity check that the number of untypeds doesn't extend past the end of the page
        debug_assert!(
            len <= (4096 - size_of::<seL4_BootInfo>() + size_of::<seL4_UntypedDesc>())
                / size_of::<seL4_UntypedDesc>()
        );
        core::slice::from_raw_parts(&self.untypedList, len)
    }
}
<|endoftext|>


<commit_before>#[macro_export]
/// Queries the database for the names of all tables, and calls
/// [`infer_table_from_schema!`](macro.infer_table_from_schema.html) for each
/// one. A schema name can optionally be passed to load from schemas other than
/// the default. If a schema name is given, the inferred tables will be wrapped
/// in a module with the same name.
///
/// Attempting to use the `env!` or `dotenv!` macros here will not work due to
/// limitations of the Macros 1.1 system, but you can pass a string in the form
/// `"env:SOME_ENV_VAR"` or `"dotenv:SOME_ENV_VAR"` to achieve the same effect.
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
macro_rules! infer_schema {
    ($database_url: expr) => {
        mod __diesel_infer_schema {
            #[derive(InferSchema)]
            #[infer_schema_options(database_url=$database_url)]
            struct _Dummy;
        }
        pub use self::__diesel_infer_schema::*;
    };

    ($database_url: expr, $schema_name: expr) => {
        mod __diesel_infer_schema {
            #[derive(InferSchema)]
            #[infer_schema_options(database_url=$database_url, schema_name=$schema_name)]
            struct _Dummy;
        }
        pub use self::__diesel_infer_schema::*;
    };
}

#[macro_export]
/// Establishes a database connection at compile time, loads the schema
/// information about a table's columns, and invokes
/// [`table!`](macro.table.html) for you automatically. For tables in a schema
/// other than the default, the table name should be given as
/// `"schema_name.table_name"`.
///
/// Attempting to use the `env!` or `dotenv!` macros here will not work due to
/// limitations of the Macros 1.1 system, but you can pass a string in the form
/// `"env:SOME_ENV_VAR"` or `"dotenv:SOME_ENV_VAR"` to achieve the same effect.
///
/// At this time, the schema inference macros do not support types from third
/// party crates, and having any columns with a type not supported by the diesel
/// core crate will result in a compiler error (please [open an
/// issue](https://github.com/diesel-rs/diesel/issues/new) if this happens
/// unexpectedly for a type listed in our docs.)
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
macro_rules! infer_table_from_schema {
    ($database_url: expr, $table_name: expr) => {
        #[derive(InferTableFromSchema)]
        #[infer_table_from_schema_options(database_url=$database_url, table_name=$table_name)]
        struct __DieselInferTableFromSchema;
    }
}

#[macro_export]
/// This macro will read your migrations at compile time, and embed a module you can use to execute
/// them at runtime without the migration files being present on the file system. This is useful if
/// you would like to use Diesel's migration infrastructure, but want to ship a single executable
/// file (such as for embedded applications). It can also be used to apply migrations to an in
/// memory database (Diesel does this for its own test suite).
///
/// You can optionally pass the path to the migrations directory to this macro. When left
/// unspecified, Diesel Codegen will search for the migrations directory in the same way that
/// Diesel CLI does. If specified, the path should be relative to the directory where `Cargo.toml`
/// resides.
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("src/doctest_setup.rs");
/// # table! {
/// #   users {
/// #       id -> Integer,
/// #       name -> VarChar,
/// #   }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # embed_migrations!("../migrations/postgresql");
/// # #[cfg(feature = "mysql")]
/// # embed_migrations!("../migrations/mysql");
/// # #[cfg(feature = "sqlite")]
/// embed_migrations!("../migrations/sqlite");
///
/// fn main() {
///     let connection = establish_connection();
///
///     // This will run the necessary migrations.
///     embedded_migrations::run(&connection);
///
///     // By default the output is thrown out. If you want to redirect it to stdout, you
///     // should call embedded_migrations::run_with_output.
///     embedded_migrations::run_with_output(&connection, &mut std::io::stdout());
/// }
/// ```
macro_rules! embed_migrations {
    () => {
        mod embedded_migrations {
            #[derive(EmbedMigrations)]
            struct _Dummy;
        }
    };

    ($migrations_path: expr) => {
        mod embedded_migrations {
            #[derive(EmbedMigrations)]
            #[embed_migrations_options(migrations_path=$migrations_path)]
            struct _Dummy;
        }
    }
}
<commit_msg>Allow dead code in embedded migrations<commit_after>#[macro_export]
/// Queries the database for the names of all tables, and calls
/// [`infer_table_from_schema!`](macro.infer_table_from_schema.html) for each
/// one. A schema name can optionally be passed to load from schemas other than
/// the default. If a schema name is given, the inferred tables will be wrapped
/// in a module with the same name.
///
/// Attempting to use the `env!` or `dotenv!` macros here will not work due to
/// limitations of the Macros 1.1 system, but you can pass a string in the form
/// `"env:SOME_ENV_VAR"` or `"dotenv:SOME_ENV_VAR"` to achieve the same effect.
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
macro_rules! infer_schema {
    ($database_url: expr) => {
        mod __diesel_infer_schema {
            #[derive(InferSchema)]
            #[infer_schema_options(database_url=$database_url)]
            struct _Dummy;
        }
        pub use self::__diesel_infer_schema::*;
    };

    ($database_url: expr, $schema_name: expr) => {
        mod __diesel_infer_schema {
            #[derive(InferSchema)]
            #[infer_schema_options(database_url=$database_url, schema_name=$schema_name)]
            struct _Dummy;
        }
        pub use self::__diesel_infer_schema::*;
    };
}

#[macro_export]
/// Establishes a database connection at compile time, loads the schema
/// information about a table's columns, and invokes
/// [`table!`](macro.table.html) for you automatically. For tables in a schema
/// other than the default, the table name should be given as
/// `"schema_name.table_name"`.
///
/// Attempting to use the `env!` or `dotenv!` macros here will not work due to
/// limitations of the Macros 1.1 system, but you can pass a string in the form
/// `"env:SOME_ENV_VAR"` or `"dotenv:SOME_ENV_VAR"` to achieve the same effect.
///
/// At this time, the schema inference macros do not support types from third
/// party crates, and having any columns with a type not supported by the diesel
/// core crate will result in a compiler error (please [open an
/// issue](https://github.com/diesel-rs/diesel/issues/new) if this happens
/// unexpectedly for a type listed in our docs.)
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
macro_rules! infer_table_from_schema {
    ($database_url: expr, $table_name: expr) => {
        #[derive(InferTableFromSchema)]
        #[infer_table_from_schema_options(database_url=$database_url, table_name=$table_name)]
        struct __DieselInferTableFromSchema;
    }
}

#[macro_export]
/// This macro will read your migrations at compile time, and embed a module you can use to execute
/// them at runtime without the migration files being present on the file system. This is useful if
/// you would like to use Diesel's migration infrastructure, but want to ship a single executable
/// file (such as for embedded applications). It can also be used to apply migrations to an in
/// memory database (Diesel does this for its own test suite).
///
/// You can optionally pass the path to the migrations directory to this macro. When left
/// unspecified, Diesel Codegen will search for the migrations directory in the same way that
/// Diesel CLI does. If specified, the path should be relative to the directory where `Cargo.toml`
/// resides.
///
/// This macro can only be used in combination with the `diesel_codegen` or
/// `diesel_codegen_syntex` crates. It will not work on its own.
///
/// # Examples
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # #[macro_use] extern crate diesel_codegen;
/// # include!("src/doctest_setup.rs");
/// # table! {
/// #   users {
/// #       id -> Integer,
/// #       name -> VarChar,
/// #   }
/// # }
/// #
/// # #[cfg(feature = "postgres")]
/// # embed_migrations!("../migrations/postgresql");
/// # #[cfg(feature = "mysql")]
/// # embed_migrations!("../migrations/mysql");
/// # #[cfg(feature = "sqlite")]
/// embed_migrations!("../migrations/sqlite");
///
/// fn main() {
///     let connection = establish_connection();
///
///     // This will run the necessary migrations.
///     embedded_migrations::run(&connection);
///
///     // By default the output is thrown out. If you want to redirect it to stdout, you
///     // should call embedded_migrations::run_with_output.
///     embedded_migrations::run_with_output(&connection, &mut std::io::stdout());
/// }
/// ```
macro_rules! embed_migrations {
    () => {
        #[allow(dead_code)]
        mod embedded_migrations {
            #[derive(EmbedMigrations)]
            struct _Dummy;
        }
    };

    ($migrations_path: expr) => {
        #[allow(dead_code)]
        mod embedded_migrations {
            #[derive(EmbedMigrations)]
            #[embed_migrations_options(migrations_path=$migrations_path)]
            struct _Dummy;
        }
    }
}
<|endoftext|>


<commit_before>use associations::HasTable;
use helper_types::*;
use query_builder::{AsChangeset, IntoUpdateTarget};
use query_dsl::*;
use result::QueryResult;
#[cfg(any(feature = "sqlite", feature = "mysql"))]
use associations::Identifiable;

pub trait InternalSaveChangesDsl<Conn, T>: Sized {
    fn internal_save_changes(self, connection: &Conn) -> QueryResult<T>;
}

impl<T, U, Conn> InternalSaveChangesDsl<Conn, U> for T where
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    Update<T, T>: LoadDsl<Conn> + LoadQuery<Conn, U>,
{
    fn internal_save_changes(self, conn: &Conn) -> QueryResult<U> {
        ::update(self).set(self).get_result(conn)
    }
}

#[cfg(feature = "sqlite")]
use sqlite::SqliteConnection;

#[cfg(feature = "sqlite")]
impl<T, U> InternalSaveChangesDsl<SqliteConnection, U> for T where
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id>,
    Update<T, T>: ExecuteDsl<SqliteConnection>,
    Find<T::Table, T::Id>: LoadQuery<SqliteConnection, U>,
{
    fn internal_save_changes(self, conn: &SqliteConnection) -> QueryResult<U> {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

#[cfg(feature = "mysql")]
use mysql::MysqlConnection;

#[cfg(feature = "mysql")]
impl<T, U> InternalSaveChangesDsl<MysqlConnection, U> for T where
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id>,
    Update<T, T>: ExecuteDsl<MysqlConnection>,
    Find<T::Table, T::Id>: LoadQuery<MysqlConnection, U>,
{
    fn internal_save_changes(self, conn: &MysqlConnection) -> QueryResult<U> {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

pub trait SaveChangesDsl<Conn> {
    fn save_changes<T>(self, connection: &Conn) -> QueryResult<T> where
        Self: InternalSaveChangesDsl<Conn, T>,
    {
        self.internal_save_changes(connection)
    }
}

impl<T, Conn> SaveChangesDsl<Conn> for T where
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
{}
<commit_msg>Add some minimal docs for `save_changes`<commit_after>use associations::HasTable;
use helper_types::*;
use query_builder::{AsChangeset, IntoUpdateTarget};
use query_dsl::*;
use result::QueryResult;
#[cfg(any(feature = "sqlite", feature = "mysql"))]
use associations::Identifiable;

pub trait InternalSaveChangesDsl<Conn, T>: Sized {
    fn internal_save_changes(self, connection: &Conn) -> QueryResult<T>;
}

impl<T, U, Conn> InternalSaveChangesDsl<Conn, U> for T where
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    Update<T, T>: LoadDsl<Conn> + LoadQuery<Conn, U>,
{
    fn internal_save_changes(self, conn: &Conn) -> QueryResult<U> {
        ::update(self).set(self).get_result(conn)
    }
}

#[cfg(feature = "sqlite")]
use sqlite::SqliteConnection;

#[cfg(feature = "sqlite")]
impl<T, U> InternalSaveChangesDsl<SqliteConnection, U> for T where
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id>,
    Update<T, T>: ExecuteDsl<SqliteConnection>,
    Find<T::Table, T::Id>: LoadQuery<SqliteConnection, U>,
{
    fn internal_save_changes(self, conn: &SqliteConnection) -> QueryResult<U> {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

#[cfg(feature = "mysql")]
use mysql::MysqlConnection;

#[cfg(feature = "mysql")]
impl<T, U> InternalSaveChangesDsl<MysqlConnection, U> for T where
    T: Copy + Identifiable,
    T: AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
    T::Table: FindDsl<T::Id>,
    Update<T, T>: ExecuteDsl<MysqlConnection>,
    Find<T::Table, T::Id>: LoadQuery<MysqlConnection, U>,
{
    fn internal_save_changes(self, conn: &MysqlConnection) -> QueryResult<U> {
        try!(::update(self).set(self).execute(conn));
        T::table().find(self.id()).get_result(conn)
    }
}

pub trait SaveChangesDsl<Conn> {
    /// Sugar for types which implement both `AsChangeset` and `Identifiable`
    ///
    /// `foo.save_changes(&conn)` is equivalent to
    /// `update(foo::table().find(foo.id())).set(&foo).get_result(&conn)`
    fn save_changes<T>(self, connection: &Conn) -> QueryResult<T> where
        Self: InternalSaveChangesDsl<Conn, T>,
    {
        self.internal_save_changes(connection)
    }
}

impl<T, Conn> SaveChangesDsl<Conn> for T where
    T: Copy + AsChangeset<Target=<T as HasTable>::Table> + IntoUpdateTarget,
{}
<|endoftext|>


<commit_before>#![feature(asm)]

#[macro_use]
extern crate log;
#[cfg(feature = "smoltcp")]
extern crate smoltcp;
extern crate x86;
#[macro_use]
extern crate lazy_static;

#[cfg(not(feature = "smoltcp"))]
mod dummy;
#[cfg(feature = "smoltcp")]
mod net;

use log::{set_logger, set_max_level, LevelFilter, Metadata, Record};

/// Data structure to filter kernel messages
struct SysLogger;

impl log::Log for SysLogger {
	fn enabled(&self, _: &Metadata) -> bool {
		true
	}

	fn flush(&self) {
		// nothing to do
	}

	fn log(&self, record: &Record) {
		if self.enabled(record.metadata()) {
			println!("[{}] {}", record.level(), record.args());
		}
	}
}

#[no_mangle]
pub extern "C" fn sys_network_init() -> i32 {
	set_logger(&SysLogger).expect("Can't initialize logger");
	set_max_level(LevelFilter::Info);

	#[cfg(feature = "smoltcp")]
	let ret: i32 = if net::network_init().is_ok() { 0 } else { -1 };
	#[cfg(not(feature = "smoltcp"))]
	let ret: i32 = -1;

	if ret < 0 {
		debug!("uhyve network isn't available!");
	}

	ret
}
<commit_msg>remove obsolete feature "asm"<commit_after>#[macro_use]
extern crate log;
#[cfg(feature = "smoltcp")]
extern crate smoltcp;
extern crate x86;
#[macro_use]
extern crate lazy_static;

#[cfg(not(feature = "smoltcp"))]
mod dummy;
#[cfg(feature = "smoltcp")]
mod net;

use log::{set_logger, set_max_level, LevelFilter, Metadata, Record};

/// Data structure to filter kernel messages
struct SysLogger;

impl log::Log for SysLogger {
	fn enabled(&self, _: &Metadata) -> bool {
		true
	}

	fn flush(&self) {
		// nothing to do
	}

	fn log(&self, record: &Record) {
		if self.enabled(record.metadata()) {
			println!("[{}] {}", record.level(), record.args());
		}
	}
}

#[no_mangle]
pub extern "C" fn sys_network_init() -> i32 {
	set_logger(&SysLogger).expect("Can't initialize logger");
	set_max_level(LevelFilter::Info);

	#[cfg(feature = "smoltcp")]
	let ret: i32 = if net::network_init().is_ok() { 0 } else { -1 };
	#[cfg(not(feature = "smoltcp"))]
	let ret: i32 = -1;

	if ret < 0 {
		debug!("uhyve network isn't available!");
	}

	ret
}
<|endoftext|>