<commit_before>//! Functionality related to publishing a new crate or version of a crate.

use hex::ToHex;
use std::sync::Arc;
use swirl::Job;

use crate::controllers::cargo_prelude::*;
use crate::git;
use crate::models::dependency;
use crate::models::{
    insert_version_owner_action, Badge, Category, Keyword, NewCrate, NewVersion, Rights,
    VersionAction,
};

use crate::render;
use crate::util::{read_fill, read_le_u32, Maximums};
use crate::views::{EncodableCrateUpload, GoodCrate, PublishWarnings};

/// Handles the `PUT /crates/new` route.
/// Used by `cargo publish` to publish a new crate or to publish a new version of an
/// existing crate.
///
/// Currently blocks the HTTP thread, perhaps some function calls can spawn new
/// threads and return completion or error through other methods  a `cargo publish
/// --status` command, via crates.io's front end, or email.
pub fn publish(req: &mut dyn Request) -> AppResult<Response> {
    let app = Arc::clone(req.app());

    // The format of the req.body() of a publish request is as follows:
    //
    // metadata length
    // metadata in JSON about the crate being published
    // .crate tarball length
    // .crate tarball file
    //
    // - The metadata is read and interpreted in the parse_new_headers function.
    // - The .crate tarball length is read in this function in order to save the size of the file
    //   in the version record in the database.
    // - Then the .crate tarball length is passed to the upload_crate function where the actual
    //   file is read and uploaded.

    let new_crate = parse_new_headers(req)?;

    let conn = app.primary_database.get()?;
    let ids = req.authenticate(&conn)?;
    let user = ids.find_user(&conn)?;

    let verified_email_address = user.verified_email(&conn)?;
    let verified_email_address = verified_email_address.ok_or_else(|| {
        cargo_err(
            "A verified email address is required to publish crates to crates.io. \
             Visit https://crates.io/me to set and verify your email address.",
        )
    })?;

    // Create a transaction on the database, if there are no errors,
    // commit the transactions to record a new or updated crate.
    conn.transaction(|| {
        let name = new_crate.name;
        let vers = &*new_crate.vers;
        let links = new_crate.links;
        let repo = new_crate.repository;
        let features = new_crate
            .features
            .into_iter()
            .map(|(k, v)| (k.0, v.into_iter().map(|v| v.0).collect()))
            .collect();
        let keywords = new_crate
            .keywords
            .iter()
            .map(|s| s.as_str())
            .collect::<Vec<_>>();
        let categories = new_crate
            .categories
            .iter()
            .map(|s| s.as_str())
            .collect::<Vec<_>>();

        // Persist the new crate, if it doesn't already exist
        let persist = NewCrate {
            name: &name,
            description: new_crate.description.as_deref(),
            homepage: new_crate.homepage.as_deref(),
            documentation: new_crate.documentation.as_deref(),
            readme: new_crate.readme.as_deref(),
            repository: repo.as_deref(),
            max_upload_size: None,
        };

        let license_file = new_crate.license_file.as_deref();
        let krate =
            persist.create_or_update(&conn, user.id, Some(&app.config.publish_rate_limit))?;

        let owners = krate.owners(&conn)?;
        if user.rights(req.app(), &owners)? < Rights::Publish {
            return Err(cargo_err(
                "this crate exists but you don't seem to be an owner. \
                 If you believe this is a mistake, perhaps you need \
                 to accept an invitation to be an owner before \
                 publishing.",
            ));
        }

        if krate.name != *name {
            return Err(cargo_err(&format_args!(
                "crate was previously named `{}`",
                krate.name
            )));
        }

        // Length of the .crate tarball, which appears after the metadata in the request body.
        // TODO: Not sure why we're using the total content length (metadata + .crate file length)
        // to compare against the max upload size... investigate that and perhaps change to use
        // this file length.
        let file_length = read_le_u32(req.body())?;

        let content_length = req
            .content_length()
            .chain_error(|| cargo_err("missing header: Content-Length"))?;

        let maximums = Maximums::new(
            krate.max_upload_size,
            app.config.max_upload_size,
            app.config.max_unpack_size,
        );

        if content_length > maximums.max_upload_size {
            return Err(cargo_err(&format_args!(
                "max upload size is: {}",
                maximums.max_upload_size
            )));
        }

        // This is only redundant for now. Eventually the duplication will be removed.
        let license = new_crate.license.clone();

        // Persist the new version of this crate
        let version = NewVersion::new(
            krate.id,
            vers,
            &features,
            license,
            license_file,
            // Downcast is okay because the file length must be less than the max upload size
            // to get here, and max upload sizes are way less than i32 max
            file_length as i32,
            user.id,
        )?
        .save(&conn, &new_crate.authors, &verified_email_address)?;

        insert_version_owner_action(
            &conn,
            version.id,
            user.id,
            ids.api_token_id(),
            VersionAction::Publish,
        )?;

        // Link this new version to all dependencies
        let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?;

        // Update all keywords for this crate
        Keyword::update_crate(&conn, &krate, &keywords)?;

        // Update all categories for this crate, collecting any invalid categories
        // in order to be able to warn about them
        let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?;

        // Update all badges for this crate, collecting any invalid badges in
        // order to be able to warn about them
        let ignored_invalid_badges = Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?;
        let top_versions = krate.top_versions(&conn)?;

        if let Some(readme) = new_crate.readme {
            render::render_and_upload_readme(
                version.id,
                readme,
                new_crate
                    .readme_file
                    .unwrap_or_else(|| String::from("README.md")),
                repo,
            )
            .enqueue(&conn)
            .map_err(|e| AppError::from_std_error(e))?;
        }

        let cksum = app
            .config
            .uploader
            .upload_crate(req, &krate, maximums, vers)?;

        let mut hex_cksum = String::new();
        cksum.write_hex(&mut hex_cksum)?;

        // Register this crate in our local git repo.
        let git_crate = git::Crate {
            name: name.0,
            vers: vers.to_string(),
            cksum: hex_cksum,
            features,
            deps: git_deps,
            yanked: Some(false),
            links,
        };
        git::add_crate(git_crate)
            .enqueue(&conn)
            .map_err(|e| AppError::from_std_error(e))?;

        // The `other` field on `PublishWarnings` was introduced to handle a temporary warning
        // that is no longer needed. As such, crates.io currently does not return any `other`
        // warnings at this time, but if we need to, the field is available.
        let warnings = PublishWarnings {
            invalid_categories: ignored_invalid_categories,
            invalid_badges: ignored_invalid_badges,
            other: vec![],
        };

        Ok(req.json(&GoodCrate {
            krate: krate.minimal_encodable(&top_versions, None, false, None),
            warnings,
        }))
    })
}

/// Used by the `krate::new` function.
///
/// This function parses the JSON headers to interpret the data and validates
/// the data during and after the parsing. Returns crate metadata.
fn parse_new_headers(req: &mut dyn Request) -> AppResult<EncodableCrateUpload> {
    // Read the json upload request
    let metadata_length = u64::from(read_le_u32(req.body())?);
    req.mut_extensions().insert(metadata_length);

    let max = req.app().config.max_upload_size;
    if metadata_length > max {
        return Err(cargo_err(&format_args!("max upload size is: {}", max)));
    }
    let mut json = vec![0; metadata_length as usize];
    read_fill(req.body(), &mut json)?;
    let json = String::from_utf8(json).map_err(|_| cargo_err("json body was not valid utf-8"))?;
    let new: EncodableCrateUpload = serde_json::from_str(&json)
        .map_err(|e| cargo_err(&format_args!("invalid upload request: {}", e)))?;

    // Make sure required fields are provided
    fn empty(s: Option<&String>) -> bool {
        s.map_or(true, String::is_empty)
    }

    // It can have up to three elements per below conditions.
    let mut missing = Vec::with_capacity(3);

    if empty(new.description.as_ref()) {
        missing.push("description");
    }
    if empty(new.license.as_ref()) && empty(new.license_file.as_ref()) {
        missing.push("license");
    }
    if new.authors.iter().all(String::is_empty) {
        missing.push("authors");
    }
    if !missing.is_empty() {
        return Err(cargo_err(&format_args!(
            "missing or empty metadata fields: {}. Please \
             see https://doc.rust-lang.org/cargo/reference/manifest.html for \
             how to upload metadata",
            missing.join(", ")
        )));
    }

    Ok(new)
}
<commit_msg>log crate name and version during publish<commit_after>//! Functionality related to publishing a new crate or version of a crate.

use hex::ToHex;
use std::sync::Arc;
use swirl::Job;

