<commit_before>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// GPL v3 license. For full terms please see the LICENSE file.

extern crate ansi_term;

use self::ansi_term::{Colour};
use utils::PathMod;
use utils::Styled;

use std::fs;
#[cfg(target_family = "unix")]
use std::os;
use std::fs::{PathExt};
use std::path::{Path};
#[cfg(target_family = "windows")]
use std::os::windows;

/// Removes an entire directory and all of its contents. Assumes the path
/// given exists.
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::remove("does_not_exist");
/// ```
pub fn remove<F: AsRef<Path>>(path: F) {
    if path.as_ref().is_dir() {
        fs::remove_dir_all(&path).ok();
        println!("Removed: {}", path.as_ref().as_str().paint(Colour::Red));
    } else {
        fs::remove_file(&path).ok();
        println!("Removed: {}", path.as_ref().as_str().paint(Colour::Red));
    }
}

/// Creates a file, assumes it has the correct permissions to write to the
/// `path` given.
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::create_file("file.txt");
/// test::remove("file.txt");
/// ```
pub fn create_file<F: AsRef<Path>>(path: F) {
    fs::File::create(path).ok();
}

/// Creates a directory, assumes it has the correct permissions to create a
/// directory in the `path` given.
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::create_dir("test_dir");
/// test::remove("test_dir");
/// ```
pub fn create_dir<F: AsRef<Path>>(path: F) {
    fs::create_dir(path).ok();
}

#[cfg(target_family = "unix")]
pub fn test_create_symlink<T: AsRef<Path>, F: AsRef<Path>>(to: &T, from: &F) {
    match os::unix::fs::symlink(from, to) {
        Ok(_) => {
            println!("{} symlinked to {}", from.as_ref().as_str().bold(),
                to.as_ref().as_str().bold());
        },
        Err(e) => {
            panic!("{}", e.to_string().paint(Colour::Red));
        }
    }
}
<commit_msg>test: don't ignore Results, add tests<commit_after>// Copyright (C) 2015, Alberto Corona <alberto@0x1a.us>
// All rights reserved. This file is part of rpf, distributed under the
// GPL v3 license. For full terms please see the LICENSE file.

extern crate ansi_term;

use self::ansi_term::{Colour};
use utils::PathMod;
use utils::Styled;

use std::fs;
#[cfg(target_family = "unix")]
use std::os;
use std::fs::{PathExt};
use std::path::{Path};
#[cfg(target_family = "windows")]
use std::os::windows;

/// Removes a directory or file and all of its contents.
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::remove("does_not_exist");
/// ```
pub fn remove<F: AsRef<Path>>(path: F) {
    if path.as_ref().is_dir() {
        match fs::remove_dir_all(&path) {
            Ok(_) => { println!("test: removed directory '{}'",
                                path.as_ref().as_str().paint(Colour::Green)) },
            Err(_) => { println!("test: unable to remove directory '{}'",
                                 path.as_ref().as_str().paint(Colour::Red)) },
        }
    } else {
        match fs::remove_file(&path) {
            Ok(_) => { println!("test: removed file '{}'",
                                path.as_ref().as_str().paint(Colour::Green)) },
            Err(_) => { println!("test: unable to remove file '{}'",
                                 path.as_ref().as_str().paint(Colour::Red)) },
        }
    }
}

/// Creates a file
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::create_file("file.txt");
/// test::remove("file.txt");
/// ```
pub fn create_file<F: AsRef<Path>>(path: F) {
    match fs::File::create(&path) {
        Ok(_) => { println!("test: created file '{}'",
                            path.as_ref().as_str().paint(Colour::Green)) },
        Err(_) => { println!("test: unable to crate file '{}'",
                             path.as_ref().as_str().paint(Colour::Red)) },
    }
}

/// Creates a directory
///
/// # Example
/// ```
/// use rpf::test;
///
/// test::create_dir("test_dir");
/// test::remove("test_dir");
/// ```
pub fn create_dir<F: AsRef<Path>>(path: F) {
    match fs::create_dir(&path) {
        Ok(_) => { println!("test: created directory '{}'",
                            path.as_ref().as_str().paint(Colour::Green)) },
        Err(_) => { println!("test: unable to crate directory '{}'",
                             path.as_ref().as_str().paint(Colour::Red)) },
    }
}

#[cfg(target_family = "unix")]
pub fn test_create_symlink<T: AsRef<Path>, F: AsRef<Path>>(to: &T, from: &F) {
    match os::unix::fs::symlink(from, to) {
        Ok(_) => {
            println!("{} symlinked to {}", from.as_ref().as_str().bold(),
                to.as_ref().as_str().bold());
        },
        Err(e) => {
            panic!("{}", e.to_string().paint(Colour::Red));
        }
    }
}

#[test]
fn test_test_remove() {
    remove("does_not_exist");
}

#[test]
fn test_test_create_file() {
    create_file("test-file");
    remove("test-file");
}

#[test]
fn test_test_create_dir() {
    create_dir("test-dir");
    remove("test-dir");
}
<|endoftext|>


<commit_before>use super::replace_subtree;
use super::View;
use git2::*;
use std::path::Path;
use std::path::PathBuf;

pub struct ChainView {
    pub first: Box<dyn View>,
    pub second: Box<dyn View>,
}

impl View for ChainView {
    fn apply(&self, repo: &Repository, tree: &Tree) -> Option<Oid> {
        let r = self.first.apply(&repo, &tree).expect("no tree");
        return self
            .second
            .apply(&repo, &repo.find_tree(r).expect("no tree"));
    }

    fn unapply(&self, repo: &Repository, tree: &Tree, parent_tree: &Tree) -> Option<Oid> {
        let p = self.first.apply(&repo, &parent_tree).expect("no tree");
        let p = repo.find_tree(p).expect("no tree");
        let a = self.second.unapply(&repo, &tree, &p).expect("no tree");
        self.first
            .unapply(&repo, &repo.find_tree(a).expect("no tree"), &parent_tree)
    }
}
<commit_msg>Remove .expect() from ChainView.apply()<commit_after>use super::replace_subtree;
use super::View;
use git2::*;
use std::path::Path;
use std::path::PathBuf;

pub struct ChainView {
    pub first: Box<dyn View>,
    pub second: Box<dyn View>,
}

impl View for ChainView {
    fn apply(&self, repo: &Repository, tree: &Tree) -> Option<Oid> {
        if let Some(r) = self.first.apply(&repo, &tree) {
            if let Ok(t) = repo.find_tree(r) {
                return self.second.apply(&repo, &t);
            }
        }
        return None
    }

    fn unapply(&self, repo: &Repository, tree: &Tree, parent_tree: &Tree) -> Option<Oid> {
        let p = self.first.apply(&repo, &parent_tree).expect("no tree");
        let p = repo.find_tree(p).expect("no tree");
        let a = self.second.unapply(&repo, &tree, &p).expect("no tree");
        self.first
            .unapply(&repo, &repo.find_tree(a).expect("no tree"), &parent_tree)
    }
}
<|endoftext|>


<commit_before>//! # OpenTelemetry Span interface
//!
//! A `Span` represents a single operation within a trace. `Span`s can be nested to form a trace
//! tree. Each trace contains a root span, which typically describes the end-to-end latency and,
//! optionally, one or more sub-spans for its sub-operations.
//!
//! The `Span`'s start and end timestamps reflect the elapsed real time of the operation. A `Span`'s
//! start time SHOULD be set to the current time on span creation. After the `Span` is created, it
//! SHOULD be possible to change its name, set its `Attributes`, and add `Links` and `Events`.
//! These MUST NOT be changed after the `Span`'s end time has been set.
//!
//! `Spans` are not meant to be used to propagate information within a process. To prevent misuse,
//! implementations SHOULD NOT provide access to a `Span`'s attributes besides its `SpanContext`.
//!
//! Vendors may implement the `Span` interface to effect vendor-specific logic. However, alternative
//! implementations MUST NOT allow callers to create Spans directly. All `Span`s MUST be created
//! via a Tracer.
use crate::api;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::fmt;
use std::time::SystemTime;

/// Interface for a single operation within a trace.
pub trait Span: fmt::Debug + 'static + Send + Sync {
    /// An API to record events in the context of a given `Span`.
    ///
    /// Events have a time associated with the moment when they are
    /// added to the `Span`.
    ///
    /// Events SHOULD preserve the order in which they're set. This will typically match
    /// the ordering of the events' timestamps.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard event names and
    /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// which have prescribed semantic meanings.
    fn add_event(&self, name: String, attributes: Vec<api::KeyValue>) {
        self.add_event_with_timestamp(name, SystemTime::now(), attributes)
    }

    /// An API to record events at a specific time in the context of a given `Span`.
    ///
    /// Events SHOULD preserve the order in which they're set. This will typically match
    /// the ordering of the events' timestamps.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard event names and
    /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// which have prescribed semantic meanings.
    fn add_event_with_timestamp(
        &self,
        name: String,
        timestamp: SystemTime,
        attributes: Vec<api::KeyValue>,
    );

    /// Returns the `SpanContext` for the given `Span`. The returned value may be used even after
    /// the `Span is finished. The returned value MUST be the same for the entire `Span` lifetime.
    fn span_context(&self) -> api::SpanContext;

    /// Returns true if this `Span` is recording information like events with the `add_event`
    /// operation, attributes using `set_attributes`, status with `set_status`, etc.
    ///
    /// This flag SHOULD be used to avoid expensive computations of a `Span` attributes or events in
    /// case when a `Span` is definitely not recorded. Note that any child span's recording is
    /// determined independently from the value of this flag (typically based on the sampled flag of
    /// a `TraceFlag` on `SpanContext`).
    ///
    /// This flag may be true despite the entire trace being sampled out. This allows to record and
    /// process information about the individual Span without sending it to the backend. An example
    /// of this scenario may be recording and processing of all incoming requests for the processing
    /// and building of SLA/SLO latency charts while sending only a subset - sampled spans - to the
    /// backend. See also the sampling section of SDK design.
    ///
    /// Users of the API should only access the `is_recording` property when instrumenting code and
    /// never access `SampledFlag` unless used in context propagators.
    fn is_recording(&self) -> bool;

    /// An API to set a single `Attribute` where the attribute properties are passed
    /// as arguments. To avoid extra allocations some implementations may offer a separate API for
    /// each of the possible value types.
    ///
    /// An `Attribute` is defined as a `KeyValue` pair.
    ///
    /// Attributes SHOULD preserve the order in which they're set. Setting an attribute
    /// with the same key as an existing attribute SHOULD overwrite the existing
    /// attribute's value.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard
    /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// that have prescribed semantic meanings.
    fn set_attribute(&self, attribute: api::KeyValue);

    /// Sets the status of the `Span`. If used, this will override the default `Span`
    /// status, which is `OK`.
    ///
    /// Only the value of the last call will be recorded, and implementations are free
    /// to ignore previous calls.
    fn set_status(&self, code: api::StatusCode, message: String);

    /// Updates the `Span`'s name. After this update, any sampling behavior based on the
    /// name will depend on the implementation.
    ///
    /// It is highly discouraged to update the name of a `Span` after its creation.
    /// `Span` name is often used to group, filter and identify the logical groups of
    /// spans. Often, filtering logic will be implemented before the `Span` creation
    /// for performance reasons, and the name update may interfere with this logic.
    ///
    /// The method name is called `update_name` to differentiate this method from the
    /// regular property. It emphasizes that this operation signifies a
    /// major change for a `Span` and may lead to re-calculation of sampling or
    /// filtering decisions made previously depending on the implementation.
    fn update_name(&self, new_name: String);

    /// Finishes the `Span`.
    ///
    /// Implementations MUST ignore all subsequent calls to `end` (there might be
    /// exceptions when the tracer is streaming events and has no mutable state
    /// associated with the Span).
    ///
    /// Calls to `end` a Span MUST not have any effects on child `Span`s as they may
    /// still be running and can be ended later.
    ///
    ///This API MUST be non-blocking.
    fn end(&self);
}

/// `SpanKind` describes the relationship between the Span, its parents,
/// and its children in a `Trace`. `SpanKind` describes two independent
/// properties that benefit tracing systems during analysis.
///
/// The first property described by `SpanKind` reflects whether the `Span`
/// is a remote child or parent. `Span`s with a remote parent are
/// interesting because they are sources of external load. `Span`s with a
/// remote child are interesting because they reflect a non-local system
/// dependency.
///
/// The second property described by `SpanKind` reflects whether a child
/// `Span` represents a synchronous call.  When a child span is synchronous,
/// the parent is expected to wait for it to complete under ordinary
/// circumstances.  It can be useful for tracing systems to know this
/// property, since synchronous `Span`s may contribute to the overall trace
/// latency. Asynchronous scenarios can be remote or local.
///
/// In order for `SpanKind` to be meaningful, callers should arrange that
/// a single `Span` does not serve more than one purpose.  For example, a
/// server-side span should not be used directly as the parent of another
/// remote span.  As a simple guideline, instrumentation should create a
/// new `Span` prior to extracting and serializing the span context for a
/// remote call.
///
/// To summarize the interpretation of these kinds:
///
/// | `SpanKind` | Synchronous | Asynchronous | Remote Incoming | Remote Outgoing |
/// |------------|-----|-----|-----|-----|
/// | `Client`   | yes |     |     | yes |
/// | `Server`   | yes |     | yes |     |
/// | `Producer` |     | yes |     | yes |
/// | `Consumer` |     | yes | yes |     |
/// | `Internal` |     |     |     |     |
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum SpanKind {
    /// Indicates that the span describes a synchronous request to
    /// some remote service.  This span is the parent of a remote `Server`
    /// span and waits for its response.
    Client,
    /// Indicates that the span covers server-side handling of a
    /// synchronous RPC or other remote request.  This span is the child of
    /// a remote `Client` span that was expected to wait for a response.
    Server,
    /// Indicates that the span describes the parent of an
    /// asynchronous request.  This parent span is expected to end before
    /// the corresponding child `Consumer` span, possibly even before the
    /// child span starts. In messaging scenarios with batching, tracing
    /// individual messages requires a new `Producer` span per message to
    /// be created.
    Producer,
    /// Indicates that the span describes the child of an
    /// asynchronous `Producer` request.
    Consumer,
    /// Default value. Indicates that the span represents an
    /// internal operation within an application, as opposed to an
    /// operations with remote parents or children.
    Internal,
}

impl fmt::Display for SpanKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            SpanKind::Client => write!(f, "client"),
            SpanKind::Server => write!(f, "server"),
            SpanKind::Producer => write!(f, "producer"),
            SpanKind::Consumer => write!(f, "consumer"),
            SpanKind::Internal => write!(f, "internal"),
        }
    }
}