use crate::controllers::cargo_prelude::*;
use crate::git;
use crate::models::dependency;
use crate::models::{
    insert_version_owner_action, Badge, Category, Keyword, NewCrate, NewVersion, Rights,
    VersionAction,
};

use crate::render;
use crate::util::{read_fill, read_le_u32, Maximums};
use crate::views::{EncodableCrateUpload, GoodCrate, PublishWarnings};

/// Handles the `PUT /crates/new` route.
/// Used by `cargo publish` to publish a new crate or to publish a new version of an
/// existing crate.
///
/// Currently blocks the HTTP thread, perhaps some function calls can spawn new
/// threads and return completion or error through other methods  a `cargo publish
/// --status` command, via crates.io's front end, or email.
pub fn publish(req: &mut dyn Request) -> AppResult<Response> {
    let app = Arc::clone(req.app());

    // The format of the req.body() of a publish request is as follows:
    //
    // metadata length
    // metadata in JSON about the crate being published
    // .crate tarball length
    // .crate tarball file
    //
    // - The metadata is read and interpreted in the parse_new_headers function.
    // - The .crate tarball length is read in this function in order to save the size of the file
    //   in the version record in the database.
    // - Then the .crate tarball length is passed to the upload_crate function where the actual
    //   file is read and uploaded.

    let new_crate = parse_new_headers(req)?;

    req.log_metadata("crate_name", new_crate.name.to_string());
    req.log_metadata("crate_version", new_crate.vers.to_string());

    let conn = app.primary_database.get()?;
    let ids = req.authenticate(&conn)?;
    let user = ids.find_user(&conn)?;

    let verified_email_address = user.verified_email(&conn)?;
    let verified_email_address = verified_email_address.ok_or_else(|| {
        cargo_err(
            "A verified email address is required to publish crates to crates.io. \
             Visit https://crates.io/me to set and verify your email address.",
        )
    })?;

    // Create a transaction on the database, if there are no errors,
    // commit the transactions to record a new or updated crate.
    conn.transaction(|| {
        let name = new_crate.name;
        let vers = &*new_crate.vers;
        let links = new_crate.links;
        let repo = new_crate.repository;
        let features = new_crate
            .features
            .into_iter()
            .map(|(k, v)| (k.0, v.into_iter().map(|v| v.0).collect()))
            .collect();
        let keywords = new_crate
            .keywords
            .iter()
            .map(|s| s.as_str())
            .collect::<Vec<_>>();
        let categories = new_crate
            .categories
            .iter()
            .map(|s| s.as_str())
            .collect::<Vec<_>>();

        // Persist the new crate, if it doesn't already exist
        let persist = NewCrate {
            name: &name,
            description: new_crate.description.as_deref(),
            homepage: new_crate.homepage.as_deref(),
            documentation: new_crate.documentation.as_deref(),
            readme: new_crate.readme.as_deref(),
            repository: repo.as_deref(),
            max_upload_size: None,
        };

        let license_file = new_crate.license_file.as_deref();
        let krate =
            persist.create_or_update(&conn, user.id, Some(&app.config.publish_rate_limit))?;

        let owners = krate.owners(&conn)?;
        if user.rights(req.app(), &owners)? < Rights::Publish {
            return Err(cargo_err(
                "this crate exists but you don't seem to be an owner. \
                 If you believe this is a mistake, perhaps you need \
                 to accept an invitation to be an owner before \
                 publishing.",
            ));
        }

        if krate.name != *name {
            return Err(cargo_err(&format_args!(
                "crate was previously named `{}`",
                krate.name
            )));
        }

        // Length of the .crate tarball, which appears after the metadata in the request body.
        // TODO: Not sure why we're using the total content length (metadata + .crate file length)
        // to compare against the max upload size... investigate that and perhaps change to use
        // this file length.
        let file_length = read_le_u32(req.body())?;

        let content_length = req
            .content_length()
            .chain_error(|| cargo_err("missing header: Content-Length"))?;

        let maximums = Maximums::new(
            krate.max_upload_size,
            app.config.max_upload_size,
            app.config.max_unpack_size,
        );

        if content_length > maximums.max_upload_size {
            return Err(cargo_err(&format_args!(
                "max upload size is: {}",
                maximums.max_upload_size
            )));
        }

        // This is only redundant for now. Eventually the duplication will be removed.
        let license = new_crate.license.clone();

        // Persist the new version of this crate
        let version = NewVersion::new(
            krate.id,
            vers,
            &features,
            license,
            license_file,
            // Downcast is okay because the file length must be less than the max upload size
            // to get here, and max upload sizes are way less than i32 max
            file_length as i32,
            user.id,
        )?
        .save(&conn, &new_crate.authors, &verified_email_address)?;

        insert_version_owner_action(
            &conn,
            version.id,
            user.id,
            ids.api_token_id(),
            VersionAction::Publish,
        )?;

        // Link this new version to all dependencies
        let git_deps = dependency::add_dependencies(&conn, &new_crate.deps, version.id)?;

        // Update all keywords for this crate
        Keyword::update_crate(&conn, &krate, &keywords)?;

        // Update all categories for this crate, collecting any invalid categories
        // in order to be able to warn about them
        let ignored_invalid_categories = Category::update_crate(&conn, &krate, &categories)?;

        // Update all badges for this crate, collecting any invalid badges in
        // order to be able to warn about them
        let ignored_invalid_badges = Badge::update_crate(&conn, &krate, new_crate.badges.as_ref())?;
        let top_versions = krate.top_versions(&conn)?;

        if let Some(readme) = new_crate.readme {
            render::render_and_upload_readme(
                version.id,
                readme,
                new_crate
                    .readme_file
                    .unwrap_or_else(|| String::from("README.md")),
                repo,
            )
            .enqueue(&conn)
            .map_err(|e| AppError::from_std_error(e))?;
        }

        let cksum = app
            .config
            .uploader
            .upload_crate(req, &krate, maximums, vers)?;

        let mut hex_cksum = String::new();
        cksum.write_hex(&mut hex_cksum)?;

        // Register this crate in our local git repo.
        let git_crate = git::Crate {
            name: name.0,
            vers: vers.to_string(),
            cksum: hex_cksum,
            features,
            deps: git_deps,
            yanked: Some(false),
            links,
        };
        git::add_crate(git_crate)
            .enqueue(&conn)
            .map_err(|e| AppError::from_std_error(e))?;

        // The `other` field on `PublishWarnings` was introduced to handle a temporary warning
        // that is no longer needed. As such, crates.io currently does not return any `other`
        // warnings at this time, but if we need to, the field is available.
        let warnings = PublishWarnings {
            invalid_categories: ignored_invalid_categories,
            invalid_badges: ignored_invalid_badges,
            other: vec![],
        };

        Ok(req.json(&GoodCrate {
            krate: krate.minimal_encodable(&top_versions, None, false, None),
            warnings,
        }))
    })
}

/// Used by the `krate::new` function.
///
/// This function parses the JSON headers to interpret the data and validates
/// the data during and after the parsing. Returns crate metadata.
fn parse_new_headers(req: &mut dyn Request) -> AppResult<EncodableCrateUpload> {
    // Read the json upload request
    let metadata_length = u64::from(read_le_u32(req.body())?);
    req.mut_extensions().insert(metadata_length);

    let max = req.app().config.max_upload_size;
    if metadata_length > max {
        return Err(cargo_err(&format_args!("max upload size is: {}", max)));
    }
    let mut json = vec![0; metadata_length as usize];
    read_fill(req.body(), &mut json)?;
    let json = String::from_utf8(json).map_err(|_| cargo_err("json body was not valid utf-8"))?;
    let new: EncodableCrateUpload = serde_json::from_str(&json)
        .map_err(|e| cargo_err(&format_args!("invalid upload request: {}", e)))?;

    // Make sure required fields are provided
    fn empty(s: Option<&String>) -> bool {
        s.map_or(true, String::is_empty)
    }

    // It can have up to three elements per below conditions.
    let mut missing = Vec::with_capacity(3);

    if empty(new.description.as_ref()) {
        missing.push("description");
    }
    if empty(new.license.as_ref()) && empty(new.license_file.as_ref()) {
        missing.push("license");
    }
    if new.authors.iter().all(String::is_empty) {
        missing.push("authors");
    }
    if !missing.is_empty() {
        return Err(cargo_err(&format_args!(
            "missing or empty metadata fields: {}. Please \
             see https://doc.rust-lang.org/cargo/reference/manifest.html for \
             how to upload metadata",
            missing.join(", ")
        )));
    }

    Ok(new)
}
<|endoftext|>


<commit_before>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    bgt t1, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 11
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, s2             // third arg is app_heap_break
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<commit_msg>start_item_riscv32: Correctly pass the app_heap_break to Rust code<commit_after>use core::hint;