/// The `StatusCode` interface represents the status of a finished `Span`.
/// It's composed of a canonical code in conjunction with an optional
/// descriptive message.
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum StatusCode {
    /// OK is returned on success.
    OK = 0,
    /// Canceled indicates the operation was canceled (typically by the caller).
    Canceled = 1,
    /// Unknown error. An example of where this error may be returned is
    /// if a Status value received from another address space belongs to
    /// an error-space that is not known in this address space. Also
    /// errors raised by APIs that do not return enough error information
    /// may be converted to this error.
    Unknown = 2,
    /// InvalidArgument indicates client specified an invalid argument.
    /// Note that this differs from FailedPrecondition. It indicates arguments
    /// that are problematic regardless of the state of the system
    /// (e.g., a malformed file name).
    InvalidArgument = 3,
    /// DeadlineExceeded means operation expired before completion.
    /// For operations that change the state of the system, this error may be
    /// returned even if the operation has completed successfully. For
    /// example, a successful response from a server could have been delayed
    /// long enough for the deadline to expire.
    DeadlineExceeded = 4,
    /// NotFound means some requested entity (e.g., file or directory) was
    /// not found.
    NotFound = 5,
    /// AlreadyExists means an attempt to create an entity failed because one
    /// already exists.
    AlreadyExists = 6,
    /// PermissionDenied indicates the caller does not have permission to
    /// execute the specified operation. It must not be used for rejections
    /// caused by exhausting some resource (use ResourceExhausted
    /// instead for those errors). It must not be
    /// used if the caller cannot be identified (use Unauthenticated
    /// instead for those errors).
    PermissionDenied = 7,
    /// ResourceExhausted indicates some resource has been exhausted, perhaps
    /// a per-user quota, or perhaps the entire file system is out of space.
    ResourceExhausted = 8,
    /// FailedPrecondition indicates operation was rejected because the
    /// system is not in a state required for the operation's execution.
    /// For example, directory to be deleted may be non-empty, an rmdir
    /// operation is applied to a non-directory, etc.
    ///
    /// A litmus test that may help a service implementor in deciding
    /// between FailedPrecondition, Aborted, and Unavailable:
    ///  (a) Use Unavailable if the client can retry just the failing call.
    ///  (b) Use Aborted if the client should retry at a higher-level
    ///      (e.g., restarting a read-modify-write sequence).
    ///  (c) Use FailedPrecondition if the client should not retry until
    ///      the system state has been explicitly fixed. E.g., if an "rmdir"
    ///      fails because the directory is non-empty, FailedPrecondition
    ///      should be returned since the client should not retry unless
    ///      they have first fixed up the directory by deleting files from it.
    ///  (d) Use FailedPrecondition if the client performs conditional
    ///      REST Get/Update/Delete on a resource and the resource on the
    ///      server does not match the condition. E.g., conflicting
    ///      read-modify-write on the same resource.
    FailedPrecondition = 9,
    /// Aborted indicates the operation was aborted, typically due to a
    /// concurrency issue like sequencer check failures, transaction aborts,
    /// etc.
    ///
    /// See litmus test above for deciding between FailedPrecondition,
    /// Aborted, and Unavailable.
    Aborted = 10,
    /// OutOfRange means operation was attempted past the valid range.
    /// E.g., seeking or reading past end of file.
    ///
    /// Unlike InvalidArgument, this error indicates a problem that may
    /// be fixed if the system state changes. For example, a 32-bit file
    /// system will generate InvalidArgument if asked to read at an
    /// offset that is not in the range [0,2^32-1], but it will generate
    /// OutOfRange if asked to read from an offset past the current
    /// file size.
    ///
    /// There is a fair bit of overlap between FailedPrecondition and
    /// OutOfRange. We recommend using OutOfRange (the more specific
    /// error) when it applies so that callers who are iterating through
    /// a space can easily look for an OutOfRange error to detect when
    /// they are done.
    OutOfRange = 11,
    /// Unimplemented indicates operation is not implemented or not
    /// supported/enabled in this service.
    Unimplemented = 12,
    /// Internal errors. Means some invariants expected by underlying
    /// system has been broken. If you see one of these errors,
    /// something is very broken.
    Internal = 13,
    /// Unavailable indicates the service is currently unavailable.
    /// This is a most likely a transient condition and may be corrected
    /// by retrying with a backoff. Note that it is not always safe to retry
    /// non-idempotent operations.
    ///
    /// See litmus test above for deciding between FailedPrecondition,
    /// Aborted, and Unavailable.
    Unavailable = 14,
    /// DataLoss indicates unrecoverable data loss or corruption.
    DataLoss = 15,
    /// Unauthenticated indicates the request does not have valid
    /// authentication credentials for the operation.
    Unauthenticated = 16,
}
<commit_msg>[span] Add record_exception method. (#152)<commit_after>//! # OpenTelemetry Span interface
//!
//! A `Span` represents a single operation within a trace. `Span`s can be nested to form a trace
//! tree. Each trace contains a root span, which typically describes the end-to-end latency and,
//! optionally, one or more sub-spans for its sub-operations.
//!
//! The `Span`'s start and end timestamps reflect the elapsed real time of the operation. A `Span`'s
//! start time SHOULD be set to the current time on span creation. After the `Span` is created, it
//! SHOULD be possible to change its name, set its `Attributes`, and add `Links` and `Events`.
//! These MUST NOT be changed after the `Span`'s end time has been set.
//!
//! `Spans` are not meant to be used to propagate information within a process. To prevent misuse,
//! implementations SHOULD NOT provide access to a `Span`'s attributes besides its `SpanContext`.
//!
//! Vendors may implement the `Span` interface to effect vendor-specific logic. However, alternative
//! implementations MUST NOT allow callers to create Spans directly. All `Span`s MUST be created
//! via a Tracer.
use crate::api;
#[cfg(feature = "serialize")]
use serde::{Deserialize, Serialize};
use std::error::Error;
use std::fmt;
use std::time::SystemTime;

/// Interface for a single operation within a trace.
pub trait Span: fmt::Debug + 'static + Send + Sync {
    /// An API to record events in the context of a given `Span`.
    ///
    /// Events have a time associated with the moment when they are
    /// added to the `Span`.
    ///
    /// Events SHOULD preserve the order in which they're set. This will typically match
    /// the ordering of the events' timestamps.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard event names and
    /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// which have prescribed semantic meanings.
    fn add_event(&self, name: String, attributes: Vec<api::KeyValue>) {
        self.add_event_with_timestamp(name, SystemTime::now(), attributes)
    }

    /// Convenience method to record an exception/error as an `Event`
    ///
    /// An exception SHOULD be recorded as an Event on the span during which it occurred.
    /// The name of the event MUST be "exception".
    ///
    /// The semantic conventions for Errors are described in ["Semantic Conventions for Exceptions"](https://github.com/open-telemetry/opentelemetry-specification/blob/master/specification/trace/semantic_conventions/exceptions.md)
    ///
    /// For now we will not set `exception.stacktrace` attribute since the `Error::backtrace`
    /// method is still in nightly. Users can provide a stacktrace by using the
    /// `record_exception_with_stacktrace` method.
    ///
    /// Users can custom the exception message by overriding the `fmt::Display` trait's `fmt` method
    /// for the error.
    fn record_exception(&self, err: &dyn Error) {
        let attributes = vec![api::KeyValue::new(
            "exception.message",
            err.to_string(),
        )];

        self.add_event("exception".to_string(), attributes);
    }

    /// Convenience method to record a exception/error as an `Event` with custom stacktrace
    ///
    /// See `Span:record_exception` method for more details.
    fn record_exception_with_stacktrace(&self, err: &dyn Error, stacktrace: String) {
        let attributes = vec![api::KeyValue::new(
            "exception.message",
            err.to_string(),
        ), api::KeyValue::new("exception.stacktrace", stacktrace)];

        self.add_event("exception".to_string(), attributes);
    }

    /// An API to record events at a specific time in the context of a given `Span`.
    ///
    /// Events SHOULD preserve the order in which they're set. This will typically match
    /// the ordering of the events' timestamps.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard event names and
    /// keys"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// which have prescribed semantic meanings.
    fn add_event_with_timestamp(
        &self,
        name: String,
        timestamp: SystemTime,
        attributes: Vec<api::KeyValue>,
    );

    /// Returns the `SpanContext` for the given `Span`. The returned value may be used even after
    /// the `Span is finished. The returned value MUST be the same for the entire `Span` lifetime.
    fn span_context(&self) -> api::SpanContext;

    /// Returns true if this `Span` is recording information like events with the `add_event`
    /// operation, attributes using `set_attributes`, status with `set_status`, etc.
    ///
    /// This flag SHOULD be used to avoid expensive computations of a `Span` attributes or events in
    /// case when a `Span` is definitely not recorded. Note that any child span's recording is
    /// determined independently from the value of this flag (typically based on the sampled flag of
    /// a `TraceFlag` on `SpanContext`).
    ///
    /// This flag may be true despite the entire trace being sampled out. This allows to record and
    /// process information about the individual Span without sending it to the backend. An example
    /// of this scenario may be recording and processing of all incoming requests for the processing
    /// and building of SLA/SLO latency charts while sending only a subset - sampled spans - to the
    /// backend. See also the sampling section of SDK design.
    ///
    /// Users of the API should only access the `is_recording` property when instrumenting code and
    /// never access `SampledFlag` unless used in context propagators.
    fn is_recording(&self) -> bool;

    /// An API to set a single `Attribute` where the attribute properties are passed
    /// as arguments. To avoid extra allocations some implementations may offer a separate API for
    /// each of the possible value types.
    ///
    /// An `Attribute` is defined as a `KeyValue` pair.
    ///
    /// Attributes SHOULD preserve the order in which they're set. Setting an attribute
    /// with the same key as an existing attribute SHOULD overwrite the existing
    /// attribute's value.
    ///
    /// Note that the OpenTelemetry project documents certain ["standard
    /// attributes"](https://github.com/open-telemetry/opentelemetry-specification/tree/v0.5.0/specification/trace/semantic_conventions/README.md)
    /// that have prescribed semantic meanings.
    fn set_attribute(&self, attribute: api::KeyValue);

    /// Sets the status of the `Span`. If used, this will override the default `Span`
    /// status, which is `OK`.
    ///
    /// Only the value of the last call will be recorded, and implementations are free
    /// to ignore previous calls.
    fn set_status(&self, code: api::StatusCode, message: String);

    /// Updates the `Span`'s name. After this update, any sampling behavior based on the
    /// name will depend on the implementation.
    ///
    /// It is highly discouraged to update the name of a `Span` after its creation.
    /// `Span` name is often used to group, filter and identify the logical groups of
    /// spans. Often, filtering logic will be implemented before the `Span` creation
    /// for performance reasons, and the name update may interfere with this logic.
    ///
    /// The method name is called `update_name` to differentiate this method from the
    /// regular property. It emphasizes that this operation signifies a
    /// major change for a `Span` and may lead to re-calculation of sampling or
    /// filtering decisions made previously depending on the implementation.
    fn update_name(&self, new_name: String);

    /// Finishes the `Span`.
    ///
    /// Implementations MUST ignore all subsequent calls to `end` (there might be
    /// exceptions when the tracer is streaming events and has no mutable state
    /// associated with the Span).
    ///
    /// Calls to `end` a Span MUST not have any effects on child `Span`s as they may
    /// still be running and can be ended later.
    ///
    ///This API MUST be non-blocking.
    fn end(&self);
}