/// Tock programs' entry point. Called by the kernel at program start. Sets up
/// the stack then calls rust_start() for the remainder of setup.
#[doc(hidden)]
#[naked]
#[no_mangle]
#[link_section = ".start"]
// The args for this function are:
//    app_start: usize,
//    mem_start: usize,
//    memory_len: usize,
//    app_heap_break: usize,
// Due to Rust issue: https://github.com/rust-lang/rust/issues/42779 we can't have
// args to the function
pub unsafe extern "C" fn _start() -> ! {
    asm!(
    // Compute the stack top.
    //
    // struct hdr* myhdr = (struct hdr*) app_start;
    // uint32_t stacktop = (((uint32_t) mem_start + myhdr->stack_size + 7) & 0xfffffff8);
    "lw   t0, 36(a0)         // t0 = myhdr->stack_size
    addi t0, t0, 7          // t0 = myhdr->stack_size + 7
    add  t0, t0, a1         // t0 = mem_start + myhdr->stack_size + 7
    li   t1, 7              // t1 = 7
    not  t1, t1             // t1 = ~0x7
    and  t0, t0, t1         // t0 = (mem_start + myhdr->stack_size + 7) & ~0x7
    //
    // Compute the app data size and where initial app brk should go.
    // This includes the GOT, data, and BSS sections. However, we can't be sure
    // the linker puts them back-to-back, but we do assume that BSS is last
    // (i.e. myhdr->got_start < myhdr->bss_start && myhdr->data_start <
    // myhdr->bss_start). With all of that true, then the size is equivalent
    // to the end of the BSS section.
    //
    // uint32_t appdata_size = myhdr->bss_start + myhdr->bss_size;
    lw   t1, 24(a0)         // t1 = myhdr->bss_start
    lw   t2, 28(a0)         // t2 = myhdr->bss_size
    lw   t3,  4(a0)         // t3 = myhdr->got_start
    add  t1, t1, t2         // t1 = bss_start + bss_size
    //
    // Move arguments we need to keep over to callee-saved locations.
    mv   s0, a0             // s0 = void* app_start
    mv   s1, t0             // s1 = stack_top
    mv   s2, a3             // s2 = app_heap_break
    //
    // Now we may want to move the stack pointer. If the kernel set the
    // `app_heap_break` larger than we need (and we are going to call `brk()`
    // to reduce it) then our stack pointer will fit and we can move it now.
    // Otherwise after the first syscall (the memop to set the brk), the return
    // will use a stack that is outside of the process accessible memory.
    //
    bgt t1, a3, skip_set_sp // Compare `app_heap_break` with new brk.
                                // If our current `app_heap_break` is larger
                                // then we need to move the stack pointer
                                // before we call the `brk` syscall.
    mv  sp, t0              // Update the stack pointer

    skip_set_sp:            // Back to regularly scheduled programming.

    // Call `brk` to set to requested memory

    // memop(0, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 0               // a1 = 0
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Debug support, tell the kernel the stack location
    //
    // memop(10, stacktop);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 10              // a1 = 10
    mv  a2, s1              // a2 = stacktop
    ecall                   // memop
    //
    // Debug support, tell the kernel the heap location
    //
    // memop(11, stacktop + appdata_size);
    li  a0, 4               // a0 = 4   // memop syscall
    li  a1, 11              // a1 = 11
    mv  a2, t1              // a2 = appdata_size
    ecall                   // memop
    //
    // Setup initial stack pointer for normal execution
    // Call into the rest of startup. This should never return.
    mv   sp, s1             // sp = stacktop
    mv   a0, s0             // first arg is app_start
    mv   s0, sp             // Set the frame pointer to sp.
    mv   a1, s1             // second arg is stacktop
    mv   a2, t1             // third arg is app_heap_break that we told the kernel
    jal  rust_start"
    :                                                              // No output operands
    :
    : "memory", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17",
      "x5", "x6", "x7", "x28", "x29", "x30", "x31", "x1"           // Clobbers
    : "volatile"                                                   // Options
    );
    hint::unreachable_unchecked();
}

/// Ensure an abort symbol exists.
#[cfg(target_arch = "riscv32")]
#[link_section = ".start"]
#[export_name = "abort"]
pub extern "C" fn abort() {
    unsafe {
        asm! ("
            // Simply go back to the start as if we had just booted.
            j    _start
        "
        :
        :
        :
        : "volatile");
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

use context::Context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use context::event::EventHandler;
use context;
use reactor;
use TimerEvent;
use action::ExecResult;

pub struct TimerEventHandler {
    contexts: Vec<Rc<RefCell<Box<EventHandler<InternalRequest>>>>>
}

impl TimerEventHandler {
    pub fn new() -> TimerEventHandler {
        TimerEventHandler {
            contexts: Vec::new()
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<EventHandler<InternalRequest>>>>) {
        self.contexts.push(handler);
    }
}

impl reactor::EventHandler<InternalRequest> for TimerEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
            println!("timer event");
            let event: InternalRequest = event.into();
            for i in self.contexts.iter_mut() {
                //i.borrow_mut().handle_event(event.clone());
            }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Timer
    }
}
<commit_msg>TimerEventHandler: forward events to EventHandlers<commit_after>use std::cell::RefCell;
use std::rc::Rc;

use context::Context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use context::event::EventHandler;
use context;
use reactor;
use TimerEvent;
use action::ExecResult;

pub struct TimerEventHandler {
    contexts: Vec<Rc<RefCell<Box<EventHandler<InternalRequest>>>>>
}

impl TimerEventHandler {
    pub fn new() -> TimerEventHandler {
        TimerEventHandler {
            contexts: Vec::new()
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<EventHandler<InternalRequest>>>>) {
        self.contexts.push(handler);
    }
}

impl reactor::EventHandler<InternalRequest> for TimerEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
            println!("timer event");
            let event: InternalRequest = event.into();
            for i in self.contexts.iter_mut() {
                i.borrow_mut().handle_event(event.clone());
            }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Timer
    }
}
<|endoftext|>


<commit_before>#![no_std]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

// u8
impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

// u16
impl FromBitfield<[u8;2]> for u16 {
    fn from_bitfield(array: [u8;2]) -> Self {
        return
            (array[0] as u16) |
            (array[1] as u16) << 8;
    }
}

impl IntoBitfield<[u8;2]> for u16 {
    fn into_bitfield(self) -> [u8;2]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
        ];
    }
}

// u32 :3
impl IntoBitfield<[u8;3]> for u32 {
    fn into_bitfield(self) -> [u8;3]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
        ];
    }
}

impl FromBitfield<[u8;3]> for u32 {
    fn from_bitfield(array: [u8;3]) -> Self {
        return
            (array[0] as u32)      |
            (array[1] as u32) << 8 |
            (array[2] as u32) << 16;
    }
}

// u32 :4
impl IntoBitfield<[u8;4]> for u32 {
    fn into_bitfield(self) -> [u8;4]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
            (self >> 24 & 0xFF) as u8
        ];
    }
}

impl FromBitfield<[u8;4]> for u32 {
    fn from_bitfield(array: [u8;4]) -> Self {
        return
            (array[0] as u32)       |
            (array[1] as u32) << 8  |
            (array[2] as u32) << 16 |
            (array[3] as u32) << 24;

    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::{FromBitfield, IntoBitfield};

    macro_rules! test_into {
        ($value:expr, $expected_array:expr) => (
            assert_eq!(
                $value.into_bitfield(),
                $expected_array
            );
        )
    }

    macro_rules! test_from {
        ($value_type:ty, $array_len:expr, $array:expr, $expected_value:expr) => (
            assert_eq!(
                <$value_type as FromBitfield<[u8;$array_len]>>::from_bitfield($array),
                $expected_value
            );
        )
    }

    #[test]
    fn bool_test() {
        test_into!(
            false,
            [0;1]
        );
        test_into!(
            true,
            [1;1]
        );

        test_from!(
            bool, 1,
            [0;1], false
        );
        test_from!(
            bool, 1,
            [1;1], true
        );
        test_from!(
            bool, 1,
            [0b11111110;1], false
        );
        test_from!(
            bool, 1,
            [0b11111111;1], true
        );
    }

    #[test]
    fn u8_test() {
        test_into!(
            (0 as u8),
            [0;1]
        );
        test_into!(
            (1 as u8),
            [1;1]
        );
        test_into!(
            (0xFF as u8),
            [0xFF;1]
        );

        test_from!(
            u8, 1,
            [0;1], 0
        );
        test_from!(
            u8, 1,
            [1;1], 1
        );
        test_from!(
            u8, 1,
            [0xFF;1], 0xFF
        );
    }

    #[test]
    fn u16_test() {
        test_into!(
            (0 as u16),
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }
        );
        test_into!(
            (1 as u16),
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }
        );
        test_into!(
            (0xFF as u16),
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }
        );
        test_into!(
            (0xFF00 as u16),
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }
        );
        test_into!(
            (0xFFFF as u16),
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }
        );

        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }, 0
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }, 1
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }, 0xFF
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }, 0xFF00
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }, 0xFFFF
        );
    }
}<commit_msg>all test for u32<commit_after>#![no_std]