/// `SpanKind` describes the relationship between the Span, its parents,
/// and its children in a `Trace`. `SpanKind` describes two independent
/// properties that benefit tracing systems during analysis.
///
/// The first property described by `SpanKind` reflects whether the `Span`
/// is a remote child or parent. `Span`s with a remote parent are
/// interesting because they are sources of external load. `Span`s with a
/// remote child are interesting because they reflect a non-local system
/// dependency.
///
/// The second property described by `SpanKind` reflects whether a child
/// `Span` represents a synchronous call.  When a child span is synchronous,
/// the parent is expected to wait for it to complete under ordinary
/// circumstances.  It can be useful for tracing systems to know this
/// property, since synchronous `Span`s may contribute to the overall trace
/// latency. Asynchronous scenarios can be remote or local.
///
/// In order for `SpanKind` to be meaningful, callers should arrange that
/// a single `Span` does not serve more than one purpose.  For example, a
/// server-side span should not be used directly as the parent of another
/// remote span.  As a simple guideline, instrumentation should create a
/// new `Span` prior to extracting and serializing the span context for a
/// remote call.
///
/// To summarize the interpretation of these kinds:
///
/// | `SpanKind` | Synchronous | Asynchronous | Remote Incoming | Remote Outgoing |
/// |------------|-----|-----|-----|-----|
/// | `Client`   | yes |     |     | yes |
/// | `Server`   | yes |     | yes |     |
/// | `Producer` |     | yes |     | yes |
/// | `Consumer` |     | yes | yes |     |
/// | `Internal` |     |     |     |     |
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum SpanKind {
    /// Indicates that the span describes a synchronous request to
    /// some remote service.  This span is the parent of a remote `Server`
    /// span and waits for its response.
    Client,
    /// Indicates that the span covers server-side handling of a
    /// synchronous RPC or other remote request.  This span is the child of
    /// a remote `Client` span that was expected to wait for a response.
    Server,
    /// Indicates that the span describes the parent of an
    /// asynchronous request.  This parent span is expected to end before
    /// the corresponding child `Consumer` span, possibly even before the
    /// child span starts. In messaging scenarios with batching, tracing
    /// individual messages requires a new `Producer` span per message to
    /// be created.
    Producer,
    /// Indicates that the span describes the child of an
    /// asynchronous `Producer` request.
    Consumer,
    /// Default value. Indicates that the span represents an
    /// internal operation within an application, as opposed to an
    /// operations with remote parents or children.
    Internal,
}

impl fmt::Display for SpanKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            SpanKind::Client => write!(f, "client"),
            SpanKind::Server => write!(f, "server"),
            SpanKind::Producer => write!(f, "producer"),
            SpanKind::Consumer => write!(f, "consumer"),
            SpanKind::Internal => write!(f, "internal"),
        }
    }
}

/// The `StatusCode` interface represents the status of a finished `Span`.
/// It's composed of a canonical code in conjunction with an optional
/// descriptive message.
#[cfg_attr(feature = "serialize", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, PartialEq)]
pub enum StatusCode {
    /// OK is returned on success.
    OK = 0,
    /// Canceled indicates the operation was canceled (typically by the caller).
    Canceled = 1,
    /// Unknown error. An example of where this error may be returned is
    /// if a Status value received from another address space belongs to
    /// an error-space that is not known in this address space. Also
    /// errors raised by APIs that do not return enough error information
    /// may be converted to this error.
    Unknown = 2,
    /// InvalidArgument indicates client specified an invalid argument.
    /// Note that this differs from FailedPrecondition. It indicates arguments
    /// that are problematic regardless of the state of the system
    /// (e.g., a malformed file name).
    InvalidArgument = 3,
    /// DeadlineExceeded means operation expired before completion.
    /// For operations that change the state of the system, this error may be
    /// returned even if the operation has completed successfully. For
    /// example, a successful response from a server could have been delayed
    /// long enough for the deadline to expire.
    DeadlineExceeded = 4,
    /// NotFound means some requested entity (e.g., file or directory) was
    /// not found.
    NotFound = 5,
    /// AlreadyExists means an attempt to create an entity failed because one
    /// already exists.
    AlreadyExists = 6,
    /// PermissionDenied indicates the caller does not have permission to
    /// execute the specified operation. It must not be used for rejections
    /// caused by exhausting some resource (use ResourceExhausted
    /// instead for those errors). It must not be
    /// used if the caller cannot be identified (use Unauthenticated
    /// instead for those errors).
    PermissionDenied = 7,
    /// ResourceExhausted indicates some resource has been exhausted, perhaps
    /// a per-user quota, or perhaps the entire file system is out of space.
    ResourceExhausted = 8,
    /// FailedPrecondition indicates operation was rejected because the
    /// system is not in a state required for the operation's execution.
    /// For example, directory to be deleted may be non-empty, an rmdir
    /// operation is applied to a non-directory, etc.
    ///
    /// A litmus test that may help a service implementor in deciding
    /// between FailedPrecondition, Aborted, and Unavailable:
    ///  (a) Use Unavailable if the client can retry just the failing call.
    ///  (b) Use Aborted if the client should retry at a higher-level
    ///      (e.g., restarting a read-modify-write sequence).
    ///  (c) Use FailedPrecondition if the client should not retry until
    ///      the system state has been explicitly fixed. E.g., if an "rmdir"
    ///      fails because the directory is non-empty, FailedPrecondition
    ///      should be returned since the client should not retry unless
    ///      they have first fixed up the directory by deleting files from it.
    ///  (d) Use FailedPrecondition if the client performs conditional
    ///      REST Get/Update/Delete on a resource and the resource on the
    ///      server does not match the condition. E.g., conflicting
    ///      read-modify-write on the same resource.
    FailedPrecondition = 9,
    /// Aborted indicates the operation was aborted, typically due to a
    /// concurrency issue like sequencer check failures, transaction aborts,
    /// etc.
    ///
    /// See litmus test above for deciding between FailedPrecondition,
    /// Aborted, and Unavailable.
    Aborted = 10,
    /// OutOfRange means operation was attempted past the valid range.
    /// E.g., seeking or reading past end of file.
    ///
    /// Unlike InvalidArgument, this error indicates a problem that may
    /// be fixed if the system state changes. For example, a 32-bit file
    /// system will generate InvalidArgument if asked to read at an
    /// offset that is not in the range [0,2^32-1], but it will generate
    /// OutOfRange if asked to read from an offset past the current
    /// file size.
    ///
    /// There is a fair bit of overlap between FailedPrecondition and
    /// OutOfRange. We recommend using OutOfRange (the more specific
    /// error) when it applies so that callers who are iterating through
    /// a space can easily look for an OutOfRange error to detect when
    /// they are done.
    OutOfRange = 11,
    /// Unimplemented indicates operation is not implemented or not
    /// supported/enabled in this service.
    Unimplemented = 12,
    /// Internal errors. Means some invariants expected by underlying
    /// system has been broken. If you see one of these errors,
    /// something is very broken.
    Internal = 13,
    /// Unavailable indicates the service is currently unavailable.
    /// This is a most likely a transient condition and may be corrected
    /// by retrying with a backoff. Note that it is not always safe to retry
    /// non-idempotent operations.
    ///
    /// See litmus test above for deciding between FailedPrecondition,
    /// Aborted, and Unavailable.
    Unavailable = 14,
    /// DataLoss indicates unrecoverable data loss or corruption.
    DataLoss = 15,
    /// Unauthenticated indicates the request does not have valid
    /// authentication credentials for the operation.
    Unauthenticated = 16,
}
<|endoftext|>


<commit_before>use libc::c_char;
use ffi::prelude::{LLVMValueRef, LLVMModuleRef};
use ffi::analysis::LLVMVerifierFailureAction;
use ffi::{analysis, core, linker, LLVMModule};
use ffi::bit_writer as writer;
use ffi::bit_reader as reader;
use cbox::{CBox, CSemiBox};
use std::ffi::CString;
use std::iter::{Iterator, IntoIterator};
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::{env, fmt, mem};
use std::marker::PhantomData;
use std::path::Path;
use std::process::Command;
use buffer::MemoryBuffer;
use context::{Context, GetContext};
use value::Function;
use ty::Type;
use util;

/// Represents a single translation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module;
native_ref!(&Module = LLVMModuleRef);
impl Module {
    /// Create a new module in the context given with the name given.
    ///
    /// The lifetime of the module will match the lifetime of the context
    /// you instance it in because the context contains it.
    ///
    /// ```rust
    /// use llvm::*;
    /// let context = Context::new();
    /// let context = context.as_semi();
    /// let module = Module::new("name", &context);
    /// println!("{:?}", module)
    /// ```
    pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module> {
        let c_name = CString::new(name).unwrap();
        unsafe { CSemiBox::new(core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.into())) }
    }
    /// Parse this bitcode file into a module, or return an error string.
    pub fn parse_bitcode<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let mut err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_file(path));
            if reader::LLVMParseBitcodeInContext(context.into(), buf.as_ptr(), &mut out, &mut err) == 1 {
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Write this module's bitcode to the path given.
    pub fn write_bitcode(&self, path: &str) -> IoResult<()> {
        util::with_cstr(path, |cpath| unsafe {
            if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
                Err(Error::new(ErrorKind::Other, &format!("could not write to {}", path) as &str))
            } else {
                Ok(())
            }
        })
    }
    /// Add a function to the module with the name given.
    pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a mut Function {
        let c_name = CString::new(name).unwrap();
        unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
    }
    /// Returns the function with the name given if it exists.
    pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Returns the type with the name given if it exists.
    pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Clone this module.
    pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module> {
        CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
    }

    /// Returns the target data of this module represented as a string
    pub fn get_target(&self) -> &str {
        unsafe {
            let target = core::LLVMGetTarget(self.into());
            util::to_str(target as *mut c_char)
        }
    }

    /// Set the target data of this module
    pub fn set_target(&self, target: &str) {
        let c_target = CString::new(target).unwrap();
        unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
    }

    /// Verify that the module is safe to run.
    pub fn verify(&self) -> Result<(), CBox<str>> {
        unsafe {
            let mut error = mem::uninitialized();
            let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
            if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
                Err(CBox::new(error))
            } else {
                Ok(())
            }
        }
    }

    /// Compile the module into an object file at the given location.
    ///
    /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
    /// installed on the user's machine.
    pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<()> {
        let dir = env::temp_dir();
        let path = path.to_str().unwrap();
        let mod_path = dir.join("module.bc");
        let mod_path = mod_path.to_str().unwrap();
        try!(self.write_bitcode(mod_path));
        Command::new("llc")
            .arg(&format!("-O={}", opt_level))
            .arg("-filetype=obj")
            .arg("-o").arg(path)
            .arg(mod_path)
            .spawn()
            .map(|_| ())
    }

    /// Link a module into this module
    pub fn link(&self, src: &Module) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.into();
            let mut message = mem::uninitialized();
            if linker::LLVMLinkModules(dest, src, linker::LLVMLinkerMode::LLVMLinkerPreserveSource, &mut message) == 1 {
                Err(CBox::new(message))
            } else {
                Ok(())
            }
        }
    }

    /// Link a module into this module
    pub fn link_destroy(&self, src: CSemiBox<Module>) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.as_ptr();
            let mut message = mem::uninitialized();
            if linker::LLVMLinkModules(dest, src, linker::LLVMLinkerMode::LLVMLinkerDestroySource, &mut message) == 1 {
                Err(CBox::new(message))
            } else {
                Ok(())
            }
        }
    }
}
impl<'a> IntoIterator for &'a Module {
    type Item = &'a Function;
    type IntoIter = Functions<'a>;
    /// Iterate through the functions in the module
    fn into_iter(self) -> Functions<'a> {
        Functions {
            value: unsafe { core::LLVMGetFirstFunction(self.into()) },
            marker: PhantomData
        }
    }
}
get_context!(Module, LLVMGetModuleContext);
to_str!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);
#[derive(Copy, Clone)]
/// An iterator through the functions contained in a module.
pub struct Functions<'a> {
    value: LLVMValueRef,
    marker: PhantomData<&'a ()>
}
impl<'a> Iterator for Functions<'a> {
    type Item = &'a Function;
    fn next(&mut self) -> Option<&'a Function> {
        if self.value.is_null() {
            None
        } else {
            let c_next = unsafe { core::LLVMGetNextFunction(self.value) };
            self.value = c_next;
            Some(self.value.into())
        }
    }
}
<commit_msg>Add global value methods to Module<commit_after>use libc::c_char;
use ffi::prelude::{LLVMValueRef, LLVMModuleRef};
use ffi::analysis::LLVMVerifierFailureAction;
use ffi::{analysis, core, linker, LLVMModule};
use ffi::bit_writer as writer;
use ffi::bit_reader as reader;
use cbox::{CBox, CSemiBox};
use std::ffi::CString;
use std::iter::{Iterator, IntoIterator};
use std::io::{Error, ErrorKind};
use std::io::Result as IoResult;
use std::{env, fmt, mem};
use std::marker::PhantomData;
use std::path::Path;
use std::process::Command;
use buffer::MemoryBuffer;
use context::{Context, GetContext};
use value::{Function, Value};
use ty::Type;
use util;

/// Represents a single translation unit of code.
///
/// This is attached to the lifetime of the context that constructs it, but is owned by the `CSemiBox`.
pub struct Module;
native_ref!(&Module = LLVMModuleRef);
impl Module {
    /// Create a new module in the context given with the name given.
    ///
    /// The lifetime of the module will match the lifetime of the context
    /// you instance it in because the context contains it.
    ///
    /// ```rust
    /// use llvm::*;
    /// let context = Context::new();
    /// let context = context.as_semi();
    /// let module = Module::new("name", &context);
    /// println!("{:?}", module)
    /// ```
    pub fn new<'a>(name: &str, context: &'a Context) -> CSemiBox<'a, Module> {
        let c_name = CString::new(name).unwrap();
        unsafe { CSemiBox::new(core::LLVMModuleCreateWithNameInContext(c_name.as_ptr(), context.into())) }
    }
    /// Add a global to the module with the given type and name.
    pub fn add_global<'a>(&'a self, ty: &'a Type, name: &str) -> &'a Value {
        util::with_cstr(name, |ptr| unsafe {
            core::LLVMAddGlobal(self.into(), ty.into(), ptr).into()
        })
    }
    /// Get the global with the name given, or `None` if no global with that name exists.
    pub fn get_global<'a>(&'a self, name: &str) -> Option<&'a Value> {
        util::with_cstr(name, |ptr| unsafe {
            let ptr = core::LLVMGetNamedGlobal(self.into(), ptr);
            util::ptr_to_null(ptr)
        })
    }
    /// Parse this bitcode file into a module, or return an error string.
    pub fn parse_bitcode<'a>(context: &'a Context, path: &str) -> Result<CSemiBox<'a, Module>, CBox<str>> {
        unsafe {
            let mut out = mem::uninitialized();
            let mut err = mem::uninitialized();
            let buf = try!(MemoryBuffer::new_from_file(path));
            if reader::LLVMParseBitcodeInContext(context.into(), buf.as_ptr(), &mut out, &mut err) == 1 {
                Err(CBox::new(err))
            } else {
                Ok(CSemiBox::new(out))
            }
        }
    }
    /// Write this module's bitcode to the path given.
    pub fn write_bitcode(&self, path: &str) -> IoResult<()> {
        util::with_cstr(path, |cpath| unsafe {
            if writer::LLVMWriteBitcodeToFile(self.into(), cpath) != 0 {
                Err(Error::new(ErrorKind::Other, &format!("could not write to {}", path) as &str))
            } else {
                Ok(())
            }
        })
    }
    /// Add a function to the module with the name given.
    pub fn add_function<'a>(&'a self, name: &str, sig: &'a Type) -> &'a mut Function {
        let c_name = CString::new(name).unwrap();
        unsafe { core::LLVMAddFunction(self.into(), c_name.as_ptr(), sig.into()) }.into()
    }
    /// Returns the function with the name given if it exists.
    pub fn get_function<'a>(&'a self, name: &str) -> Option<&'a Function> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetNamedFunction(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Returns the type with the name given if it exists.
    pub fn get_type<'a>(&'a self, name: &str) -> Option<&'a Type> {
        let c_name = CString::new(name).unwrap();
        unsafe {
            let ty = core::LLVMGetTypeByName(self.into(), c_name.as_ptr());
            util::ptr_to_null(ty)
        }
    }
    /// Clone this module.
    pub fn clone<'a>(&'a self) -> CSemiBox<'a, Module> {
        CSemiBox::new(unsafe { core::LLVMCloneModule(self.into()) })
    }

    /// Returns the target data of this module represented as a string
    pub fn get_target(&self) -> &str {
        unsafe {
            let target = core::LLVMGetTarget(self.into());
            util::to_str(target as *mut c_char)
        }
    }

    /// Set the target data of this module
    pub fn set_target(&self, target: &str) {
        let c_target = CString::new(target).unwrap();
        unsafe { core::LLVMSetTarget(self.into(), c_target.as_ptr()) }
    }

    /// Verify that the module is safe to run.
    pub fn verify(&self) -> Result<(), CBox<str>> {
        unsafe {
            let mut error = mem::uninitialized();
            let action = LLVMVerifierFailureAction::LLVMReturnStatusAction;
            if analysis::LLVMVerifyModule(self.into(), action, &mut error) == 1 {
                Err(CBox::new(error))
            } else {
                Ok(())
            }
        }
    }

    /// Compile the module into an object file at the given location.
    ///
    /// Note that this uses the LLVM tool `llc` to do this, which may or may not be
    /// installed on the user's machine.
    pub fn compile(&self, path: &Path, opt_level: usize) -> IoResult<()> {
        let dir = env::temp_dir();
        let path = path.to_str().unwrap();
        let mod_path = dir.join("module.bc");
        let mod_path = mod_path.to_str().unwrap();
        try!(self.write_bitcode(mod_path));
        Command::new("llc")
            .arg(&format!("-O={}", opt_level))
            .arg("-filetype=obj")
            .arg("-o").arg(path)
            .arg(mod_path)
            .spawn()
            .map(|_| ())
    }

    /// Link a module into this module
    pub fn link(&self, src: &Module) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.into();
            let mut message = mem::uninitialized();
            if linker::LLVMLinkModules(dest, src, linker::LLVMLinkerMode::LLVMLinkerPreserveSource, &mut message) == 1 {
                Err(CBox::new(message))
            } else {
                Ok(())
            }
        }
    }

    /// Link a module into this module
    pub fn link_destroy(&self, src: CSemiBox<Module>) -> Result<(), CBox<str>> {
        unsafe {
            let dest = self.into();
            let src = src.as_ptr();
            let mut message = mem::uninitialized();
            if linker::LLVMLinkModules(dest, src, linker::LLVMLinkerMode::LLVMLinkerDestroySource, &mut message) == 1 {
                Err(CBox::new(message))
            } else {
                Ok(())
            }
        }
    }
}
impl<'a> IntoIterator for &'a Module {
    type Item = &'a Function;
    type IntoIter = Functions<'a>;
    /// Iterate through the functions in the module
    fn into_iter(self) -> Functions<'a> {
        Functions {
            value: unsafe { core::LLVMGetFirstFunction(self.into()) },
            marker: PhantomData
        }
    }
}
get_context!(Module, LLVMGetModuleContext);
to_str!(Module, LLVMPrintModuleToString);
dispose!(Module, LLVMModule, core::LLVMDisposeModule);
#[derive(Copy, Clone)]
/// An iterator through the functions contained in a module.
pub struct Functions<'a> {
    value: LLVMValueRef,
    marker: PhantomData<&'a ()>
}
impl<'a> Iterator for Functions<'a> {
    type Item = &'a Function;
    fn next(&mut self) -> Option<&'a Function> {
        if self.value.is_null() {
            None
        } else {
            let c_next = unsafe { core::LLVMGetNextFunction(self.value) };
            self.value = c_next;
            Some(self.value.into())
        }
    }
}
<|endoftext|>