pub trait BitfieldRegister {
    type Data;
    const REGISTER_SIZE: usize;
    fn data(&self) -> & Self::Data;
}

pub trait FromBitfield<Array> {
    fn from_bitfield(array:Array) -> Self;
}

pub trait IntoBitfield<Array> {
    fn into_bitfield(self) -> Array;
}

// u8
impl FromBitfield<[u8;1]> for u8 {
    fn from_bitfield(array: [u8;1]) -> Self {
        return array[0];
    }
}

impl IntoBitfield<[u8;1]> for u8 {
    fn into_bitfield(self) -> [u8;1]{
        return [self;1];
    }
}

// u16
impl FromBitfield<[u8;2]> for u16 {
    fn from_bitfield(array: [u8;2]) -> Self {
        return
            (array[0] as u16) |
            (array[1] as u16) << 8;
    }
}

impl IntoBitfield<[u8;2]> for u16 {
    fn into_bitfield(self) -> [u8;2]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
        ];
    }
}

// u32 :3
impl IntoBitfield<[u8;3]> for u32 {
    fn into_bitfield(self) -> [u8;3]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
        ];
    }
}

impl FromBitfield<[u8;3]> for u32 {
    fn from_bitfield(array: [u8;3]) -> Self {
        return
            (array[0] as u32)      |
            (array[1] as u32) << 8 |
            (array[2] as u32) << 16;
    }
}

// u32 :4
impl IntoBitfield<[u8;4]> for u32 {
    fn into_bitfield(self) -> [u8;4]{
        return [
            (self & 0xFF) as u8,
            (self >> 8 & 0xFF) as u8,
            (self >> 16 & 0xFF) as u8,
            (self >> 24 & 0xFF) as u8
        ];
    }
}

impl FromBitfield<[u8;4]> for u32 {
    fn from_bitfield(array: [u8;4]) -> Self {
        return
            (array[0] as u32)       |
            (array[1] as u32) << 8  |
            (array[2] as u32) << 16 |
            (array[3] as u32) << 24;

    }
}

impl FromBitfield<[u8;1]> for bool {
    fn from_bitfield(array: [u8;1]) -> Self {
        return (array[0] & 1) != 0;
    }
}

impl IntoBitfield<[u8;1]> for bool {
    fn into_bitfield(self) -> [u8;1]{
        // If you cast a bool into an integer, true will be 1 and false will be 0.
        // https://doc.rust-lang.org/std/primitive.bool.html
        return [self as u8;1];
    }
}

mod tests {
    use super::{FromBitfield, IntoBitfield};

    macro_rules! test_into {
        ($value:expr, $expected_array:expr, $array_len:expr) => (
            let array: [u8;$array_len] = $value.into_bitfield();
            assert_eq!(
                array,
                $expected_array
            );
        )
    }

    macro_rules! test_from {
        ($value_type:ty, $array_len:expr, $array:expr, $expected_value:expr) => (
            assert_eq!(
                <$value_type as FromBitfield<[u8;$array_len]>>::from_bitfield($array),
                $expected_value
            );
        )
    }

    #[test]
    fn bool_test() {
        test_into!(
            false,
            [0;1], 1
        );
        test_from!(
            bool, 1,
            [0;1], false
        );

        test_into!(
            true,
            [1;1], 1
        );
        test_from!(
            bool, 1,
            [1;1], true
        );

        test_from!(
            bool, 1,
            [0b11111110;1], false
        );

        test_from!(
            bool, 1,
            [0b11111111;1], true
        );
    }

    #[test]
    fn u8_test() {
        test_into!(
            (0 as u8),
            [0;1], 1
        );
        test_from!(
            u8, 1,
            [0;1], 0
        );

        test_into!(
            (1 as u8),
            [1;1], 1
        );
        test_from!(
            u8, 1,
            [1;1], 1
        );

        test_into!(
            (0xFF as u8),
            [0xFF;1], 1
        );
        test_from!(
            u8, 1,
            [0xFF;1], 0xFF
        );
    }

    #[test]
    fn u16_test() {
        test_into!(
            (0 as u16),
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }, 2
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0x00u8]; X }, 0
        );

        test_into!(
            (1 as u16),
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }, 2
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x01u8, 0x00u8]; X }, 1
        );

        test_into!(
            (0xFF as u16),
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }, 2
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0x00u8]; X }, 0xFF
        );

        test_into!(
            (0xFF00 as u16),
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }, 2
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0x00u8, 0xFFu8]; X }, 0xFF00
        );

        test_into!(
            (0xFFFF as u16),
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }, 2
        );
        test_from!(
            u16, 2,
            { static X: [u8;2] = [0xFFu8, 0xFFu8]; X }, 0xFFFF
        );
    }

    #[test]
    fn u32_3_test() {
        test_into!(
            (0 as u32),
            { static X: [u8;3] = [0x00u8, 0x00u8, 0x00u8]; X }, 3
        );
        test_from!(
            u32, 3,
            { static X: [u8;3] = [0x00u8, 0x00u8, 0x00u8]; X }, 0
        );

        test_into!(
            (1 as u32),
            { static X: [u8;3] = [0x01u8, 0x00u8, 0x00u8]; X }, 3
        );
        test_from!(
            u32, 3,
            { static X: [u8;3] = [0x01u8, 0x00u8, 0x00u8]; X }, 1
        );

        test_into!(
            (0xFF as u32),
            { static X: [u8;3] = [0xFFu8, 0x00u8, 0x00u8]; X }, 3
        );
        test_from!(
            u32, 3,
            { static X: [u8;3] = [0xFFu8, 0x00u8, 0x00u8]; X }, 0xFF
        );

        test_into!(
            (0xFF0000 as u32),
            { static X: [u8;3] = [0x00u8, 0x00u8, 0xFFu8]; X }, 3
        );
        test_from!(
            u32, 3,
            { static X: [u8;3] = [0x00u8, 0x00u8, 0xFFu8]; X }, 0xFF0000
        );

        test_into!(
            (0xFFFFFF as u32),
            { static X: [u8;3] = [0xFFu8, 0xFFu8, 0xFFu8]; X }, 3
        );
        test_from!(
            u32, 3,
            { static X: [u8;3] = [0xFFu8, 0xFFu8, 0xFFu8]; X }, 0xFFFFFF
        );
    }

    #[test]
    fn u32_4_test() {
        test_into!(
            (0 as u32),
            { static X: [u8;4] = [0x00u8, 0x00u8, 0x00u8, 0x00u8]; X }, 4
        );
        test_from!(
            u32, 4,
            { static X: [u8;4] = [0x00u8, 0x00u8, 0x00u8, 0x00u8]; X }, 0
        );

        test_into!(
            (1 as u32),
            { static X: [u8;4] = [0x01u8, 0x00u8, 0x00u8, 0x00u8]; X }, 4
        );
        test_from!(
            u32, 4,
            { static X: [u8;4] = [0x01u8, 0x00u8, 0x00u8, 0x00u8]; X }, 1
        );

        test_into!(
            (0xFF as u32),
            { static X: [u8;4] = [0xFFu8, 0x00u8, 0x00u8, 0x00u8]; X }, 4
        );
        test_from!(
            u32, 4,
            { static X: [u8;4] = [0xFFu8, 0x00u8, 0x00u8, 0x00u8]; X }, 0xFF
        );

        test_into!(
            (0xFF000000 as u32),
            { static X: [u8;4] = [0x00u8, 0x00u8, 0x00u8, 0xFFu8]; X }, 4
        );
        test_from!(
            u32, 4,
            { static X: [u8;4] = [0x00u8, 0x00u8, 0x00u8, 0xFFu8]; X }, 0xFF000000
        );

        test_into!(
            (0xFFFFFFFF as u32),
            { static X: [u8;4] = [0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8]; X }, 4
        );
        test_from!(
            u32, 4,
            { static X: [u8;4] = [0xFFu8, 0xFFu8, 0xFFu8, 0xFFu8]; X }, 0xFFFFFFFF
        );
    }
}<|endoftext|>