<commit_before>use range::Range;
use read_token;
use std::rc::Rc;

use {
    MetaData,
    MetaReader,
    ParseError,
};

/// Contains information about number.
pub struct Number {
    /// The property to set.
    pub property: Option<Rc<String>>,
}

impl Number {
    /// Parses number.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        chars: &[char],
        offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        if let Some(range) = read_token::number(chars, offset) {
            let mut text = String::with_capacity(range.length);
            for c in chars.iter().take(range.length) {
                text.push(*c);
            }
            match text.parse::<f64>() {
                Err(err) => Err((range, ParseError::ParseFloatError(err))),
                Ok(val) => {
                    if let Some(ref property) = self.property {
                        match meta_reader.data(
                            MetaData::F64(property.clone(), val),
                            state,
                            range
                        ) {
                            Err(err) => Err((range, err)),
                            Ok(state) => Ok((range, state)),
                        }
                    } else {
                        Ok((range, state.clone()))
                    }
                }
            }
        } else {
            return Err((Range::new(offset, 0), ParseError::ExpectedNumber))
        }
    }
}
<commit_msg>Added unit tests for `Number`<commit_after>use range::Range;
use read_token;
use std::rc::Rc;

use {
    MetaData,
    MetaReader,
    ParseError,
};

/// Contains information about number.
pub struct Number {
    /// The property to set.
    pub property: Option<Rc<String>>,
}

impl Number {
    /// Parses number.
    pub fn parse<M>(
        &self,
        meta_reader: &mut M,
        state: &M::State,
        chars: &[char],
        offset: usize
    ) -> Result<(Range, M::State), (Range, ParseError)>
        where M: MetaReader
    {
        if let Some(range) = read_token::number(chars, offset) {
            let mut text = String::with_capacity(range.length);
            for c in chars.iter().take(range.length) {
                text.push(*c);
            }
            match text.parse::<f64>() {
                Err(err) => Err((range, ParseError::ParseFloatError(err))),
                Ok(val) => {
                    if let Some(ref property) = self.property {
                        match meta_reader.data(
                            MetaData::F64(property.clone(), val),
                            state,
                            range
                        ) {
                            Err(err) => Err((range, err)),
                            Ok(state) => Ok((range, state)),
                        }
                    } else {
                        Ok((range, state.clone()))
                    }
                }
            }
        } else {
            return Err((Range::new(offset, 0), ParseError::ExpectedNumber))
        }
    }
}

#[cfg(test)]
mod tests {
    use super::super::*;
    use range::Range;
    use std::rc::Rc;

    #[test]
    fn expected_number() {
        let text = "foo";
        let chars: Vec<char> = text.chars().collect();
        let number = Number { property: None };
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let res = number.parse(&mut tokenizer, &s, &chars, 0);
        assert_eq!(res, Err((Range::new(0, 0), ParseError::ExpectedNumber)));
    }

    #[test]
    fn successful() {
        let text = "foo 1 1.1 10e1 10.0E1";
        let chars: Vec<char> = text.chars().collect();
        let number = Number { property: None };
        let mut tokenizer = Tokenizer::new();
        let s = TokenizerState::new();
        let res = number.parse(&mut tokenizer, &s, &chars[4..], 4);
        assert_eq!(res, Ok((Range::new(4, 1), s)));
        let res = number.parse(&mut tokenizer, &s, &chars[6..], 6);
        assert_eq!(res, Ok((Range::new(6, 3), s)));
        let res = number.parse(&mut tokenizer, &s, &chars[10..], 10);
        assert_eq!(res, Ok((Range::new(10, 4), s)));

        let val: Rc<String> = Rc::new("val".into());
        let number = Number { property: Some(val.clone()) };
        let res = number.parse(&mut tokenizer, &s, &chars[15..], 15);
        assert_eq!(res, Ok((Range::new(15, 6), TokenizerState(1))));
        assert_eq!(tokenizer.tokens.len(), 1);
        assert_eq!(&tokenizer.tokens[0].0, &MetaData::F64(val.clone(), 10.0e1));
    }
}
<|endoftext|>


<commit_before>use std;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;

use class::ClassId;
use ctxt::{SemContext, get_ctxt};
use gc::root::IndirectObj;
use mem;
use vtable::VTable;

#[repr(C)]
pub struct Header {
    // ptr to class
    vtable: *mut VTable,

    // additional information>
    // bit 0 - marked flag
    // bit 1-4 - age (4 bits)
    info: usize,
}

impl Header {
    pub fn size() -> i32 {
        std::mem::size_of::<Header>() as i32
    }

    pub fn vtblptr(&self) -> *mut VTable {
        self.vtable
    }

    pub fn vtbl(&self) -> &mut VTable {
        unsafe { &mut *self.vtable }
    }

    pub fn set_mark(&mut self, value: bool) {
        self.info = if value {
            self.info | 1
        } else {
            self.info & (!1)
        };
    }

    pub fn marked(&self) -> bool {
        if (self.info & 1) != 0 { true } else { false }
    }

    pub fn age(&self) -> u32 {
        (self.info & 0x1E) as u32 >> 1
    }

    pub fn set_age(&mut self, age: u32) {
        assert!(age <= 15);
        self.info = (self.info & !0x1E) | (age << 1) as usize;
    }
}

#[test]
fn test_age() {
    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 3 << 1,
    };
    assert_eq!(3, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 15 << 1,
    };
    assert_eq!(15, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    assert_eq!(0, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0xFFFF,
    };
    assert_eq!(15, hdr.age());
}

#[test]
fn test_set_age() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };

    hdr.set_age(15);
    assert_eq!(15, hdr.age());

    hdr.set_age(0);
    assert_eq!(0, hdr.age());

    hdr.set_age(2);
    assert_eq!(2, hdr.age());
}

#[test]
#[should_panic]
fn test_set_age_over_15() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    hdr.set_age(16);
}

// is used to reference any object
#[repr(C)]
pub struct Obj {
    header: Header,
    data: u8,
}