<commit_before>// vim: tw=80
use proc_macro2::Span;
use quote::{ToTokens, format_ident, quote};
use syn::*;

use crate::mock_function::{self, MockFunction};

pub(crate) struct MockTrait {
    pub attrs: Vec<Attribute>,
    pub generics: Generics,
    pub methods: Vec<MockFunction>,
    pub name: Ident,
    structname: Ident,
}

impl MockTrait {
    pub fn name(&self) -> &Ident {
        &self.name
    }

    /// Create a new MockTrait
    ///
    /// # Arguments
    /// * `structname` - name of the struct that implements this trait
    /// * `trait_`  -    Mockable ItemTrait
    /// * `vis`     -   Visibility of the struct
    pub fn new(structname: &Ident, trait_: ItemTrait, vis: &Visibility) -> Self {
        let mut methods = Vec::new();
        for ti in trait_.items.into_iter() {
            if let TraitItem::Method(tim) = ti {
                let mf = mock_function::Builder::new(&tim.sig, &vis)
                    .attrs(&tim.attrs)
                    .levels(2)
                    .call_levels(0)
                    .struct_(structname)
                    .trait_(&trait_.ident)
                    .build();
                methods.push(mf);
            }
        }
        MockTrait {
            attrs: trait_.attrs,
            generics: trait_.generics,
            methods,
            name: trait_.ident,
            structname: structname.clone()
        }
    }

    /// Generate code for the expect_ method
    ///
    /// # Arguments
    ///
    /// * `modname`:    Name of the parent struct's private module
    // Supplying modname is an unfortunately hack.  Ideally MockTrait
    // wouldn't need to know that.
    pub fn trait_impl(&self, modname: &Ident) -> impl ToTokens {
        let (ig, tg, wc) = self.generics.split_for_impl();
        let ss_modname = format_ident!("{}_{}", &modname, self.name);
        let calls = self.methods.iter()
                .map(|meth| meth.call(None))
                .collect::<Vec<_>>();
        let expects = self.methods.iter()
                .map(|meth| meth.expect(&ss_modname))
                .collect::<Vec<_>>();
        let name = &self.name;
        let structname = &self.structname;
        quote!(
            impl #ig #name for #structname #tg #wc {
                #(#calls)*
            }
            impl #ig #structname #tg #wc {
                #(#expects)*
            }
        )
    }
}
<commit_msg>Support associated types in mock!<commit_after>// vim: tw=80
use proc_macro2::Span;
use quote::{ToTokens, format_ident, quote};
use syn::{
    *,
    spanned::Spanned
};

use crate::{
    mock_function::{self, MockFunction},
    compile_error
};

pub(crate) struct MockTrait {
    pub attrs: Vec<Attribute>,
    pub generics: Generics,
    pub methods: Vec<MockFunction>,
    pub name: Ident,
    structname: Ident,
    pub types: Vec<TraitItemType>
}

impl MockTrait {
    pub fn name(&self) -> &Ident {
        &self.name
    }

    /// Create a new MockTrait
    ///
    /// # Arguments
    /// * `structname` - name of the struct that implements this trait
    /// * `trait_`  -    Mockable ItemTrait
    /// * `vis`     -   Visibility of the struct
    pub fn new(structname: &Ident, trait_: ItemTrait, vis: &Visibility) -> Self {
        let mut methods = Vec::new();
        let mut types = Vec::new();
        for ti in trait_.items.into_iter() {
            match ti {
                TraitItem::Const(_) => {
                    // const items can easily be added by the user in a separate
                    // impl block
                },
                TraitItem::Method(tim) => {
                    let mf = mock_function::Builder::new(&tim.sig, &vis)
                        .attrs(&tim.attrs)
                        .levels(2)
                        .call_levels(0)
                        .struct_(structname)
                        .trait_(&trait_.ident)
                        .build();
                    methods.push(mf);
                },
                TraitItem::Type(tit) => {
                    types.push(tit);
                },
                _ => {
                    compile_error(ti.span(),
                    "This impl item is not yet supported by MockAll");
                }
            }
        }
        MockTrait {
            attrs: trait_.attrs,
            generics: trait_.generics,
            methods,
            name: trait_.ident,
            structname: structname.clone(),
            types
        }
    }

    /// Generate code for the expect_ method
    ///
    /// # Arguments
    ///
    /// * `modname`:    Name of the parent struct's private module
    // Supplying modname is an unfortunately hack.  Ideally MockTrait
    // wouldn't need to know that.
    pub fn trait_impl(&self, modname: &Ident) -> impl ToTokens {
        let (ig, tg, wc) = self.generics.split_for_impl();
        let ss_modname = format_ident!("{}_{}", &modname, self.name);
        let calls = self.methods.iter()
                .map(|meth| meth.call(None))
                .collect::<Vec<_>>();
        let expects = self.methods.iter()
                .map(|meth| meth.expect(&ss_modname))
                .collect::<Vec<_>>();
        let name = &self.name;
        let structname = &self.structname;
        let types = &self.types;
        quote!(
            impl #ig #name for #structname #tg #wc {
                #(#types)*
                #(#calls)*
            }
            impl #ig #structname #tg #wc {
                #(#expects)*
            }
        )
    }
}
<|endoftext|>


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

// Functions for dealing with stratis and device mapper names.

use std::fmt;
use std::fmt::Display;
use std::path::Path;

use devicemapper::{DmNameBuf, DmUuidBuf};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.to_simple_ref()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    Cache,
    /// The cache sub-device of the DM cache device.
    CacheSub,
    /// The meta sub-device of the DM cache device.
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("flex")                            4
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-flex-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 61"),
    )
}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-{}-thin-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"),
    )
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("thinpool")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 65 (66 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-thinpool-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 65"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 66"),
    )
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("physical")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-physical-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"),
    )
}

/// Validate a path for use as a Pool or Filesystem name.
pub fn validate_name(name: &str) -> StratisResult<()> {
    let name_path = Path::new(name);
    if name.contains('\u{0}') {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains NULL characters : {}", name),
        ));
    }
    if name_path.components().count() != 1 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is a path with 0 or more than 1 components : {}", name),
        ));
    }
    if name_path.is_absolute() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is an absolute path : {}", name),
        ));
    }
    if name == "." || name == ".." {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is . or .. : {}", name),
        ));
    }
    // Linux has a maximum filename length of 255 bytes
    if name.len() > 255 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name has more than 255 characters : {}", name),
        ));
    }

    if name.len() != name.trim().len() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains leading or trailing space : {}", name),
        ));
    }
    if name.chars().any(|c| c.is_control()) {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains control characters : {}", name),
        ));
    }
    Ok(())
}

#[cfg(test)]
mod tests {

    use engine::strat_engine::names::validate_name;

    #[test]
    pub fn test_validate_name() {
        assert!(validate_name(&'\u{0}'.to_string()).is_err());
        assert!(validate_name("./some").is_err());
        assert!(validate_name("../../root").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name("\u{1c}\u{7}").is_err());
        assert!(validate_name("./foo/bar.txt").is_err());
        assert!(validate_name(".").is_err());
        assert!(validate_name("..").is_err());
        assert!(validate_name("/dev/sdb").is_err());
        assert!(validate_name("").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name(" leading_space").is_err());
        assert!(validate_name("trailing_space ").is_err());
        assert!(validate_name("\u{0}leading_null").is_err());
        assert!(validate_name("trailing_null\u{0}").is_err());
        assert!(validate_name("middle\u{0}_null").is_err());
        assert!(validate_name("\u{0}multiple\u{0}_null\u{0}").is_err());
        assert!(validate_name(&"𐌏".repeat(64)).is_err());

        assert!(validate_name(&"𐌏".repeat(63)).is_ok());
        assert!(validate_name(&'\u{10fff8}'.to_string()).is_ok());
        assert!(validate_name("*< ? >").is_ok());
        assert!(validate_name("...").is_ok());
        assert!(validate_name("ok.name").is_ok());
        assert!(validate_name("ok name with spaces").is_ok());
        assert!(validate_name("\\\\").is_ok());
        assert!(validate_name("\u{211D}").is_ok());
        assert!(validate_name("☺").is_ok());
        assert!(validate_name("ok_name").is_ok());
    }
}
<commit_msg>Allow a test function to contain a lot of assertions<commit_after>// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// Functions for dealing with stratis and device mapper names.

use std::fmt;
use std::fmt::Display;
use std::path::Path;

use devicemapper::{DmNameBuf, DmUuidBuf};

use stratis::{ErrorEnum, StratisError, StratisResult};

use super::super::super::engine::{FilesystemUuid, PoolUuid};

const FORMAT_VERSION: u16 = 1;

#[derive(Clone, Copy)]
pub enum FlexRole {
    MetadataVolume,
    ThinData,
    ThinMeta,
    ThinMetaSpare,
}

impl Display for FlexRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            FlexRole::MetadataVolume => write!(f, "mdv"),
            FlexRole::ThinData => write!(f, "thindata"),
            FlexRole::ThinMeta => write!(f, "thinmeta"),
            FlexRole::ThinMetaSpare => write!(f, "thinmetaspare"),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinRole {
    Filesystem(FilesystemUuid),
}

impl Display for ThinRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinRole::Filesystem(uuid) => write!(f, "fs-{}", uuid.to_simple_ref()),
        }
    }
}

#[derive(Clone, Copy)]
pub enum ThinPoolRole {
    Pool,
}

impl Display for ThinPoolRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ThinPoolRole::Pool => write!(f, "pool"),
        }
    }
}

/// The various roles taken on by DM devices in the cache tier.
#[derive(Clone, Copy)]
pub enum CacheRole {
    /// The DM cache device, contains the other three devices.
    Cache,
    /// The cache sub-device of the DM cache device.
    CacheSub,
    /// The meta sub-device of the DM cache device.
    MetaSub,
    /// The origin sub-device of the DM cache device, holds the actual data.
    OriginSub,
}

impl Display for CacheRole {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CacheRole::Cache => write!(f, "cache"),
            CacheRole::CacheSub => write!(f, "cachesub"),
            CacheRole::MetaSub => write!(f, "metasub"),
            CacheRole::OriginSub => write!(f, "originsub"),
        }
    }
}

/// Format a name & uuid for the flex layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("flex")                            4
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(FlexRole))                     13
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_flex_ids(pool_uuid: PoolUuid, role: FlexRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-flex-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 61"),
    )
}

/// Format a name & uuid for the thin layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("thin")                            4
///             + num_dashes                             4
///             + len(pool uuid)                         32
///             + max(len(ThinRole))                     35
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 46 (47 for UUID)
pub fn format_thin_ids(pool_uuid: PoolUuid, role: ThinRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-{}-thin-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display length < 46"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display length < 47"),
    )
}

/// Format a name & uuid for the thin pool layer.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("thinpool")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(ThinPoolRole))                 4
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 65 (66 for UUID)
pub fn format_thinpool_ids(pool_uuid: PoolUuid, role: ThinPoolRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-thinpool-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 65"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 66"),
    )
}

/// Format a name & uuid for dm devices in the backstore.
///
/// Prerequisite: len(format!("{}", FORMAT_VERSION)
///             + len("stratis")                         7
///             + len("private")                         7
///             + len("physical")                        8
///             + num_dashes                             5
///             + len(pool uuid)                         32
///             + max(len(CacheRole))                    9
///             < 128 (129 for UUID)
///
/// which is equivalent to len(format!("{}", FORMAT_VERSION) < 60 (61 for UUID)
pub fn format_backstore_ids(pool_uuid: PoolUuid, role: CacheRole) -> (DmNameBuf, DmUuidBuf) {
    let value = format!(
        "stratis-{}-private-{}-physical-{}",
        FORMAT_VERSION,
        pool_uuid.to_simple_ref(),
        role
    );
    (
        DmNameBuf::new(value.clone()).expect("FORMAT_VERSION display_length < 60"),
        DmUuidBuf::new(value).expect("FORMAT_VERSION display_length < 61"),
    )
}

/// Validate a path for use as a Pool or Filesystem name.
pub fn validate_name(name: &str) -> StratisResult<()> {
    let name_path = Path::new(name);
    if name.contains('\u{0}') {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains NULL characters : {}", name),
        ));
    }
    if name_path.components().count() != 1 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is a path with 0 or more than 1 components : {}", name),
        ));
    }
    if name_path.is_absolute() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is an absolute path : {}", name),
        ));
    }
    if name == "." || name == ".." {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name is . or .. : {}", name),
        ));
    }
    // Linux has a maximum filename length of 255 bytes
    if name.len() > 255 {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name has more than 255 characters : {}", name),
        ));
    }

    if name.len() != name.trim().len() {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains leading or trailing space : {}", name),
        ));
    }
    if name.chars().any(|c| c.is_control()) {
        return Err(StratisError::Engine(
            ErrorEnum::Invalid,
            format!("Name contains control characters : {}", name),
        ));
    }
    Ok(())
}

#[cfg(test)]
mod tests {

    use engine::strat_engine::names::validate_name;

    #[test]
    #[allow(clippy::cyclomatic_complexity)]
    pub fn test_validate_name() {
        assert!(validate_name(&'\u{0}'.to_string()).is_err());
        assert!(validate_name("./some").is_err());
        assert!(validate_name("../../root").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name("\u{1c}\u{7}").is_err());
        assert!(validate_name("./foo/bar.txt").is_err());
        assert!(validate_name(".").is_err());
        assert!(validate_name("..").is_err());
        assert!(validate_name("/dev/sdb").is_err());
        assert!(validate_name("").is_err());
        assert!(validate_name("/").is_err());
        assert!(validate_name(" leading_space").is_err());
        assert!(validate_name("trailing_space ").is_err());
        assert!(validate_name("\u{0}leading_null").is_err());
        assert!(validate_name("trailing_null\u{0}").is_err());
        assert!(validate_name("middle\u{0}_null").is_err());
        assert!(validate_name("\u{0}multiple\u{0}_null\u{0}").is_err());
        assert!(validate_name(&"𐌏".repeat(64)).is_err());

        assert!(validate_name(&"𐌏".repeat(63)).is_ok());
        assert!(validate_name(&'\u{10fff8}'.to_string()).is_ok());
        assert!(validate_name("*< ? >").is_ok());
        assert!(validate_name("...").is_ok());
        assert!(validate_name("ok.name").is_ok());
        assert!(validate_name("ok name with spaces").is_ok());
        assert!(validate_name("\\\\").is_ok());
        assert!(validate_name("\u{211D}").is_ok());
        assert!(validate_name("☺").is_ok());
        assert!(validate_name("ok_name").is_ok());
    }
}
<|endoftext|>


<commit_before>use super::Projection;
use utils::cartesian_product;
use ndarray::{Axis, ArrayView, Array1, Array2};
use geometry::{Span, Space, RegularSpace};
use geometry::dimensions::{Continuous, Partitioned};

pub struct RBFNetwork {
    mu: Array2<f64>,
    gamma: Array1<f64>,
}

impl RBFNetwork {
    pub fn new(mu: Array2<f64>, gamma: Array1<f64>) -> Self {
        if mu.cols() != gamma.len() {
            panic!("Dimensions of mu ({:?}) and gamma ({:?}) must agree.", mu.shape(), gamma.shape());
        }

        RBFNetwork {
            mu: mu,
            gamma: gamma,
        }
    }

    pub fn from_space(input_space: RegularSpace<Partitioned>) -> Self {
        let n_features = match input_space.span() {
            Span::Finite(s) => s,
            _ =>
                panic!("`RBFNetwork` projection only supports partitioned \
                        input spaces.")
        };

        let centres = input_space.centres();
        let flat_combs =
            cartesian_product(&centres)
            .iter().cloned()
            .flat_map(|e| e).collect();

        let mu = Array2::from_shape_vec((n_features, input_space.dim()),
                                        flat_combs).unwrap();
        let gamma = input_space.iter().map(|d| {
            let s = d.partition_width();
            -1.0 / (s * s)
        }).collect();

        RBFNetwork::new(mu, gamma)
    }
}

impl Projection<RegularSpace<Continuous>> for RBFNetwork {
    fn project(&self, input: &Vec<f64>) -> Array1<f64> {
        let d = &self.mu - &ArrayView::from_shape((1, self.mu.cols()), input).unwrap();
        let e = (&d * &d * &self.gamma).mapv(|v| v.exp()).sum(Axis(1));
        let z = e.sum(Axis(0));

        e / z
    }

    fn dim(&self) -> usize {
        self.mu.rows()
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.mu == other.mu &&
            self.gamma == other.gamma &&
            self.dim() == other.dim()
    }
}
<commit_msg>Replace calls to .sum() with .sum_axis()<commit_after>use super::Projection;
use utils::cartesian_product;
use ndarray::{Axis, ArrayView, Array1, Array2};
use geometry::{Span, Space, RegularSpace};
use geometry::dimensions::{Continuous, Partitioned};

pub struct RBFNetwork {
    mu: Array2<f64>,
    gamma: Array1<f64>,
}