impl Obj {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn size(&self) -> usize {
        let cls = self.header().vtbl().class();
        let size = cls.size;

        if size > 0 {
            return size as usize;
        }

        let ty = cls.ty;

        if cls.is_array {
            let handle: Handle<ByteArray> = Handle { ptr: self as *const Obj as *const ByteArray };

            let value = Header::size() as usize + mem::ptr_width() as usize +
                        cls.element_size as usize * handle.len() as usize;

            return mem::align_usize(value, mem::ptr_width() as usize);
        }

        if ty.cls_id() == get_ctxt().primitive_classes.str_class {
            let handle: Handle<Str> = Handle { ptr: self as *const Obj as *const Str };
            mem::align_usize(handle.size(), mem::ptr_width() as usize)
        } else {
            panic!("size unknown");
        }
    }

    pub fn visit_reference_fields<F>(&mut self, mut f: F)
        where F: FnMut(IndirectObj)
    {
        let classptr = self.header().vtbl().classptr;
        let cls = unsafe { &*classptr };

        if cls.is_object_array {
            let array = unsafe { &*(self as *const _ as *const StrArray) };

            // walk through all objects in array
            let mut ptr = array.data() as *mut *mut Obj;
            let last = unsafe { ptr.offset(array.len() as isize) };

            while ptr < last {
                f((ptr as usize).into());

                unsafe { ptr = ptr.offset(1) }
            }

            return;
        }

        for &offset in &cls.ref_fields {
            let obj = (self as *mut Obj as usize) + offset as usize;
            f(obj.into());
        }
    }
}

#[repr(C)]
pub struct Handle<T> {
    ptr: *const T,
}

unsafe impl<T> Send for Handle<T> {}

impl<T> Handle<T> {
    pub fn null() -> Handle<T> {
        Handle { ptr: ptr::null() }
    }

    pub fn cast<R>(&self) -> Handle<R> {
        Handle { ptr: self.ptr as *const R }
    }

    pub fn raw(&self) -> *const T {
        self.ptr
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.ptr as *mut T) }
    }
}

impl<T> Into<Handle<T>> for usize {
    fn into(self) -> Handle<T> {
        Handle { ptr: self as *const T }
    }
}

#[repr(C)]
pub struct Testing {
    header: Header,
    failed: bool,
}

impl Testing {
    pub fn has_failed(&self) -> bool {
        self.failed
    }
}

#[repr(C)]
pub struct Str {
    header: Header,
    length: usize,
    data: u8,
}

impl Str {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

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

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn to_cstring(&self) -> CString {
        let view = unsafe { slice::from_raw_parts(self.data(), self.len()) };

        CString::new(view).unwrap()
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() // string content
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer_in_perm(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_perm(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());
        }

        handle
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_heap(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());

            // string should end with 0 for C compatibility
            *(data.offset(buf.len() as isize)) = 0;
        }

        handle
    }

    pub fn concat(ctxt: &SemContext, lhs: Handle<Str>, rhs: Handle<Str>) -> Handle<Str> {
        let len = lhs.len() + rhs.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(lhs.data(), handle.data() as *mut u8, lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                                     handle.data().offset(lhs.len() as isize) as *mut u8,
                                     rhs.len());

            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }

    // duplicate string into a new object
    pub fn dup(&self, ctxt: &SemContext) -> Handle<Str> {
        let len = self.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(self.data(), handle.data() as *mut u8, len);
            *(handle.data().offset(len as isize) as *mut u8) = 0;
        }

        handle
    }
}

fn str_alloc_heap(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt,
              len,
              |ctxt, size| ctxt.gc.alloc(ctxt, size) as *const u8)
}

fn str_alloc_perm(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt, len, |ctxt, size| ctxt.gc.alloc_perm(size))
}

fn str_alloc<F>(ctxt: &SemContext, len: usize, alloc: F) -> Handle<Str>
    where F: FnOnce(&SemContext, usize) -> *const u8
{
    let size = Header::size() as usize      // Object header
                + mem::ptr_width() as usize // length field
                + len; // string content

    let size = mem::align_usize(size, mem::ptr_width() as usize);
    let ptr = alloc(ctxt, size) as usize;

    let clsid = ctxt.primitive_classes.str_class;
    let cls = ctxt.classes[clsid].borrow();
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Str> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

#[repr(C)]
pub struct Array<T: Copy> {
    header: Header,
    length: usize,
    data: u8,
    phantom: PhantomData<T>,
}

impl<T> Array<T>
    where T: Copy
{
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

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

    pub fn data(&self) -> *const T {
        &self.data as *const u8 as *const T
    }

    pub fn data_mut(&mut self) -> *mut T {
        &self.data as *const u8 as *mut T
    }

    pub fn get_at(&self, idx: usize) -> T {
        unsafe { *self.data().offset(idx as isize) }
    }

    pub fn set_at(&mut self, idx: usize, val: T) {
        unsafe {
            *self.data_mut().offset(idx as isize) = val;
        }
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() * std::mem::size_of::<T>() // array content
    }

    pub fn alloc(ctxt: &SemContext, len: usize, elem: T, clsid: ClassId) -> Handle<Array<T>> {
        let size = Header::size() as usize        // Object header
                   + mem::ptr_width() as usize    // length field
                   + len * std::mem::size_of::<T>(); // array content

        let ptr = ctxt.gc.alloc(ctxt, size) as usize;
        let cls = ctxt.classes[clsid].borrow();
        let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
        let mut handle: Handle<Array<T>> = ptr.into();
        handle.header_mut().vtable = vtable as *mut VTable;
        handle.length = len;

        for i in 0..handle.len() {
            unsafe {
                *handle.data_mut().offset(i as isize) = elem;
            }
        }

        handle
    }
}

pub fn offset_of_array_length() -> i32 {
    offset_of!(Array<i32>, length) as i32
}

pub fn offset_of_array_data() -> i32 {
    offset_of!(Array<i32>, data) as i32
}

pub type BoolArray = Array<bool>;
pub type ByteArray = Array<u8>;
pub type CharArray = Array<char>;
pub type IntArray = Array<i32>;
pub type LongArray = Array<i64>;
pub type FloatArray = Array<f32>;
pub type DoubleArray = Array<f64>;
pub type StrArray = Array<Handle<Str>>;

pub fn alloc(ctxt: &SemContext, clsid: ClassId) -> Handle<Obj> {
    let cls = ctxt.classes[clsid].borrow();
    let size = mem::align_usize(cls.size as usize, mem::ptr_width() as usize);

    let ptr = ctxt.gc.alloc(ctxt, size) as usize;
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Obj> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

pub struct Exception {
    pub header: Header,
    pub msg: Handle<Str>,
    pub backtrace: Handle<IntArray>,
    pub elements: Handle<Obj>,
}

pub struct StackTraceElement {
    pub header: Header,
    pub name: Handle<Str>,
    pub line: i32,
}
<commit_msg>remove null termination of strings<commit_after>use std;
use std::ffi::CString;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::ptr;
use std::slice;

use class::ClassId;
use ctxt::{SemContext, get_ctxt};
use gc::root::IndirectObj;
use mem;
use vtable::VTable;

#[repr(C)]
pub struct Header {
    // ptr to class
    vtable: *mut VTable,

    // additional information>
    // bit 0 - marked flag
    // bit 1-4 - age (4 bits)
    info: usize,
}

impl Header {
    pub fn size() -> i32 {
        std::mem::size_of::<Header>() as i32
    }

    pub fn vtblptr(&self) -> *mut VTable {
        self.vtable
    }

    pub fn vtbl(&self) -> &mut VTable {
        unsafe { &mut *self.vtable }
    }

    pub fn set_mark(&mut self, value: bool) {
        self.info = if value {
            self.info | 1
        } else {
            self.info & (!1)
        };
    }

    pub fn marked(&self) -> bool {
        if (self.info & 1) != 0 { true } else { false }
    }

    pub fn age(&self) -> u32 {
        (self.info & 0x1E) as u32 >> 1
    }

    pub fn set_age(&mut self, age: u32) {
        assert!(age <= 15);
        self.info = (self.info & !0x1E) | (age << 1) as usize;
    }
}

#[test]
fn test_age() {
    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 3 << 1,
    };
    assert_eq!(3, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 15 << 1,
    };
    assert_eq!(15, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    assert_eq!(0, hdr.age());

    let hdr = Header {
        vtable: ptr::null_mut(),
        info: 0xFFFF,
    };
    assert_eq!(15, hdr.age());
}

#[test]
fn test_set_age() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };

    hdr.set_age(15);
    assert_eq!(15, hdr.age());

    hdr.set_age(0);
    assert_eq!(0, hdr.age());

    hdr.set_age(2);
    assert_eq!(2, hdr.age());
}