impl RBFNetwork {
    pub fn new(mu: Array2<f64>, gamma: Array1<f64>) -> Self {
        if mu.cols() != gamma.len() {
            panic!("Dimensions of mu ({:?}) and gamma ({:?}) must agree.", mu.shape(), gamma.shape());
        }

        RBFNetwork {
            mu: mu,
            gamma: gamma,
        }
    }

    pub fn from_space(input_space: RegularSpace<Partitioned>) -> Self {
        let n_features = match input_space.span() {
            Span::Finite(s) => s,
            _ =>
                panic!("`RBFNetwork` projection only supports partitioned \
                        input spaces.")
        };

        let centres = input_space.centres();
        let flat_combs =
            cartesian_product(&centres)
            .iter().cloned()
            .flat_map(|e| e).collect();

        let mu = Array2::from_shape_vec((n_features, input_space.dim()),
                                        flat_combs).unwrap();
        let gamma = input_space.iter().map(|d| {
            let s = d.partition_width();
            -1.0 / (s * s)
        }).collect();

        RBFNetwork::new(mu, gamma)
    }
}

impl Projection<RegularSpace<Continuous>> for RBFNetwork {
    fn project(&self, input: &Vec<f64>) -> Array1<f64> {
        let d = &self.mu - &ArrayView::from_shape((1, self.mu.cols()), input).unwrap();
        let e = (&d * &d * &self.gamma).mapv(|v| v.exp()).sum_axis(Axis(1));
        let z = e.sum_axis(Axis(0));

        e / z
    }

    fn dim(&self) -> usize {
        self.mu.rows()
    }

    fn equivalent(&self, other: &Self) -> bool {
        self.mu == other.mu &&
            self.gamma == other.gamma &&
            self.dim() == other.dim()
    }
}
<|endoftext|>


<commit_before>use types::CBytes;
use IntoBytes;
use frame::*;

#[derive(Debug)]
pub struct BodyReqAuthResponse {
    data: CBytes
}

impl BodyReqAuthResponse {
    pub fn new(data: CBytes) -> BodyReqAuthResponse {
        BodyReqAuthResponse { data: data }
    }
}

impl IntoBytes for BodyReqAuthResponse {
    fn into_cbytes(&self) -> Vec<u8> {
        self.data.into_cbytes()
    }
}

// Frame implementation related to BodyReqStartup

impl Frame {
    /// Creates new frame of type `AuthResponse`.
    pub fn new_req_auth_response(bytes: Vec<u8>) -> Frame {
        let version = Version::Request;
        let flag = Flag::Ignore;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::AuthResponse;
        let body = BodyReqAuthResponse::new(CBytes::new(bytes));

        Frame {
            version: version,
            flags: vec![flag],
            stream: stream,
            opcode: opcode,
            body: body.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![]
        }
    }
}
<commit_msg>Derive tests to frame_auth_response<commit_after>use types::CBytes;
use IntoBytes;
use frame::*;

#[derive(Debug)]
pub struct BodyReqAuthResponse {
    data: CBytes
}

impl BodyReqAuthResponse {
    pub fn new(data: CBytes) -> BodyReqAuthResponse {
        BodyReqAuthResponse { data: data }
    }
}

impl IntoBytes for BodyReqAuthResponse {
    fn into_cbytes(&self) -> Vec<u8> {
        self.data.into_cbytes()
    }
}

// Frame implementation related to BodyReqStartup

impl Frame {
    /// Creates new frame of type `AuthResponse`.
    pub fn new_req_auth_response(bytes: Vec<u8>) -> Frame {
        let version = Version::Request;
        let flag = Flag::Ignore;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::AuthResponse;
        let body = BodyReqAuthResponse::new(CBytes::new(bytes));

        Frame {
            version: version,
            flags: vec![flag],
            stream: stream,
            opcode: opcode,
            body: body.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![]
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use types::CBytes;
    use IntoBytes;
    use frame::*;

    #[test]
    fn body_req_auth_response() {
        let bytes = CBytes::new(vec![1, 2, 3]);
        let body = BodyReqAuthResponse::new(bytes);
        assert_eq!(body.into_cbytes(), vec![0, 0, 0, 3, 1, 2, 3]);
    }

    #[test]
    fn frame_body_req_auth_response() {
        let bytes = vec![1, 2, 3];
        let frame = Frame::new_req_auth_response(bytes);
        assert_eq!(frame.version, Version::Request);
        assert_eq!(frame.flags, vec![Flag::Ignore]);
        assert_eq!(frame.stream, 0);
        assert_eq!(frame.opcode, Opcode::AuthResponse);
        assert_eq!(frame.body, &[0, 0, 0, 3, 1, 2, 3]);
        assert_eq!(frame.tracing_id, None);
        assert_eq!(frame.warnings.len(), 0);
    }
}
<|endoftext|>


<commit_before>use std::fs::{File, OpenOptions};
use std::io::{Read, Write, Seek, SeekFrom};
use std::cell::RefCell;

trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; 8192],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; 8192],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        // println!("Writing {:02X} to {:04X}", v, address);
        // match address {
        //    0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000] = v,
        //    _ => unimplemented!(),
        //}
    }
}

#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

struct Mbc3 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: RefCell<File>,
    memory_mode: MemoryMode,

    ram_offset: usize,
    ram_enabled: bool,
}

impl Mbc3 {
    pub fn new(data: Vec<u8>) -> Mbc3 {
        let mut disk = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open("save.dat")
            .unwrap();

        let mut ram = vec![];
        disk.read_to_end(&mut ram);

        if ram.len() < 32768 {
            println!("Warning: invalid file size, blanking ram.");
            disk.seek(SeekFrom::Start(0));
            disk.write_all(&[0; 32768]);
        }

        Mbc3 {
            selected_bank: 1,
            data: data,
            offset: 0,
            ram: RefCell::new(disk),
            memory_mode: MemoryMode::C4_32,

            ram_offset: 0,
            ram_enabled: false,
        }
    }

    fn write_ram(&mut self, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        self.ram.borrow_mut().write_all(&[v]);
    }

    fn read_ram(&self, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        let mut buffer = [0; 1];
        self.ram.borrow_mut().read_exact(&mut buffer).unwrap();

        buffer[0]
    }
}

impl Mbc for Mbc3 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => self.read_ram(address),
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => panic!("Unrecognized value for RAM enablement."),
                }
            },
            0x2000 ... 0x3FFF => {
                // Any write to this area will enable the bank of memory contained in v
                // if 0 is selected we will select 1 because 0 is already available
                // statically in 0 0000 - 3FFF
                if v > 0 {
                    self.offset = ((v - 1) as usize) * 0x4000;
                } else {
                    self.offset = 0x0000;
                }
                // println!("Setting offset to {:06X}", self.offset);
            },
            0x4000 ... 0x5FFF => {
                match v {
                    0x00 => self.ram_offset = 0,
                    0x01 => self.ram_offset = 8192,
                    0x02 => self.ram_offset = 16384,
                    0x03 => self.ram_offset = 24576,
                    _ => unimplemented!(),
                }
            },
            0x6000 ... 0x7FFF => {
                println!("Attempt to write {:02X} to {:04X}", v, address);
                /* match v & 0x1 {
                    0x0 => self.memory_mode = MemoryMode::C16_8, // Memory mode 16_8,
                    0x1 => self.memory_mode = MemoryMode::C4_32,
                    _   => panic!(),
                }*/
            },
            0xA000 ... 0xBFFF => { self.write_ram(address, v); },
            _ => unimplemented!(),
        }
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 => Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 | 0x01 => Box::new(Mbc3::new(bytes)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}
<commit_msg>Don't write to stdout when enabling ram.<commit_after>use std::fs::{File, OpenOptions};
use std::io::{Read, Write, Seek, SeekFrom};
use std::cell::RefCell;

trait Mbc {
    fn read(&self, address: u16) -> u8;
    fn write(&mut self, address: u16, v: u8);
}

struct Mbc0 {
    data: Vec<u8>,
    ram: [u8; 8192],
}

impl Mbc0 {
    pub fn new(data: Vec<u8>) -> Mbc0 {
        Mbc0 {
            data: data,
            ram: [0; 8192],
        }
    }
}

impl Mbc for Mbc0 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x7FFF => self.data[address as usize],
            0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000],
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        // println!("Writing {:02X} to {:04X}", v, address);
        // match address {
        //    0xA000 ... 0xBFFF => self.ram[(address as usize) - 0xA000] = v,
        //    _ => unimplemented!(),
        //}
    }
}

#[derive(PartialEq, Eq)]
enum MemoryMode {
    C4_32,
    C16_8,
}