#[test]
#[should_panic]
fn test_set_age_over_15() {
    let mut hdr = Header {
        vtable: ptr::null_mut(),
        info: 0,
    };
    hdr.set_age(16);
}

// is used to reference any object
#[repr(C)]
pub struct Obj {
    header: Header,
    data: u8,
}

impl Obj {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn size(&self) -> usize {
        let cls = self.header().vtbl().class();
        let size = cls.size;

        if size > 0 {
            return size as usize;
        }

        let ty = cls.ty;

        if cls.is_array {
            let handle: Handle<ByteArray> = Handle { ptr: self as *const Obj as *const ByteArray };

            let value = Header::size() as usize + mem::ptr_width() as usize +
                        cls.element_size as usize * handle.len() as usize;

            return mem::align_usize(value, mem::ptr_width() as usize);
        }

        if ty.cls_id() == get_ctxt().primitive_classes.str_class {
            let handle: Handle<Str> = Handle { ptr: self as *const Obj as *const Str };
            mem::align_usize(handle.size(), mem::ptr_width() as usize)
        } else {
            panic!("size unknown");
        }
    }

    pub fn visit_reference_fields<F>(&mut self, mut f: F)
        where F: FnMut(IndirectObj)
    {
        let classptr = self.header().vtbl().classptr;
        let cls = unsafe { &*classptr };

        if cls.is_object_array {
            let array = unsafe { &*(self as *const _ as *const StrArray) };

            // walk through all objects in array
            let mut ptr = array.data() as *mut *mut Obj;
            let last = unsafe { ptr.offset(array.len() as isize) };

            while ptr < last {
                f((ptr as usize).into());

                unsafe { ptr = ptr.offset(1) }
            }

            return;
        }

        for &offset in &cls.ref_fields {
            let obj = (self as *mut Obj as usize) + offset as usize;
            f(obj.into());
        }
    }
}

#[repr(C)]
pub struct Handle<T> {
    ptr: *const T,
}

unsafe impl<T> Send for Handle<T> {}

impl<T> Handle<T> {
    pub fn null() -> Handle<T> {
        Handle { ptr: ptr::null() }
    }

    pub fn cast<R>(&self) -> Handle<R> {
        Handle { ptr: self.ptr as *const R }
    }

    pub fn raw(&self) -> *const T {
        self.ptr
    }
}

// known limitation of #[derive(Copy, Clone)]
// traits need to be implemented manually
impl<T> Copy for Handle<T> {}
impl<T> Clone for Handle<T> {
    fn clone(&self) -> Handle<T> {
        *self
    }
}

impl<T> Deref for Handle<T> {
    type Target = T;

    fn deref(&self) -> &T {
        unsafe { &*self.ptr }
    }
}

impl<T> DerefMut for Handle<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { &mut *(self.ptr as *mut T) }
    }
}

impl<T> Into<Handle<T>> for usize {
    fn into(self) -> Handle<T> {
        Handle { ptr: self as *const T }
    }
}

#[repr(C)]
pub struct Testing {
    header: Header,
    failed: bool,
}

impl Testing {
    pub fn has_failed(&self) -> bool {
        self.failed
    }
}

#[repr(C)]
pub struct Str {
    header: Header,
    length: usize,
    data: u8,
}

impl Str {
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

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

    pub fn data(&self) -> *const u8 {
        &self.data as *const u8
    }

    pub fn to_cstring(&self) -> CString {
        let view = unsafe { slice::from_raw_parts(self.data(), self.len()) };

        CString::new(view).unwrap()
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() // string content
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer_in_perm(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_perm(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());
        }

        handle
    }

    /// allocates string from buffer in permanent space
    pub fn from_buffer(ctxt: &SemContext, buf: &[u8]) -> Handle<Str> {
        let mut handle = str_alloc_heap(ctxt, buf.len());
        handle.length = buf.len();

        unsafe {
            let data = handle.data() as *mut u8;

            // copy buffer content into Str
            ptr::copy_nonoverlapping(buf.as_ptr(), data, buf.len());
        }

        handle
    }

    pub fn concat(ctxt: &SemContext, lhs: Handle<Str>, rhs: Handle<Str>) -> Handle<Str> {
        let len = lhs.len() + rhs.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(lhs.data(), handle.data() as *mut u8, lhs.len());
            ptr::copy_nonoverlapping(rhs.data(),
                                     handle.data().offset(lhs.len() as isize) as *mut u8,
                                     rhs.len());
        }

        handle
    }

    // duplicate string into a new object
    pub fn dup(&self, ctxt: &SemContext) -> Handle<Str> {
        let len = self.len();
        let mut handle = str_alloc_heap(ctxt, len);

        unsafe {
            handle.length = len;

            ptr::copy_nonoverlapping(self.data(), handle.data() as *mut u8, len);
        }

        handle
    }
}

fn str_alloc_heap(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt,
              len,
              |ctxt, size| ctxt.gc.alloc(ctxt, size) as *const u8)
}

fn str_alloc_perm(ctxt: &SemContext, len: usize) -> Handle<Str> {
    str_alloc(ctxt, len, |ctxt, size| ctxt.gc.alloc_perm(size))
}

fn str_alloc<F>(ctxt: &SemContext, len: usize, alloc: F) -> Handle<Str>
    where F: FnOnce(&SemContext, usize) -> *const u8
{
    let size = Header::size() as usize      // Object header
                + mem::ptr_width() as usize // length field
                + len; // string content

    let size = mem::align_usize(size, mem::ptr_width() as usize);
    let ptr = alloc(ctxt, size) as usize;

    let clsid = ctxt.primitive_classes.str_class;
    let cls = ctxt.classes[clsid].borrow();
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Str> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

#[repr(C)]
pub struct Array<T: Copy> {
    header: Header,
    length: usize,
    data: u8,
    phantom: PhantomData<T>,
}

impl<T> Array<T>
    where T: Copy
{
    pub fn header(&self) -> &Header {
        &self.header
    }

    pub fn header_mut(&mut self) -> &mut Header {
        &mut self.header
    }

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

    pub fn data(&self) -> *const T {
        &self.data as *const u8 as *const T
    }

    pub fn data_mut(&mut self) -> *mut T {
        &self.data as *const u8 as *mut T
    }

    pub fn get_at(&self, idx: usize) -> T {
        unsafe { *self.data().offset(idx as isize) }
    }

    pub fn set_at(&mut self, idx: usize, val: T) {
        unsafe {
            *self.data_mut().offset(idx as isize) = val;
        }
    }

    pub fn size(&self) -> usize {
        Header::size() as usize         // Object header
            + mem::ptr_width() as usize // length field
            + self.len() * std::mem::size_of::<T>() // array content
    }

    pub fn alloc(ctxt: &SemContext, len: usize, elem: T, clsid: ClassId) -> Handle<Array<T>> {
        let size = Header::size() as usize        // Object header
                   + mem::ptr_width() as usize    // length field
                   + len * std::mem::size_of::<T>(); // array content

        let ptr = ctxt.gc.alloc(ctxt, size) as usize;
        let cls = ctxt.classes[clsid].borrow();
        let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
        let mut handle: Handle<Array<T>> = ptr.into();
        handle.header_mut().vtable = vtable as *mut VTable;
        handle.length = len;

        for i in 0..handle.len() {
            unsafe {
                *handle.data_mut().offset(i as isize) = elem;
            }
        }

        handle
    }
}

pub fn offset_of_array_length() -> i32 {
    offset_of!(Array<i32>, length) as i32
}

pub fn offset_of_array_data() -> i32 {
    offset_of!(Array<i32>, data) as i32
}

pub type BoolArray = Array<bool>;
pub type ByteArray = Array<u8>;
pub type CharArray = Array<char>;
pub type IntArray = Array<i32>;
pub type LongArray = Array<i64>;
pub type FloatArray = Array<f32>;
pub type DoubleArray = Array<f64>;
pub type StrArray = Array<Handle<Str>>;

pub fn alloc(ctxt: &SemContext, clsid: ClassId) -> Handle<Obj> {
    let cls = ctxt.classes[clsid].borrow();
    let size = mem::align_usize(cls.size as usize, mem::ptr_width() as usize);

    let ptr = ctxt.gc.alloc(ctxt, size) as usize;
    let vtable: *const VTable = &**cls.vtable.as_ref().unwrap();
    let mut handle: Handle<Obj> = ptr.into();
    handle.header_mut().vtable = vtable as *mut VTable;

    handle
}

pub struct Exception {
    pub header: Header,
    pub msg: Handle<Str>,
    pub backtrace: Handle<IntArray>,
    pub elements: Handle<Obj>,
}

pub struct StackTraceElement {
    pub header: Header,
    pub name: Handle<Str>,
    pub line: i32,
}
<|endoftext|>