struct Mbc3 {
    selected_bank: usize,
    data: Vec<u8>,
    offset: usize,
    ram: RefCell<File>,
    memory_mode: MemoryMode,

    ram_offset: usize,
    ram_enabled: bool,
}

impl Mbc3 {
    pub fn new(data: Vec<u8>) -> Mbc3 {
        let mut disk = OpenOptions::new()
            .read(true)
            .write(true)
            .create(true)
            .open("save.dat")
            .unwrap();

        let mut ram = vec![];
        disk.read_to_end(&mut ram);

        if ram.len() < 32768 {
            println!("Warning: invalid file size, blanking ram.");
            disk.seek(SeekFrom::Start(0));
            disk.write_all(&[0; 32768]);
        }

        Mbc3 {
            selected_bank: 1,
            data: data,
            offset: 0,
            ram: RefCell::new(disk),
            memory_mode: MemoryMode::C4_32,

            ram_offset: 0,
            ram_enabled: false,
        }
    }

    fn write_ram(&mut self, address: u16, v: u8) {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        self.ram.borrow_mut().write_all(&[v]);
    }

    fn read_ram(&self, address: u16) -> u8 {
        if !self.ram_enabled {
            panic!("MBC3 RAM has not been enabled.");
        }

        let address = (address - 0xA000) as usize + self.ram_offset;
        self.ram.borrow_mut().seek(SeekFrom::Start(address as u64));
        let mut buffer = [0; 1];
        self.ram.borrow_mut().read_exact(&mut buffer).unwrap();

        buffer[0]
    }
}

impl Mbc for Mbc3 {
    fn read(&self, address: u16) -> u8 {
        match address {
            0x0000 ... 0x3FFF => self.data[address as usize],
            0x4000 ... 0x7FFF => self.data[address as usize + self.offset],
            0xA000 ... 0xBFFF => self.read_ram(address),
            _ => unimplemented!(),
        }
    }

    fn write(&mut self, address: u16, v: u8) {
        match address {
            0x0000 ... 0x1FFF => {
                match v {
                    0x00 => self.ram_enabled = false,
                    0x0A => self.ram_enabled = true,
                    _    => panic!("Unrecognized value for RAM enablement."),
                }
            },
            0x2000 ... 0x3FFF => {
                // Any write to this area will enable the bank of memory contained in v
                // if 0 is selected we will select 1 because 0 is already available
                // statically in 0 0000 - 3FFF
                if v > 0 {
                    self.offset = ((v - 1) as usize) * 0x4000;
                } else {
                    self.offset = 0x0000;
                }
                // println!("Setting offset to {:06X}", self.offset);
            },
            0x4000 ... 0x5FFF => {
                match v {
                    0x00 => self.ram_offset = 0,
                    0x01 => self.ram_offset = 8192,
                    0x02 => self.ram_offset = 16384,
                    0x03 => self.ram_offset = 24576,
                    _ => unimplemented!(),
                }
            },
            0x6000 ... 0x7FFF => {
                // println!("Attempt to write {:02X} to {:04X}", v, address);
                /* match v & 0x1 {
                    0x0 => self.memory_mode = MemoryMode::C16_8, // Memory mode 16_8,
                    0x1 => self.memory_mode = MemoryMode::C4_32,
                    _   => panic!(),
                }*/
            },
            0xA000 ... 0xBFFF => { self.write_ram(address, v); },
            _ => unimplemented!(),
        }
    }
}

pub struct MemoryController {
    controller: Box<Mbc>,
}

impl MemoryController {
    pub fn from_bytes(bytes: Vec<u8>) -> MemoryController {
        let controller = match bytes[0x147] {
            0x00 => Box::new(Mbc0::new(bytes)) as Box<Mbc>,
            0x0F | 0x10 | 0x11 | 0x12 | 0x13 | 0x01 => Box::new(Mbc3::new(bytes)) as Box<Mbc>,
            _ => {
                println!("Unrecognized type {:02X}", bytes[0x147]);
                panic!();
            }
        };

        MemoryController {
            controller: controller,
        }
    }

    pub fn read(&self, address: u16) -> u8 {
        self.controller.read(address)
    }

    pub fn write(&mut self, address: u16, v: u8) {
        self.controller.write(address, v);
    }
}
<|endoftext|>


<commit_before>//! A collection of methods that modify the background of the outputs.
use super::super::{Container, ContainerType, LayoutTree, TreeError,
                   MaybeBackground, IncompleteBackground};
use super::super::commands::CommandResult;

use uuid::Uuid;
use wayland_sys::server::wl_client;
use rustwlc::WlcView;
use rustwlc::wayland::wlc_view_get_wl_client;

impl LayoutTree {
    /// Attempts to attach the `bg` to the `outputs`.
    ///
    /// If any of them already have a background attached,
    pub fn attach_background(&mut self, bg: WlcView, output_id: Uuid)
                             -> Result<bool, TreeError> {
        match *self.lookup_mut(output_id)? {
            Container::Output { ref mut background, .. } => {
                match *background {
                    None => {
                        // The background wasn't expecting it
                        Ok(false)
                    }
                    Some(MaybeBackground::Incomplete(incomplete)) => {
                        let client: *mut wl_client;
                        unsafe {
                            client = wlc_view_get_wl_client(bg.0 as _) as _;
                        }
                        *background = Some(incomplete.build(client, bg));
                        Ok(match background.unwrap() {
                            MaybeBackground::Incomplete(_) => false,
                            MaybeBackground::Complete(_) => true,
                        })
                    },
                    _ => Ok(false)
                }
            },
            _ => Err(TreeError::UuidWrongType(output_id,
                                              vec![ContainerType::Output]))
        }
    }

    pub fn attach_incomplete_background(&mut self,
                                        bg: IncompleteBackground,
                                        output_id: Uuid) -> CommandResult {
        match *self.lookup_mut(output_id)? {
            Container::Output { ref mut background, .. } => {
                match *background {
                    None => {
                        *background = Some(bg.into());
                        Ok(())
                    },
                    Some(MaybeBackground::Complete(_)) => {
                        warn!("Tried to set background while one is still active");
                        warn!("This operation is not allowed, due to a bug with xwayland");
                        Ok(())
                    }
                    _ => {
                        warn!("Tried to set background while the other was still loading!");
                        Ok(())
                    }
                }
            },
            _ => Err(TreeError::UuidWrongType(output_id,
                                              vec![ContainerType::Output]))
        }
    }
}
<commit_msg>Fixed warnings<commit_after>//! A collection of methods that modify the background of the outputs.
use super::super::{Container, ContainerType, LayoutTree, TreeError,
                   MaybeBackground, IncompleteBackground};
use super::super::commands::CommandResult;

use uuid::Uuid;
use wayland_sys::server::wl_client;
use rustwlc::WlcView;
use rustwlc::wayland::wlc_view_get_wl_client;

impl LayoutTree {
    /// Attempts to attach the `bg` to the `outputs`.
    ///
    /// If any of them already have a background attached,
    pub fn attach_background(&mut self, bg: WlcView, output_id: Uuid)
                             -> Result<bool, TreeError> {
        match *self.lookup_mut(output_id)? {
            Container::Output { ref mut background, .. } => {
                match *background {
                    None => {
                        // The background wasn't expecting it
                        Ok(false)
                    }
                    Some(MaybeBackground::Incomplete(incomplete)) => {
                        let client: *mut wl_client;
                        unsafe {
                            client = wlc_view_get_wl_client(bg.0 as _) as _;
                        }
                        *background = Some(incomplete.build(client, bg));
                        Ok(match background.unwrap() {
                            MaybeBackground::Incomplete(_) => false,
                            MaybeBackground::Complete(_) => true,
                        })
                    },
                    _ => Ok(false)
                }
            },
            _ => Err(TreeError::UuidWrongType(output_id,
                                              vec![ContainerType::Output]))
        }
    }

    pub fn attach_incomplete_background(&mut self,
                                        bg: IncompleteBackground,
                                        output_id: Uuid) -> CommandResult {
        match *self.lookup_mut(output_id)? {
            Container::Output { ref mut background, .. } => {
                match *background {
                    None => {
                        *background = Some(bg.into());
                        Ok(())
                    },
                    Some(MaybeBackground::Complete(complete)) => {
                        warn!("Tried to set background while one is still active {:?}", complete);
                        warn!("This operation is not allowed, due to a bug with xwayland");
                        Ok(())
                    }
                    _ => {
                        warn!("Tried to set background while the other was still loading!");
                        Ok(())
                    }
                }
            },
            _ => Err(TreeError::UuidWrongType(output_id,
                                              vec![ContainerType::Output]))
        }
    }
}
<|endoftext|>