<commit_before>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate cortex;
extern crate pericortex;

use cortex::backend::{Backend, TEST_DB_ADDRESS};
use cortex::data::{Corpus,Service, Task, TaskStatus};
use cortex::manager::{TaskManager};
use pericortex::worker::{TexToHtmlWorker, Worker};
use cortex::importer::Importer;
use std::thread;
use std::str;
use std::process::Command;

#[test]
fn mock_tex_to_html() {
  // Check if we have latexmlc installed, skip otherwise:
  let which_result = Command::new("which").arg("latexmlc").output().unwrap().stdout;
  let latexmlc_path = str::from_utf8(&which_result).unwrap();
  if latexmlc_path.is_empty() {
    println!("latexmlc not installed, skipping test");
    return assert!(true);
  }
  // Initialize a corpus, import a single task, and enable a service on it
  let test_backend = Backend::testdb();
  assert!(test_backend.setup_task_tables().is_ok());

  let mock_corpus = test_backend.add(
    Corpus {
      id : None,
      name : "mock round-trip corpus".to_string(),
      path : "tests/data/".to_string(),
      complex : true,
    }).unwrap();
  let tex_to_html_service = test_backend.add(
    Service {
      id : None,
      name : "tex_to_html".to_string(),
      version : 0.1,
      inputformat : "tex".to_string(),
      outputformat : "html".to_string(),
      inputconverter : Some("import".to_string()),
      complex : true
    }).unwrap();
  let mut abs_path = Importer::cwd();
  abs_path.push("tests/data/1206.5501/1206.5501.zip");
  let abs_entry = abs_path.to_str().unwrap().to_string();
  test_backend.add(
    Task {
      id : None,
      entry : abs_entry.clone(),
      serviceid : 2, // Import service always has id 2
      corpusid : mock_corpus.id.unwrap().clone(),
      status : TaskStatus::NoProblem.raw()
    }).unwrap();
  let conversion_task = Task {
      id : None,
      entry : abs_entry.clone(),
      serviceid : tex_to_html_service.id.unwrap().clone(),
      corpusid : mock_corpus.id.unwrap().clone(),
      status : TaskStatus::TODO.raw()
    };
  test_backend.add(conversion_task.clone()).unwrap();

  // Start up a ventilator/sink pair
  thread::spawn(move || {
    let manager = TaskManager {
      source_port : 5555,
      result_port : 5556,
      queue_size : 100000,
      message_size : 100,
      backend_address : TEST_DB_ADDRESS.clone().to_string()
    };
    assert!(manager.start().is_ok());
  });
  // Start up an tex to html worker
  let worker = TexToHtmlWorker::default();
  // Perform a single echo task
  assert!(worker.start(Some(1)).is_ok());
  // Check round-trip success
  let finished_task = test_backend.sync(&conversion_task).unwrap();
  println!("Finished: {:?}", finished_task);
  // Wait for the finisher to persist to DB
  thread::sleep_ms(3001); // TODO: Can this be deterministic? Join?
  // This particular test finishes with an Error with the current LaTeXML (needs cmp.sty).
  assert!(finished_task.status == TaskStatus::Error.raw())
}<commit_msg>why was the sleep placed in such a wrong place? fix.<commit_after>// Copyright 2015 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.
extern crate cortex;
extern crate pericortex;

use cortex::backend::{Backend, TEST_DB_ADDRESS};
use cortex::data::{Corpus,Service, Task, TaskStatus};
use cortex::manager::{TaskManager};
use pericortex::worker::{TexToHtmlWorker, Worker};
use cortex::importer::Importer;
use std::thread;
use std::str;
use std::process::Command;

#[test]
fn mock_tex_to_html() {
  // Check if we have latexmlc installed, skip otherwise:
  let which_result = Command::new("which").arg("latexmlc").output().unwrap().stdout;
  let latexmlc_path = str::from_utf8(&which_result).unwrap();
  if latexmlc_path.is_empty() {
    println!("latexmlc not installed, skipping test");
    return assert!(true);
  }
  // Initialize a corpus, import a single task, and enable a service on it
  let test_backend = Backend::testdb();
  assert!(test_backend.setup_task_tables().is_ok());

  let mock_corpus = test_backend.add(
    Corpus {
      id : None,
      name : "mock round-trip corpus".to_string(),
      path : "tests/data/".to_string(),
      complex : true,
    }).unwrap();
  let tex_to_html_service = test_backend.add(
    Service {
      id : None,
      name : "tex_to_html".to_string(),
      version : 0.1,
      inputformat : "tex".to_string(),
      outputformat : "html".to_string(),
      inputconverter : Some("import".to_string()),
      complex : true
    }).unwrap();
  let mut abs_path = Importer::cwd();
  abs_path.push("tests/data/1206.5501/1206.5501.zip");
  let abs_entry = abs_path.to_str().unwrap().to_string();
  test_backend.add(
    Task {
      id : None,
      entry : abs_entry.clone(),
      serviceid : 2, // Import service always has id 2
      corpusid : mock_corpus.id.unwrap().clone(),
      status : TaskStatus::NoProblem.raw()
    }).unwrap();
  let conversion_task = Task {
      id : None,
      entry : abs_entry.clone(),
      serviceid : tex_to_html_service.id.unwrap().clone(),
      corpusid : mock_corpus.id.unwrap().clone(),
      status : TaskStatus::TODO.raw()
    };
  test_backend.add(conversion_task.clone()).unwrap();

  // Start up a ventilator/sink pair
  thread::spawn(move || {
    let manager = TaskManager {
      source_port : 5555,
      result_port : 5556,
      queue_size : 100000,
      message_size : 100,
      backend_address : TEST_DB_ADDRESS.clone().to_string()
    };
    assert!(manager.start().is_ok());
  });
  // Start up an tex to html worker
  let worker = TexToHtmlWorker::default();
  // Perform a single echo task
  assert!(worker.start(Some(1)).is_ok());
  // Wait for the finisher to persist to DB
  thread::sleep_ms(2001); // TODO: Can this be deterministic? Join?
  // Check round-trip success
  let finished_task = test_backend.sync(&conversion_task).unwrap();
  println!("Finished: {:?}", finished_task);
  // This particular test finishes with an Error with the current LaTeXML (needs cmp.sty).
  assert!(finished_task.status == TaskStatus::Error.raw())
}<|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/. */

//! Types used to report parsing errors.

use cssparser::{Parser, SourcePosition};
use log;

pub trait ParseErrorReporter {
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str);
    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync>;
}

pub struct StdoutErrorReporter;
impl ParseErrorReporter for StdoutErrorReporter {
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str) {
         if log_enabled!(log::LogLevel::Info) {
             let location = input.source_location(position);
             info!("{}:{} {}", location.line, location.column, message)
         }
    }

    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
        Box::new(StdoutErrorReporter)
    }
}
<commit_msg>style: Document the error_reporting module.<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/. */

//! Types used to report parsing errors.

#![deny(missing_docs)]

use cssparser::{Parser, SourcePosition};
use log;

/// A generic trait for an error reporter.
pub trait ParseErrorReporter {
    /// Called the style engine detects an error.
    ///
    /// Returns the current input being parsed, the source position it was
    /// reported from, and a message.
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str);
    /// Clone this error reporter.
    ///
    /// TODO(emilio): I'm pretty sure all the box shenanigans can go away.
    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync>;
}

/// An error reporter that reports the errors to the `info` log channel.
///
/// TODO(emilio): The name of this reporter is a lie, and should be renamed!
pub struct StdoutErrorReporter;
impl ParseErrorReporter for StdoutErrorReporter {
    fn report_error(&self, input: &mut Parser, position: SourcePosition, message: &str) {
         if log_enabled!(log::LogLevel::Info) {
             let location = input.source_location(position);
             info!("{}:{} {}", location.line, location.column, message)
         }
    }

    fn clone(&self) -> Box<ParseErrorReporter + Send + Sync> {
        Box::new(StdoutErrorReporter)
    }
}
<|endoftext|>


<commit_before>//! # Global Descriptor Table (GDT) manager module
//!
//! ## References
//! - [OSDev GDT](http://wiki.osdev.org/Global_Descriptor_Table)

use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;

pub struct Gdt {
    table: [u64; 9],
    next_free: usize,
}

impl Gdt {
    pub fn new() -> Gdt {
        Gdt {
            table: [0; 9],
            next_free: 1
        }
    }

    /// Add a new entry to the GDT
    pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
    }

    /// Add a new entry to the GDT
    pub fn add_entry_user(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        let new_seg = SegmentSelector::new(index as u16, PrivilegeLevel::Ring3);
        new_seg
    }

    /// This is used to control the number of entries on the GDT table.
    fn push(&mut self, value: u64) -> usize {
        if self.next_free < self.table.len() {
            let index = self.next_free;
            self.table[index] = value;
            self.next_free += 1;
            index
        } else {
            panic!("GDT full");
        }
    }

    /// Loads the GDT table into memory.
    pub fn load(&'static self) {
        use x86_64::instructions::tables::{DescriptorTablePointer, lgdt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self.table.as_ptr() as u64,
            limit: (self.table.len() * size_of::<u64>() - 1) as u16,
        };

        unsafe { lgdt(&ptr) };
    }
}

/// Represents a descriptor
pub enum Descriptor {
    UserSegment(u64),
    SystemSegment(u64, u64),
}

impl Descriptor {
    /// Creates a kernel mode segment
    pub fn kernel_code_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    pub fn kernel_data_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates a segment for the TLS
    pub fn thread_local_segment(offset: usize) -> Descriptor {
        use bit_field::BitField;

        // set the descriptor flags
        let flags = USER_SEGMENT | PRESENT | LONG_MODE;

        // get the bytes
        let mut bits = flags.bits();

        // set the offset
        let off = offset as u64;
        bits.set_bits(16..40, off.get_bits(0..24));
        bits.set_bits(56..64, off.get_bits(24..32));

        Descriptor::UserSegment(bits)
    }

    /// Create a new TSS segment
    ///
    /// ## Parameters
    ///
    /// * `tss` - Task state segment
    pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
        use core::mem::size_of;
        use bit_field::BitField;

        let ptr = tss as *const _ as u64;

        let mut low = PRESENT.bits();
        // base
        low.set_bits(16..40, ptr.get_bits(0..24));
        low.set_bits(56..64, ptr.get_bits(24..32));
        // limit (the `-1` in needed since the bound is inclusive)
        low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
        // type (0b1001 = available 64-bit tss)
        low.set_bits(40..44, 0b1001);

        let mut high = 0;
        high.set_bits(0..32, ptr.get_bits(32..64));

        Descriptor::SystemSegment(low, high)
    }

    /// Creates an user mode code segment
    pub fn user_code_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE | RING_3;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates an user mode data segment
    pub fn user_data_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates an user mode TLS segment
    pub fn user_thread_local_segment(offset: usize) -> Descriptor {
        use bit_field::BitField;

        // set the descriptor flags
        let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;

        // get the bytes
        let mut bits = flags.bits();

        // set the offset
        let off = offset as u64;
        bits.set_bits(16..40, off.get_bits(0..24));
        bits.set_bits(56..64, off.get_bits(24..32));

        Descriptor::UserSegment(bits)
    }
}

bitflags! {
    flags DescriptorFlags: u64 {
        const CONFORMING        = 1 << 42,
        const EXECUTABLE        = 1 << 43,
        const USER_SEGMENT      = 1 << 44,
        const RING_3            = 3 << 5,
        const PRESENT           = 1 << 47,
        const LONG_MODE         = 1 << 53,
    }
}
<commit_msg>Fix Ring 3 bit<commit_after>//! # Global Descriptor Table (GDT) manager module
//!
//! ## References
//! - [OSDev GDT](http://wiki.osdev.org/Global_Descriptor_Table)

use x86_64::structures::tss::TaskStateSegment;
use x86_64::structures::gdt::SegmentSelector;
use x86_64::PrivilegeLevel;

pub struct Gdt {
    table: [u64; 9],
    next_free: usize,
}

impl Gdt {
    pub fn new() -> Gdt {
        Gdt {
            table: [0; 9],
            next_free: 1
        }
    }

    /// Add a new entry to the GDT
    pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
    }

    /// Add a new entry to the GDT
    pub fn add_entry_user(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        let new_seg = SegmentSelector::new(index as u16, PrivilegeLevel::Ring3);
        new_seg
    }

    /// This is used to control the number of entries on the GDT table.
    fn push(&mut self, value: u64) -> usize {
        if self.next_free < self.table.len() {
            let index = self.next_free;
            self.table[index] = value;
            self.next_free += 1;
            index
        } else {
            panic!("GDT full");
        }
    }

    /// Loads the GDT table into memory.
    pub fn load(&'static self) {
        use x86_64::instructions::tables::{DescriptorTablePointer, lgdt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self.table.as_ptr() as u64,
            limit: (self.table.len() * size_of::<u64>() - 1) as u16,
        };

        unsafe { lgdt(&ptr) };
    }
}

/// Represents a descriptor
pub enum Descriptor {
    UserSegment(u64),
    SystemSegment(u64, u64),
}

impl Descriptor {
    /// Creates a kernel mode segment
    pub fn kernel_code_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    pub fn kernel_data_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates a segment for the TLS
    pub fn thread_local_segment(offset: usize) -> Descriptor {
        use bit_field::BitField;

        // set the descriptor flags
        let flags = USER_SEGMENT | PRESENT | LONG_MODE;

        // get the bytes
        let mut bits = flags.bits();

        // set the offset
        let off = offset as u64;
        bits.set_bits(16..40, off.get_bits(0..24));
        bits.set_bits(56..64, off.get_bits(24..32));

        Descriptor::UserSegment(bits)
    }

    /// Create a new TSS segment
    ///
    /// ## Parameters
    ///
    /// * `tss` - Task state segment
    pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
        use core::mem::size_of;
        use bit_field::BitField;

        let ptr = tss as *const _ as u64;

        let mut low = PRESENT.bits();
        // base
        low.set_bits(16..40, ptr.get_bits(0..24));
        low.set_bits(56..64, ptr.get_bits(24..32));
        // limit (the `-1` in needed since the bound is inclusive)
        low.set_bits(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
        // type (0b1001 = available 64-bit tss)
        low.set_bits(40..44, 0b1001);

        let mut high = 0;
        high.set_bits(0..32, ptr.get_bits(32..64));

        Descriptor::SystemSegment(low, high)
    }

    /// Creates an user mode code segment
    pub fn user_code_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE | RING_3;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates an user mode data segment
    pub fn user_data_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;
        Descriptor::UserSegment(flags.bits())
    }

    /// Creates an user mode TLS segment
    pub fn user_thread_local_segment(offset: usize) -> Descriptor {
        use bit_field::BitField;

        // set the descriptor flags
        let flags = USER_SEGMENT | PRESENT | LONG_MODE | RING_3;

        // get the bytes
        let mut bits = flags.bits();

        // set the offset
        let off = offset as u64;
        bits.set_bits(16..40, off.get_bits(0..24));
        bits.set_bits(56..64, off.get_bits(24..32));

        Descriptor::UserSegment(bits)
    }
}

bitflags! {
    flags DescriptorFlags: u64 {
        const CONFORMING        = 1 << 42,
        const EXECUTABLE        = 1 << 43,
        const USER_SEGMENT      = 1 << 44,
        const RING_3            = 3 << 45,
        const PRESENT           = 1 << 47,
        const LONG_MODE         = 1 << 53,
    }
}
<|endoftext|>


<commit_before>use {compiler, spirv, ErrorCode};
use bindings::root::*;
use std::ptr;
use std::marker::PhantomData;

/// A HLSL target.
#[derive(Debug, Clone)]
pub enum Target {}

impl spirv::Target for Target {
    type Data = ();
}

/// A HLSL shader model version.
#[allow(non_snake_case, non_camel_case_types)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum ShaderModel {
    V3_0,
    V4_0,
    V4_0L9_0,
    V4_0L9_1,
    V4_0L9_3,
    V4_1,
    V5_0,
    V5_1,
    V6_0,
}

#[allow(non_snake_case, non_camel_case_types)]
impl ShaderModel {
    fn as_raw(&self) -> i32 {
        match *self {
            ShaderModel::V3_0 => 30,
            ShaderModel::V4_0 => 40,
            ShaderModel::V4_0L9_0 => 40,
            ShaderModel::V4_0L9_1 => 40,
            ShaderModel::V4_0L9_3 => 40,
            ShaderModel::V4_1 => 41,
            ShaderModel::V5_0 => 50,
            ShaderModel::V5_1 => 51,
            ShaderModel::V6_0 => 60,
        }
    }
}

#[derive(Debug, Clone)]
pub struct CompilerVertexOptions {
    pub invert_y: bool,
    pub transform_clip_space: bool,
}

impl Default for CompilerVertexOptions {
    fn default() -> CompilerVertexOptions {
        CompilerVertexOptions {
            invert_y: false,
            transform_clip_space: false,
        }
    }
}

/// HLSL compiler options.
#[derive(Debug, Clone)]
pub struct CompilerOptions {
    pub shader_model: ShaderModel,
    pub vertex: CompilerVertexOptions,
}

impl CompilerOptions {
    fn as_raw(&self) -> ScHlslCompilerOptions {
        ScHlslCompilerOptions {
            shader_model: self.shader_model.as_raw(),
            vertex_invert_y: self.vertex.invert_y,
            vertex_transform_clip_space: self.vertex.transform_clip_space,
        }
    }
}

impl Default for CompilerOptions {
    fn default() -> CompilerOptions {
        CompilerOptions {
            shader_model: ShaderModel::V3_0,
            vertex: CompilerVertexOptions::default(),
        }
    }
}

impl spirv::Parse<Target> for spirv::Ast<Target> {
    fn parse(module: &spirv::Module) -> Result<Self, ErrorCode> {
        let compiler = {
            let mut compiler = ptr::null_mut();
            unsafe {
                check!(sc_internal_compiler_hlsl_new(
                    &mut compiler,
                    module.words.as_ptr() as *const u32,
                    module.words.len() as usize,
                ));
            }

            compiler::Compiler {
                sc_compiler: compiler,
                target_data: (),
            }
        };

        Ok(spirv::Ast {
            compiler,
            target_type: PhantomData,
        })
    }
}

impl spirv::Compile<Target> for spirv::Ast<Target> {
    type CompilerOptions = CompilerOptions;

    /// Set HLSL compiler specific compilation settings.
    fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> {
        let raw_options = options.as_raw();
        unsafe {
            check!(sc_internal_compiler_hlsl_set_options(
                self.compiler.sc_compiler,
                &raw_options,
            ));
        }

        Ok(())
    }

    /// Generate HLSL shader from the AST.
    fn compile(&self) -> Result<String, ErrorCode> {
        self.compiler.compile()
    }
}
<commit_msg>Simplify `as_raw`<commit_after>use {compiler, spirv, ErrorCode};
use bindings::root::*;
use std::ptr;
use std::marker::PhantomData;

/// A HLSL target.
#[derive(Debug, Clone)]
pub enum Target {}

impl spirv::Target for Target {
    type Data = ();
}

/// A HLSL shader model version.
#[allow(non_snake_case, non_camel_case_types)]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum ShaderModel {
    V3_0,
    V4_0,
    V4_0L9_0,
    V4_0L9_1,
    V4_0L9_3,
    V4_1,
    V5_0,
    V5_1,
    V6_0,
}

#[allow(non_snake_case, non_camel_case_types)]
impl ShaderModel {
    fn as_raw(&self) -> i32 {
        use self::ShaderModel::*;
        match *self {
            V3_0 => 30,
            V4_0 => 40,
            V4_0L9_0 => 40,
            V4_0L9_1 => 40,
            V4_0L9_3 => 40,
            V4_1 => 41,
            V5_0 => 50,
            V5_1 => 51,
            V6_0 => 60,
        }
    }
}

#[derive(Debug, Clone)]
pub struct CompilerVertexOptions {
    pub invert_y: bool,
    pub transform_clip_space: bool,
}

impl Default for CompilerVertexOptions {
    fn default() -> CompilerVertexOptions {
        CompilerVertexOptions {
            invert_y: false,
            transform_clip_space: false,
        }
    }
}

/// HLSL compiler options.
#[derive(Debug, Clone)]
pub struct CompilerOptions {
    pub shader_model: ShaderModel,
    pub vertex: CompilerVertexOptions,
}

impl CompilerOptions {
    fn as_raw(&self) -> ScHlslCompilerOptions {
        ScHlslCompilerOptions {
            shader_model: self.shader_model.as_raw(),
            vertex_invert_y: self.vertex.invert_y,
            vertex_transform_clip_space: self.vertex.transform_clip_space,
        }
    }
}

impl Default for CompilerOptions {
    fn default() -> CompilerOptions {
        CompilerOptions {
            shader_model: ShaderModel::V3_0,
            vertex: CompilerVertexOptions::default(),
        }
    }
}

impl spirv::Parse<Target> for spirv::Ast<Target> {
    fn parse(module: &spirv::Module) -> Result<Self, ErrorCode> {
        let compiler = {
            let mut compiler = ptr::null_mut();
            unsafe {
                check!(sc_internal_compiler_hlsl_new(
                    &mut compiler,
                    module.words.as_ptr() as *const u32,
                    module.words.len() as usize,
                ));
            }

            compiler::Compiler {
                sc_compiler: compiler,
                target_data: (),
            }
        };

        Ok(spirv::Ast {
            compiler,
            target_type: PhantomData,
        })
    }
}

impl spirv::Compile<Target> for spirv::Ast<Target> {
    type CompilerOptions = CompilerOptions;

    /// Set HLSL compiler specific compilation settings.
    fn set_compiler_options(&mut self, options: &CompilerOptions) -> Result<(), ErrorCode> {
        let raw_options = options.as_raw();
        unsafe {
            check!(sc_internal_compiler_hlsl_set_options(
                self.compiler.sc_compiler,
                &raw_options,
            ));
        }

        Ok(())
    }

    /// Generate HLSL shader from the AST.
    fn compile(&self) -> Result<String, ErrorCode> {
        self.compiler.compile()
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::interrupter::{Error as InterrupterError, Interrupter};
use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
use super::usb_hub::{Error as HubError, UsbPort};
use super::xhci_abi::{
    AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
    TrbCompletionCode, TrbType,
};
use super::xhci_regs::MAX_INTERRUPTER;
use bit_field::Error as BitFieldError;
use std::cmp::min;
use std::fmt::{self, Display};
use std::mem;
use std::sync::{Arc, Weak};
use sync::Mutex;
use sys_util::{error, Error as SysError, EventFd, GuestMemory};
use usb_util::types::UsbRequestSetup;
use usb_util::usb_transfer::TransferStatus;

#[derive(Debug)]
pub enum Error {
    TrbType(BitFieldError),
    CastTrb(TrbError),
    TransferLength(TrbError),
    BadTrbType(TrbType),
    WriteCompletionEvent(SysError),
    CreateBuffer(BufferError),
    DetachPort(HubError),
    SendInterrupt(InterrupterError),
    SubmitTransfer,
}

type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            TrbType(e) => write!(f, "cannot get trb type: {}", e),
            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
            TransferLength(e) => write!(f, "cannot get transfer length: {}", e),
            BadTrbType(t) => write!(f, "unexpected trb type: {:?}", t),
            WriteCompletionEvent(e) => write!(f, "cannot write completion event: {}", e),
            CreateBuffer(e) => write!(f, "cannot create transfer buffer: {}", e),
            DetachPort(e) => write!(f, "cannot detach from port: {}", e),
            SendInterrupt(e) => write!(f, "cannot send interrupter: {}", e),
            SubmitTransfer => write!(f, "failed to submit transfer to backend"),
        }
    }
}

/// Type of usb endpoints.
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum TransferDirection {
    In,
    Out,
    Control,
}

/// Current state of xhci transfer.
pub enum XhciTransferState {
    Created,
    /// When transfer is submitted, it will contain a transfer callback, which should be invoked
    /// when the transfer is cancelled.
    Submitted {
        cancel_callback: Box<dyn FnMut() + Send>,
    },
    Cancelling,
    Cancelled,
    Completed,
}

impl XhciTransferState {
    /// Try to cancel this transfer, if it's possible.
    pub fn try_cancel(&mut self) {
        match mem::replace(self, XhciTransferState::Created) {
            XhciTransferState::Submitted {
                mut cancel_callback,
            } => {
                *self = XhciTransferState::Cancelling;
                cancel_callback();
            }
            XhciTransferState::Cancelling => {
                error!("Another cancellation is already issued.");
            }
            _ => {
                *self = XhciTransferState::Cancelled;
            }
        }
    }
}

/// Type of a transfer received handled by transfer ring.
pub enum XhciTransferType {
    // Normal means bulk transfer or interrupt transfer, depending on endpoint type.
    // See spec 4.11.2.1.
    Normal(ScatterGatherBuffer),
    // See usb spec for setup stage, data stage and status stage,
    // see xHCI spec 4.11.2.2 for corresponding trbs.
    SetupStage(UsbRequestSetup),
    DataStage(ScatterGatherBuffer),
    StatusStage,
    // See xHCI spec 4.11.2.3.
    Isochronous(ScatterGatherBuffer),
    // See xHCI spec 6.4.1.4.
    Noop,
}

impl XhciTransferType {
    /// Analyze transfer descriptor and return transfer type.
    pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
        // We can figure out transfer type from the first trb.
        // See transfer descriptor description in xhci spec for more details.
        match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
            TrbType::Normal => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::Normal(buffer))
            }
            TrbType::SetupStage => {
                let trb = td[0].trb.cast::<SetupStageTrb>().map_err(Error::CastTrb)?;
                Ok(XhciTransferType::SetupStage(UsbRequestSetup::new(
                    trb.get_request_type(),
                    trb.get_request(),
                    trb.get_value(),
                    trb.get_index(),
                    trb.get_length(),
                )))
            }
            TrbType::DataStage => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::DataStage(buffer))
            }
            TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
            TrbType::Isoch => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::Isochronous(buffer))
            }
            TrbType::Noop => Ok(XhciTransferType::Noop),
            t => Err(Error::BadTrbType(t)),
        }
    }
}

/// Xhci Transfer manager holds reference to all ongoing transfers. Can cancel them all if
/// needed.
#[derive(Clone)]
pub struct XhciTransferManager {
    transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
}

impl XhciTransferManager {
    /// Create a new manager.
    pub fn new() -> XhciTransferManager {
        XhciTransferManager {
            transfers: Arc::new(Mutex::new(Vec::new())),
        }
    }

    /// Build a new XhciTransfer. Endpoint id is the id in xHCI device slot.
    pub fn create_transfer(
        &self,
        mem: GuestMemory,
        port: Arc<UsbPort>,
        interrupter: Arc<Mutex<Interrupter>>,
        slot_id: u8,
        endpoint_id: u8,
        transfer_trbs: TransferDescriptor,
        completion_event: EventFd,
    ) -> XhciTransfer {
        assert!(!transfer_trbs.is_empty());
        let transfer_dir = {
            if endpoint_id == 0 {
                TransferDirection::Control
            } else if (endpoint_id % 2) == 0 {
                TransferDirection::Out
            } else {
                TransferDirection::In
            }
        };
        let t = XhciTransfer {
            manager: self.clone(),
            state: Arc::new(Mutex::new(XhciTransferState::Created)),
            mem,
            port,
            interrupter,
            transfer_completion_event: completion_event,
            slot_id,
            endpoint_id,
            transfer_dir,
            transfer_trbs,
        };
        self.transfers.lock().push(Arc::downgrade(&t.state));
        t
    }

    /// Cancel all current transfers.
    pub fn cancel_all(&self) {
        self.transfers.lock().iter().for_each(|t| {
            let state = match t.upgrade() {
                Some(state) => state,
                None => {
                    error!("transfer is already cancelled or finished");
                    return;
                }
            };
            state.lock().try_cancel();
        });
    }

    fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
        let mut transfers = self.transfers.lock();
        match transfers.iter().position(|wt| match wt.upgrade() {
            Some(wt) => Arc::ptr_eq(&wt, t),
            None => false,
        }) {
            None => error!("attempted to remove unknow transfer"),
            Some(i) => {
                transfers.swap_remove(i);
            }
        }
    }
}

/// Xhci transfer denotes a transfer initiated by guest os driver. It will be submitted to a
/// XhciBackendDevice.
pub struct XhciTransfer {
    manager: XhciTransferManager,
    state: Arc<Mutex<XhciTransferState>>,
    mem: GuestMemory,
    port: Arc<UsbPort>,
    interrupter: Arc<Mutex<Interrupter>>,
    slot_id: u8,
    // id of endpoint in device slot.
    endpoint_id: u8,
    transfer_dir: TransferDirection,
    transfer_trbs: TransferDescriptor,
    transfer_completion_event: EventFd,
}

impl Drop for XhciTransfer {
    fn drop(&mut self) {
        self.manager.remove_transfer(&self.state);
    }
}

impl fmt::Debug for XhciTransfer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_trbs {:?}",
            self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_trbs
        )
    }
}

impl XhciTransfer {
    /// Get state of this transfer.
    pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
        &self.state
    }

    /// Get transfer type.
    pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
        XhciTransferType::new(self.mem.clone(), self.transfer_trbs.clone())
    }

    /// Get endpoint number.
    pub fn get_endpoint_number(&self) -> u8 {
        // See spec 4.5.1 for dci.
        self.endpoint_id / 2
    }

    /// get transfer direction.
    pub fn get_transfer_dir(&self) -> TransferDirection {
        self.transfer_dir
    }

    /// This functions should be invoked when transfer is completed (or failed).
    pub fn on_transfer_complete(
        &self,
        status: &TransferStatus,
        bytes_transferred: u32,
    ) -> Result<()> {
        match status {
            TransferStatus::NoDevice => {
                usb_debug!("device disconnected, detaching from port");
                // If the device is gone, we don't need to send transfer completion event, cause we
                // are going to destroy everything related to this device anyway.
                self.port.detach().map_err(Error::DetachPort)?;
                return Ok(());
            }
            TransferStatus::Cancelled => {
                // TODO(jkwang) According to the spec, we should send a stopped event here. But
                // kernel driver does not do anything meaningful when it sees a stopped event.
                return self
                    .transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent);
            }
            TransferStatus::Completed => {
                self.transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent)?;
            }
            _ => {
                // Transfer failed, we are not handling this correctly yet. Guest kernel might see
                // short packets for in transfer and might think control transfer is successful. It
                // will eventually find out device is in a wrong state.
                self.transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent)?;
            }
        }

        let mut edtla: u32 = 0;
        // As noted in xHCI spec 4.11.3.1
        // Transfer Event TRB only occurs under the following conditions:
        //   1. If the Interrupt On Completion flag is set.
        //   2. When a short transfer occurs during the execution of a Transfer TRB and the
        //      Interrupt-on-Short Packet flag is set.
        //   3. If an error occurs during the execution of a Transfer TRB.
        // Errors are handled above, so just check for the two flags.
        for atrb in &self.transfer_trbs {
            edtla += atrb.trb.transfer_length().map_err(Error::TransferLength)?;
            if atrb.trb.interrupt_on_completion()
                || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
            {
                // For details about event data trb and EDTLA, see spec 4.11.5.2.
                if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
                    let tlength = min(edtla, bytes_transferred);
                    self.interrupter
                        .lock()
                        .send_transfer_event_trb(
                            TrbCompletionCode::Success,
                            atrb.trb
                                .cast::<EventDataTrb>()
                                .map_err(Error::CastTrb)?
                                .get_event_data(),
                            tlength,
                            true,
                            self.slot_id,
                            self.endpoint_id,
                        )
                        .map_err(Error::SendInterrupt)?;
                } else {
                    // For Short Transfer details, see xHCI spec 4.10.1.1.
                    if edtla > bytes_transferred {
                        usb_debug!("on transfer complete short packet");
                        let residual_transfer_length = edtla - bytes_transferred;
                        self.interrupter
                            .lock()
                            .send_transfer_event_trb(
                                TrbCompletionCode::ShortPacket,
                                atrb.gpa,
                                residual_transfer_length,
                                true,
                                self.slot_id,
                                self.endpoint_id,
                            )
                            .map_err(Error::SendInterrupt)?;
                    } else {
                        usb_debug!("on transfer complete success");
                        self.interrupter
                            .lock()
                            .send_transfer_event_trb(
                                TrbCompletionCode::Success,
                                atrb.gpa,
                                0, // transfer length
                                true,
                                self.slot_id,
                                self.endpoint_id,
                            )
                            .map_err(Error::SendInterrupt)?;
                    }
                }
            }
        }
        Ok(())
    }

    /// Send this transfer to backend if it's a valid transfer.
    pub fn send_to_backend_if_valid(self) -> Result<()> {
        if self.validate_transfer()? {
            // Backend should invoke on transfer complete when transfer is completed.
            let port = self.port.clone();
            let mut backend = port.get_backend_device();
            match &mut *backend {
                Some(backend) => backend
                    .submit_transfer(self)
                    .map_err(|_| Error::SubmitTransfer)?,
                None => {
                    error!("backend is already disconnected");
                    self.transfer_completion_event
                        .write(1)
                        .map_err(Error::WriteCompletionEvent)?;
                }
            }
        } else {
            error!("invalid td on transfer ring");
            self.transfer_completion_event
                .write(1)
                .map_err(Error::WriteCompletionEvent)?;
        }
        Ok(())
    }

    // Check each trb in the transfer descriptor for invalid or out of bounds
    // parameters. Returns true iff the transfer descriptor is valid.
    fn validate_transfer(&self) -> Result<bool> {
        let mut valid = true;
        for atrb in &self.transfer_trbs {
            if !trb_is_valid(&atrb) {
                self.interrupter
                    .lock()
                    .send_transfer_event_trb(
                        TrbCompletionCode::TrbError,
                        atrb.gpa,
                        0,
                        false,
                        self.slot_id,
                        self.endpoint_id,
                    )
                    .map_err(Error::SendInterrupt)?;
                valid = false;
            }
        }
        Ok(valid)
    }
}

fn trb_is_valid(atrb: &AddressedTrb) -> bool {
    let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
        Ok(v) => v,
        Err(e) => {
            error!("unknown error {:?}", e);
            return false;
        }
    };
    can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
}
<commit_msg>usb: handle transfer errors after port is detached<commit_after>// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use super::interrupter::{Error as InterrupterError, Interrupter};
use super::scatter_gather_buffer::{Error as BufferError, ScatterGatherBuffer};
use super::usb_hub::{Error as HubError, UsbPort};
use super::xhci_abi::{
    AddressedTrb, Error as TrbError, EventDataTrb, SetupStageTrb, TransferDescriptor, TrbCast,
    TrbCompletionCode, TrbType,
};
use super::xhci_regs::MAX_INTERRUPTER;
use bit_field::Error as BitFieldError;
use std::cmp::min;
use std::fmt::{self, Display};
use std::mem;
use std::sync::{Arc, Weak};
use sync::Mutex;
use sys_util::{error, Error as SysError, EventFd, GuestMemory};
use usb_util::types::UsbRequestSetup;
use usb_util::usb_transfer::TransferStatus;

#[derive(Debug)]
pub enum Error {
    TrbType(BitFieldError),
    CastTrb(TrbError),
    TransferLength(TrbError),
    BadTrbType(TrbType),
    WriteCompletionEvent(SysError),
    CreateBuffer(BufferError),
    DetachPort(HubError),
    SendInterrupt(InterrupterError),
    SubmitTransfer,
}

type Result<T> = std::result::Result<T, Error>;

impl Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Error::*;

        match self {
            TrbType(e) => write!(f, "cannot get trb type: {}", e),
            CastTrb(e) => write!(f, "cannot cast trb: {}", e),
            TransferLength(e) => write!(f, "cannot get transfer length: {}", e),
            BadTrbType(t) => write!(f, "unexpected trb type: {:?}", t),
            WriteCompletionEvent(e) => write!(f, "cannot write completion event: {}", e),
            CreateBuffer(e) => write!(f, "cannot create transfer buffer: {}", e),
            DetachPort(e) => write!(f, "cannot detach from port: {}", e),
            SendInterrupt(e) => write!(f, "cannot send interrupter: {}", e),
            SubmitTransfer => write!(f, "failed to submit transfer to backend"),
        }
    }
}

/// Type of usb endpoints.
#[derive(PartialEq, Clone, Copy, Debug)]
pub enum TransferDirection {
    In,
    Out,
    Control,
}

/// Current state of xhci transfer.
pub enum XhciTransferState {
    Created,
    /// When transfer is submitted, it will contain a transfer callback, which should be invoked
    /// when the transfer is cancelled.
    Submitted {
        cancel_callback: Box<dyn FnMut() + Send>,
    },
    Cancelling,
    Cancelled,
    Completed,
}

impl XhciTransferState {
    /// Try to cancel this transfer, if it's possible.
    pub fn try_cancel(&mut self) {
        match mem::replace(self, XhciTransferState::Created) {
            XhciTransferState::Submitted {
                mut cancel_callback,
            } => {
                *self = XhciTransferState::Cancelling;
                cancel_callback();
            }
            XhciTransferState::Cancelling => {
                error!("Another cancellation is already issued.");
            }
            _ => {
                *self = XhciTransferState::Cancelled;
            }
        }
    }
}

/// Type of a transfer received handled by transfer ring.
pub enum XhciTransferType {
    // Normal means bulk transfer or interrupt transfer, depending on endpoint type.
    // See spec 4.11.2.1.
    Normal(ScatterGatherBuffer),
    // See usb spec for setup stage, data stage and status stage,
    // see xHCI spec 4.11.2.2 for corresponding trbs.
    SetupStage(UsbRequestSetup),
    DataStage(ScatterGatherBuffer),
    StatusStage,
    // See xHCI spec 4.11.2.3.
    Isochronous(ScatterGatherBuffer),
    // See xHCI spec 6.4.1.4.
    Noop,
}

impl XhciTransferType {
    /// Analyze transfer descriptor and return transfer type.
    pub fn new(mem: GuestMemory, td: TransferDescriptor) -> Result<XhciTransferType> {
        // We can figure out transfer type from the first trb.
        // See transfer descriptor description in xhci spec for more details.
        match td[0].trb.get_trb_type().map_err(Error::TrbType)? {
            TrbType::Normal => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::Normal(buffer))
            }
            TrbType::SetupStage => {
                let trb = td[0].trb.cast::<SetupStageTrb>().map_err(Error::CastTrb)?;
                Ok(XhciTransferType::SetupStage(UsbRequestSetup::new(
                    trb.get_request_type(),
                    trb.get_request(),
                    trb.get_value(),
                    trb.get_index(),
                    trb.get_length(),
                )))
            }
            TrbType::DataStage => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::DataStage(buffer))
            }
            TrbType::StatusStage => Ok(XhciTransferType::StatusStage),
            TrbType::Isoch => {
                let buffer = ScatterGatherBuffer::new(mem, td).map_err(Error::CreateBuffer)?;
                Ok(XhciTransferType::Isochronous(buffer))
            }
            TrbType::Noop => Ok(XhciTransferType::Noop),
            t => Err(Error::BadTrbType(t)),
        }
    }
}

/// Xhci Transfer manager holds reference to all ongoing transfers. Can cancel them all if
/// needed.
#[derive(Clone)]
pub struct XhciTransferManager {
    transfers: Arc<Mutex<Vec<Weak<Mutex<XhciTransferState>>>>>,
}

impl XhciTransferManager {
    /// Create a new manager.
    pub fn new() -> XhciTransferManager {
        XhciTransferManager {
            transfers: Arc::new(Mutex::new(Vec::new())),
        }
    }

    /// Build a new XhciTransfer. Endpoint id is the id in xHCI device slot.
    pub fn create_transfer(
        &self,
        mem: GuestMemory,
        port: Arc<UsbPort>,
        interrupter: Arc<Mutex<Interrupter>>,
        slot_id: u8,
        endpoint_id: u8,
        transfer_trbs: TransferDescriptor,
        completion_event: EventFd,
    ) -> XhciTransfer {
        assert!(!transfer_trbs.is_empty());
        let transfer_dir = {
            if endpoint_id == 0 {
                TransferDirection::Control
            } else if (endpoint_id % 2) == 0 {
                TransferDirection::Out
            } else {
                TransferDirection::In
            }
        };
        let t = XhciTransfer {
            manager: self.clone(),
            state: Arc::new(Mutex::new(XhciTransferState::Created)),
            mem,
            port,
            interrupter,
            transfer_completion_event: completion_event,
            slot_id,
            endpoint_id,
            transfer_dir,
            transfer_trbs,
        };
        self.transfers.lock().push(Arc::downgrade(&t.state));
        t
    }

    /// Cancel all current transfers.
    pub fn cancel_all(&self) {
        self.transfers.lock().iter().for_each(|t| {
            let state = match t.upgrade() {
                Some(state) => state,
                None => {
                    error!("transfer is already cancelled or finished");
                    return;
                }
            };
            state.lock().try_cancel();
        });
    }

    fn remove_transfer(&self, t: &Arc<Mutex<XhciTransferState>>) {
        let mut transfers = self.transfers.lock();
        match transfers.iter().position(|wt| match wt.upgrade() {
            Some(wt) => Arc::ptr_eq(&wt, t),
            None => false,
        }) {
            None => error!("attempted to remove unknow transfer"),
            Some(i) => {
                transfers.swap_remove(i);
            }
        }
    }
}

/// Xhci transfer denotes a transfer initiated by guest os driver. It will be submitted to a
/// XhciBackendDevice.
pub struct XhciTransfer {
    manager: XhciTransferManager,
    state: Arc<Mutex<XhciTransferState>>,
    mem: GuestMemory,
    port: Arc<UsbPort>,
    interrupter: Arc<Mutex<Interrupter>>,
    slot_id: u8,
    // id of endpoint in device slot.
    endpoint_id: u8,
    transfer_dir: TransferDirection,
    transfer_trbs: TransferDescriptor,
    transfer_completion_event: EventFd,
}

impl Drop for XhciTransfer {
    fn drop(&mut self) {
        self.manager.remove_transfer(&self.state);
    }
}

impl fmt::Debug for XhciTransfer {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "xhci_transfer slot id: {}, endpoint id {}, transfer_dir {:?}, transfer_trbs {:?}",
            self.slot_id, self.endpoint_id, self.transfer_dir, self.transfer_trbs
        )
    }
}

impl XhciTransfer {
    /// Get state of this transfer.
    pub fn state(&self) -> &Arc<Mutex<XhciTransferState>> {
        &self.state
    }

    /// Get transfer type.
    pub fn get_transfer_type(&self) -> Result<XhciTransferType> {
        XhciTransferType::new(self.mem.clone(), self.transfer_trbs.clone())
    }

    /// Get endpoint number.
    pub fn get_endpoint_number(&self) -> u8 {
        // See spec 4.5.1 for dci.
        self.endpoint_id / 2
    }

    /// get transfer direction.
    pub fn get_transfer_dir(&self) -> TransferDirection {
        self.transfer_dir
    }

    /// This functions should be invoked when transfer is completed (or failed).
    pub fn on_transfer_complete(
        &self,
        status: &TransferStatus,
        bytes_transferred: u32,
    ) -> Result<()> {
        match status {
            TransferStatus::NoDevice => {
                usb_debug!("device disconnected, detaching from port");
                // If the device is gone, we don't need to send transfer completion event, cause we
                // are going to destroy everything related to this device anyway.
                return match self.port.detach() {
                    Ok(v) => Ok(v),
                    // It's acceptable for the port to be already disconnected
                    // as asynchronous transfer completions are processed.
                    Err(HubError::AlreadyDetached(_e)) => Ok(()),
                    Err(e) => Err(Error::DetachPort(e)),
                };
            }
            TransferStatus::Cancelled => {
                // TODO(jkwang) According to the spec, we should send a stopped event here. But
                // kernel driver does not do anything meaningful when it sees a stopped event.
                return self
                    .transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent);
            }
            TransferStatus::Completed => {
                self.transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent)?;
            }
            _ => {
                // Transfer failed, we are not handling this correctly yet. Guest kernel might see
                // short packets for in transfer and might think control transfer is successful. It
                // will eventually find out device is in a wrong state.
                self.transfer_completion_event
                    .write(1)
                    .map_err(Error::WriteCompletionEvent)?;
            }
        }

        let mut edtla: u32 = 0;
        // As noted in xHCI spec 4.11.3.1
        // Transfer Event TRB only occurs under the following conditions:
        //   1. If the Interrupt On Completion flag is set.
        //   2. When a short transfer occurs during the execution of a Transfer TRB and the
        //      Interrupt-on-Short Packet flag is set.
        //   3. If an error occurs during the execution of a Transfer TRB.
        // Errors are handled above, so just check for the two flags.
        for atrb in &self.transfer_trbs {
            edtla += atrb.trb.transfer_length().map_err(Error::TransferLength)?;
            if atrb.trb.interrupt_on_completion()
                || (atrb.trb.interrupt_on_short_packet() && edtla > bytes_transferred)
            {
                // For details about event data trb and EDTLA, see spec 4.11.5.2.
                if atrb.trb.get_trb_type().map_err(Error::TrbType)? == TrbType::EventData {
                    let tlength = min(edtla, bytes_transferred);
                    self.interrupter
                        .lock()
                        .send_transfer_event_trb(
                            TrbCompletionCode::Success,
                            atrb.trb
                                .cast::<EventDataTrb>()
                                .map_err(Error::CastTrb)?
                                .get_event_data(),
                            tlength,
                            true,
                            self.slot_id,
                            self.endpoint_id,
                        )
                        .map_err(Error::SendInterrupt)?;
                } else {
                    // For Short Transfer details, see xHCI spec 4.10.1.1.
                    if edtla > bytes_transferred {
                        usb_debug!("on transfer complete short packet");
                        let residual_transfer_length = edtla - bytes_transferred;
                        self.interrupter
                            .lock()
                            .send_transfer_event_trb(
                                TrbCompletionCode::ShortPacket,
                                atrb.gpa,
                                residual_transfer_length,
                                true,
                                self.slot_id,
                                self.endpoint_id,
                            )
                            .map_err(Error::SendInterrupt)?;
                    } else {
                        usb_debug!("on transfer complete success");
                        self.interrupter
                            .lock()
                            .send_transfer_event_trb(
                                TrbCompletionCode::Success,
                                atrb.gpa,
                                0, // transfer length
                                true,
                                self.slot_id,
                                self.endpoint_id,
                            )
                            .map_err(Error::SendInterrupt)?;
                    }
                }
            }
        }
        Ok(())
    }

    /// Send this transfer to backend if it's a valid transfer.
    pub fn send_to_backend_if_valid(self) -> Result<()> {
        if self.validate_transfer()? {
            // Backend should invoke on transfer complete when transfer is completed.
            let port = self.port.clone();
            let mut backend = port.get_backend_device();
            match &mut *backend {
                Some(backend) => backend
                    .submit_transfer(self)
                    .map_err(|_| Error::SubmitTransfer)?,
                None => {
                    error!("backend is already disconnected");
                    self.transfer_completion_event
                        .write(1)
                        .map_err(Error::WriteCompletionEvent)?;
                }
            }
        } else {
            error!("invalid td on transfer ring");
            self.transfer_completion_event
                .write(1)
                .map_err(Error::WriteCompletionEvent)?;
        }
        Ok(())
    }

    // Check each trb in the transfer descriptor for invalid or out of bounds
    // parameters. Returns true iff the transfer descriptor is valid.
    fn validate_transfer(&self) -> Result<bool> {
        let mut valid = true;
        for atrb in &self.transfer_trbs {
            if !trb_is_valid(&atrb) {
                self.interrupter
                    .lock()
                    .send_transfer_event_trb(
                        TrbCompletionCode::TrbError,
                        atrb.gpa,
                        0,
                        false,
                        self.slot_id,
                        self.endpoint_id,
                    )
                    .map_err(Error::SendInterrupt)?;
                valid = false;
            }
        }
        Ok(valid)
    }
}

fn trb_is_valid(atrb: &AddressedTrb) -> bool {
    let can_be_in_transfer_ring = match atrb.trb.can_be_in_transfer_ring() {
        Ok(v) => v,
        Err(e) => {
            error!("unknown error {:?}", e);
            return false;
        }
    };
    can_be_in_transfer_ring && (atrb.trb.interrupter_target() < MAX_INTERRUPTER)
}
<|endoftext|>


<commit_before><commit_msg>begin writing the client code using examples/client.rs as sandbox<commit_after><|endoftext|>


<commit_before><commit_msg>Added color example<commit_after><|endoftext|>


<commit_before>#[link(name = "ruby")]
extern "C" {
    pub fn ruby_init();
}
<commit_msg>remove unneeded link attribute<commit_after>extern "C" {
    pub fn ruby_init();
}
<|endoftext|>


<commit_before>//! This module provides a simplified abstraction for working with
//! code blocks identified by their integer `NodeId`. In particular,
//! it captures a common set of attributes that all "function-like
//! things" (represented by `FnLike` instances) share. For example,
//! all `FnLike` instances have a type signature (be it explicit or
//! inferred). And all `FnLike` instances have a body, i.e., the code
//! that is run when the function-like thing it represents is invoked.
//!
//! With the above abstraction in place, one can treat the program
//! text as a collection of blocks of code (and most such blocks are
//! nested within a uniquely determined `FnLike`), and users can ask
//! for the `Code` associated with a particular NodeId.

use crate::hir::intravisit::FnKind;
use crate::hir::map;
use rustc_hir as ast;
use rustc_hir::{Expr, FnDecl, Node};
use rustc_span::Span;
use syntax::ast::{Attribute, Ident};

/// An FnLikeNode is a Node that is like a fn, in that it has a decl
/// and a body (as well as a NodeId, a span, etc).
///
/// More specifically, it is one of either:
///
///   - A function item,
///   - A closure expr (i.e., an ExprKind::Closure), or
///   - The default implementation for a trait method.
///
/// To construct one, use the `Code::from_node` function.
#[derive(Copy, Clone, Debug)]
pub struct FnLikeNode<'a> {
    node: Node<'a>,
}

/// MaybeFnLike wraps a method that indicates if an object
/// corresponds to some FnLikeNode.
trait MaybeFnLike {
    fn is_fn_like(&self) -> bool;
}

impl MaybeFnLike for ast::Item<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            ast::ItemKind::Fn(..) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for ast::ImplItem<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            ast::ImplItemKind::Method(..) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for ast::TraitItem<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for ast::Expr<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            ast::ExprKind::Closure(..) => true,
            _ => false,
        }
    }
}

/// Carries either an FnLikeNode or a Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
pub enum Code<'a> {
    FnLike(FnLikeNode<'a>),
    Expr(&'a Expr<'a>),
}

impl<'a> Code<'a> {
    pub fn id(&self) -> ast::HirId {
        match *self {
            Code::FnLike(node) => node.id(),
            Code::Expr(block) => block.hir_id,
        }
    }

    /// Attempts to construct a Code from presumed FnLike or Expr node input.
    pub fn from_node(map: &map::Map<'a>, id: ast::HirId) -> Option<Code<'a>> {
        match map.get(id) {
            map::Node::Block(_) => {
                //  Use the parent, hopefully an expression node.
                Code::from_node(map, map.get_parent_node(id))
            }
            map::Node::Expr(expr) => Some(Code::Expr(expr)),
            node => FnLikeNode::from_node(node).map(Code::FnLike),
        }
    }
}

/// These are all the components one can extract from a fn item for
/// use when implementing FnLikeNode operations.
struct ItemFnParts<'a> {
    ident: Ident,
    decl: &'a ast::FnDecl<'a>,
    header: ast::FnHeader,
    vis: &'a ast::Visibility<'a>,
    generics: &'a ast::Generics<'a>,
    body: ast::BodyId,
    id: ast::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

/// These are all the components one can extract from a closure expr
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
    decl: &'a FnDecl<'a>,
    body: ast::BodyId,
    id: ast::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

impl<'a> ClosureParts<'a> {
    fn new(
        d: &'a FnDecl<'a>,
        b: ast::BodyId,
        id: ast::HirId,
        s: Span,
        attrs: &'a [Attribute],
    ) -> Self {
        ClosureParts { decl: d, body: b, id, span: s, attrs }
    }
}

impl<'a> FnLikeNode<'a> {
    /// Attempts to construct a FnLikeNode from presumed FnLike node input.
    pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
        let fn_like = match node {
            map::Node::Item(item) => item.is_fn_like(),
            map::Node::TraitItem(tm) => tm.is_fn_like(),
            map::Node::ImplItem(it) => it.is_fn_like(),
            map::Node::Expr(e) => e.is_fn_like(),
            _ => false,
        };
        fn_like.then_some(FnLikeNode { node })
    }

    pub fn body(self) -> ast::BodyId {
        self.handle(
            |i: ItemFnParts<'a>| i.body,
            |_, _, _: &'a ast::FnSig<'a>, _, body: ast::BodyId, _, _| body,
            |c: ClosureParts<'a>| c.body,
        )
    }

    pub fn decl(self) -> &'a FnDecl<'a> {
        self.handle(
            |i: ItemFnParts<'a>| &*i.decl,
            |_, _, sig: &'a ast::FnSig<'a>, _, _, _, _| &sig.decl,
            |c: ClosureParts<'a>| c.decl,
        )
    }

    pub fn span(self) -> Span {
        self.handle(
            |i: ItemFnParts<'_>| i.span,
            |_, _, _: &'a ast::FnSig<'a>, _, _, span, _| span,
            |c: ClosureParts<'_>| c.span,
        )
    }

    pub fn id(self) -> ast::HirId {
        self.handle(
            |i: ItemFnParts<'_>| i.id,
            |id, _, _: &'a ast::FnSig<'a>, _, _, _, _| id,
            |c: ClosureParts<'_>| c.id,
        )
    }

    pub fn constness(self) -> ast::Constness {
        self.kind().header().map_or(ast::Constness::NotConst, |header| header.constness)
    }

    pub fn asyncness(self) -> ast::IsAsync {
        self.kind().header().map_or(ast::IsAsync::NotAsync, |header| header.asyncness)
    }

    pub fn unsafety(self) -> ast::Unsafety {
        self.kind().header().map_or(ast::Unsafety::Normal, |header| header.unsafety)
    }

    pub fn kind(self) -> FnKind<'a> {
        let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
            FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
        };
        let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs);
        let method = |_, ident: Ident, sig: &'a ast::FnSig<'a>, vis, _, _, attrs| {
            FnKind::Method(ident, sig, vis, attrs)
        };
        self.handle(item, method, closure)
    }

    fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
    where
        I: FnOnce(ItemFnParts<'a>) -> A,
        M: FnOnce(
            ast::HirId,
            Ident,
            &'a ast::FnSig<'a>,
            Option<&'a ast::Visibility<'a>>,
            ast::BodyId,
            Span,
            &'a [Attribute],
        ) -> A,
        C: FnOnce(ClosureParts<'a>) -> A,
    {
        match self.node {
            map::Node::Item(i) => match i.kind {
                ast::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
                    id: i.hir_id,
                    ident: i.ident,
                    decl: &sig.decl,
                    body: block,
                    vis: &i.vis,
                    span: i.span,
                    attrs: &i.attrs,
                    header: sig.header,
                    generics,
                }),
                _ => bug!("item FnLikeNode that is not fn-like"),
            },
            map::Node::TraitItem(ti) => match ti.kind {
                ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
                    method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                }
                _ => bug!("trait method FnLikeNode that is not fn-like"),
            },
            map::Node::ImplItem(ii) => match ii.kind {
                ast::ImplItemKind::Method(ref sig, body) => {
                    method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                }
                _ => bug!("impl method FnLikeNode that is not fn-like"),
            },
            map::Node::Expr(e) => match e.kind {
                ast::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
                    closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs))
                }
                _ => bug!("expr FnLikeNode that is not fn-like"),
            },
            _ => bug!("other FnLikeNode that is not fn-like"),
        }
    }
}
<commit_msg>canonicalize imports in map::block<commit_after>//! This module provides a simplified abstraction for working with
//! code blocks identified by their integer `NodeId`. In particular,
//! it captures a common set of attributes that all "function-like
//! things" (represented by `FnLike` instances) share. For example,
//! all `FnLike` instances have a type signature (be it explicit or
//! inferred). And all `FnLike` instances have a body, i.e., the code
//! that is run when the function-like thing it represents is invoked.
//!
//! With the above abstraction in place, one can treat the program
//! text as a collection of blocks of code (and most such blocks are
//! nested within a uniquely determined `FnLike`), and users can ask
//! for the `Code` associated with a particular NodeId.

use crate::hir::intravisit::FnKind;
use crate::hir::map::Map;
use rustc_hir as hir;
use rustc_hir::{Expr, FnDecl, Node};
use rustc_span::Span;
use syntax::ast::{Attribute, Ident};

/// An FnLikeNode is a Node that is like a fn, in that it has a decl
/// and a body (as well as a NodeId, a span, etc).
///
/// More specifically, it is one of either:
///
///   - A function item,
///   - A closure expr (i.e., an ExprKind::Closure), or
///   - The default implementation for a trait method.
///
/// To construct one, use the `Code::from_node` function.
#[derive(Copy, Clone, Debug)]
pub struct FnLikeNode<'a> {
    node: Node<'a>,
}

/// MaybeFnLike wraps a method that indicates if an object
/// corresponds to some FnLikeNode.
trait MaybeFnLike {
    fn is_fn_like(&self) -> bool;
}

impl MaybeFnLike for hir::Item<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            hir::ItemKind::Fn(..) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for hir::ImplItem<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            hir::ImplItemKind::Method(..) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for hir::TraitItem<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
            _ => false,
        }
    }
}

impl MaybeFnLike for hir::Expr<'_> {
    fn is_fn_like(&self) -> bool {
        match self.kind {
            hir::ExprKind::Closure(..) => true,
            _ => false,
        }
    }
}

/// Carries either an FnLikeNode or a Expr, as these are the two
/// constructs that correspond to "code" (as in, something from which
/// we can construct a control-flow graph).
#[derive(Copy, Clone)]
pub enum Code<'a> {
    FnLike(FnLikeNode<'a>),
    Expr(&'a Expr<'a>),
}

impl<'a> Code<'a> {
    pub fn id(&self) -> hir::HirId {
        match *self {
            Code::FnLike(node) => node.id(),
            Code::Expr(block) => block.hir_id,
        }
    }

    /// Attempts to construct a Code from presumed FnLike or Expr node input.
    pub fn from_node(map: &Map<'a>, id: hir::HirId) -> Option<Code<'a>> {
        match map.get(id) {
            Node::Block(_) => {
                //  Use the parent, hopefully an expression node.
                Code::from_node(map, map.get_parent_node(id))
            }
            Node::Expr(expr) => Some(Code::Expr(expr)),
            node => FnLikeNode::from_node(node).map(Code::FnLike),
        }
    }
}

/// These are all the components one can extract from a fn item for
/// use when implementing FnLikeNode operations.
struct ItemFnParts<'a> {
    ident: Ident,
    decl: &'a hir::FnDecl<'a>,
    header: hir::FnHeader,
    vis: &'a hir::Visibility<'a>,
    generics: &'a hir::Generics<'a>,
    body: hir::BodyId,
    id: hir::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

/// These are all the components one can extract from a closure expr
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
    decl: &'a FnDecl<'a>,
    body: hir::BodyId,
    id: hir::HirId,
    span: Span,
    attrs: &'a [Attribute],
}

impl<'a> ClosureParts<'a> {
    fn new(
        d: &'a FnDecl<'a>,
        b: hir::BodyId,
        id: hir::HirId,
        s: Span,
        attrs: &'a [Attribute],
    ) -> Self {
        ClosureParts { decl: d, body: b, id, span: s, attrs }
    }
}

impl<'a> FnLikeNode<'a> {
    /// Attempts to construct a FnLikeNode from presumed FnLike node input.
    pub fn from_node(node: Node<'_>) -> Option<FnLikeNode<'_>> {
        let fn_like = match node {
            Node::Item(item) => item.is_fn_like(),
            Node::TraitItem(tm) => tm.is_fn_like(),
            Node::ImplItem(it) => it.is_fn_like(),
            Node::Expr(e) => e.is_fn_like(),
            _ => false,
        };
        fn_like.then_some(FnLikeNode { node })
    }

    pub fn body(self) -> hir::BodyId {
        self.handle(
            |i: ItemFnParts<'a>| i.body,
            |_, _, _: &'a hir::FnSig<'a>, _, body: hir::BodyId, _, _| body,
            |c: ClosureParts<'a>| c.body,
        )
    }

    pub fn decl(self) -> &'a FnDecl<'a> {
        self.handle(
            |i: ItemFnParts<'a>| &*i.decl,
            |_, _, sig: &'a hir::FnSig<'a>, _, _, _, _| &sig.decl,
            |c: ClosureParts<'a>| c.decl,
        )
    }

    pub fn span(self) -> Span {
        self.handle(
            |i: ItemFnParts<'_>| i.span,
            |_, _, _: &'a hir::FnSig<'a>, _, _, span, _| span,
            |c: ClosureParts<'_>| c.span,
        )
    }

    pub fn id(self) -> hir::HirId {
        self.handle(
            |i: ItemFnParts<'_>| i.id,
            |id, _, _: &'a hir::FnSig<'a>, _, _, _, _| id,
            |c: ClosureParts<'_>| c.id,
        )
    }

    pub fn constness(self) -> hir::Constness {
        self.kind().header().map_or(hir::Constness::NotConst, |header| header.constness)
    }

    pub fn asyncness(self) -> hir::IsAsync {
        self.kind().header().map_or(hir::IsAsync::NotAsync, |header| header.asyncness)
    }

    pub fn unsafety(self) -> hir::Unsafety {
        self.kind().header().map_or(hir::Unsafety::Normal, |header| header.unsafety)
    }

    pub fn kind(self) -> FnKind<'a> {
        let item = |p: ItemFnParts<'a>| -> FnKind<'a> {
            FnKind::ItemFn(p.ident, p.generics, p.header, p.vis, p.attrs)
        };
        let closure = |c: ClosureParts<'a>| FnKind::Closure(c.attrs);
        let method = |_, ident: Ident, sig: &'a hir::FnSig<'a>, vis, _, _, attrs| {
            FnKind::Method(ident, sig, vis, attrs)
        };
        self.handle(item, method, closure)
    }

    fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A
    where
        I: FnOnce(ItemFnParts<'a>) -> A,
        M: FnOnce(
            hir::HirId,
            Ident,
            &'a hir::FnSig<'a>,
            Option<&'a hir::Visibility<'a>>,
            hir::BodyId,
            Span,
            &'a [Attribute],
        ) -> A,
        C: FnOnce(ClosureParts<'a>) -> A,
    {
        match self.node {
            Node::Item(i) => match i.kind {
                hir::ItemKind::Fn(ref sig, ref generics, block) => item_fn(ItemFnParts {
                    id: i.hir_id,
                    ident: i.ident,
                    decl: &sig.decl,
                    body: block,
                    vis: &i.vis,
                    span: i.span,
                    attrs: &i.attrs,
                    header: sig.header,
                    generics,
                }),
                _ => bug!("item FnLikeNode that is not fn-like"),
            },
            Node::TraitItem(ti) => match ti.kind {
                hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
                    method(ti.hir_id, ti.ident, sig, None, body, ti.span, &ti.attrs)
                }
                _ => bug!("trait method FnLikeNode that is not fn-like"),
            },
            Node::ImplItem(ii) => match ii.kind {
                hir::ImplItemKind::Method(ref sig, body) => {
                    method(ii.hir_id, ii.ident, sig, Some(&ii.vis), body, ii.span, &ii.attrs)
                }
                _ => bug!("impl method FnLikeNode that is not fn-like"),
            },
            Node::Expr(e) => match e.kind {
                hir::ExprKind::Closure(_, ref decl, block, _fn_decl_span, _gen) => {
                    closure(ClosureParts::new(&decl, block, e.hir_id, e.span, &e.attrs))
                }
                _ => bug!("expr FnLikeNode that is not fn-like"),
            },
            _ => bug!("other FnLikeNode that is not fn-like"),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// An "interner" is a data structure that associates values with uint tags and
// allows bidirectional lookup; i.e. given a value, one can easily find the
// type, and vice versa.

use ast::Name;

use collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::mem;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = (*vect).len() as Name;
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = (*vect).len() as Name;
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx as uint)).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

// A StrInterner differs from Interner<String> in that it accepts
// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = self.len() as Name;
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = self.len() as Name;
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    // create a gensym with the same name as an existing
    // entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = self.len() as Name;
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx as uint)).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx as uint)).clone()
    }

    /// Returns this string with lifetime tied to the interner. Since
    /// strings may never be removed from the interner, this is safe.
    pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str {
        let vect = self.vect.borrow();
        let s: &str = vect.get(idx as uint).as_slice();
        unsafe {
            mem::transmute(s)
        }
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(13);
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), 1);
        assert_eq!(i.intern(RcStr::new("cat")), 1);
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), 2);
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), 3);
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), 4);
        assert_eq!(i.get(0), RcStr::new("dog"));
        assert_eq!(i.get(1), RcStr::new("cat"));
        assert_eq!(i.get(2), RcStr::new("zebra"));
        assert_eq!(i.get(3), RcStr::new("zebra"));
        assert_eq!(i.get(4), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(0), RcStr::new("Alan"));
        assert_eq!(i.get(1), RcStr::new("Bob"));
        assert_eq!(i.get(2), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), 1);
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), 0);
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), 0);
        // different string gets a different #:
        assert_eq!(i.intern("cat"), 1);
        assert_eq!(i.intern("cat"), 1);
        // dog is still at zero
        assert_eq!(i.intern("dog"), 0);
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), 2);
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), 3);
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), 4);
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(2), 5);
        assert_eq!(i.get(5), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(2), 6);
        assert_eq!(i.get(6), RcStr::new("zebra"));
        assert_eq!(i.get(0), RcStr::new("dog"));
        assert_eq!(i.get(1), RcStr::new("cat"));
        assert_eq!(i.get(2), RcStr::new("zebra"));
        assert_eq!(i.get(3), RcStr::new("zebra"));
        assert_eq!(i.get(4), RcStr::new("dog"));
    }
}
<commit_msg>syntax: use doc comments in the interner<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// An "interner" is a data structure that associates values with uint tags and
// allows bidirectional lookup; i.e. given a value, one can easily find the
// type, and vice versa.

use ast::Name;

use collections::HashMap;
use std::cell::RefCell;
use std::cmp::Equiv;
use std::fmt;
use std::hash::Hash;
use std::mem;
use std::rc::Rc;

pub struct Interner<T> {
    map: RefCell<HashMap<T, Name>>,
    vect: RefCell<Vec<T> >,
}

// when traits can extend traits, we should extend index<Name,T> to get []
impl<T: Eq + Hash + Clone + 'static> Interner<T> {
    pub fn new() -> Interner<T> {
        Interner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[T]) -> Interner<T> {
        let rv = Interner::new();
        for v in init.iter() {
            rv.intern((*v).clone());
        }
        rv
    }

    pub fn intern(&self, val: T) -> Name {
        let mut map = self.map.borrow_mut();
        match (*map).find(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let mut vect = self.vect.borrow_mut();
        let new_idx = (*vect).len() as Name;
        (*map).insert(val.clone(), new_idx);
        (*vect).push(val);
        new_idx
    }

    pub fn gensym(&self, val: T) -> Name {
        let mut vect = self.vect.borrow_mut();
        let new_idx = (*vect).len() as Name;
        // leave out of .map to avoid colliding
        (*vect).push(val);
        new_idx
    }

    pub fn get(&self, idx: Name) -> T {
        let vect = self.vect.borrow();
        (*(*vect).get(idx as uint)).clone()
    }

    pub fn len(&self) -> uint {
        let vect = self.vect.borrow();
        (*vect).len()
    }

    pub fn find_equiv<Q:Hash + Equiv<T>>(&self, val: &Q) -> Option<Name> {
        let map = self.map.borrow();
        match (*map).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[deriving(Clone, PartialEq, Hash, PartialOrd)]
pub struct RcStr {
    string: Rc<String>,
}

impl Eq for RcStr {}

impl Ord for RcStr {
    fn cmp(&self, other: &RcStr) -> Ordering {
        self.as_slice().cmp(&other.as_slice())
    }
}

impl Str for RcStr {
    #[inline]
    fn as_slice<'a>(&'a self) -> &'a str {
        let s: &'a str = self.string.as_slice();
        s
    }
}

impl fmt::Show for RcStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use std::fmt::Show;
        self.as_slice().fmt(f)
    }
}

impl RcStr {
    pub fn new(string: &str) -> RcStr {
        RcStr {
            string: Rc::new(string.to_string()),
        }
    }
}

/// A StrInterner differs from Interner<String> in that it accepts
/// &str rather than RcStr, resulting in less allocation.
pub struct StrInterner {
    map: RefCell<HashMap<RcStr, Name>>,
    vect: RefCell<Vec<RcStr> >,
}

/// When traits can extend traits, we should extend index<Name,T> to get []
impl StrInterner {
    pub fn new() -> StrInterner {
        StrInterner {
            map: RefCell::new(HashMap::new()),
            vect: RefCell::new(Vec::new()),
        }
    }

    pub fn prefill(init: &[&str]) -> StrInterner {
        let rv = StrInterner::new();
        for &v in init.iter() { rv.intern(v); }
        rv
    }

    pub fn intern(&self, val: &str) -> Name {
        let mut map = self.map.borrow_mut();
        match map.find_equiv(&val) {
            Some(&idx) => return idx,
            None => (),
        }

        let new_idx = self.len() as Name;
        let val = RcStr::new(val);
        map.insert(val.clone(), new_idx);
        self.vect.borrow_mut().push(val);
        new_idx
    }

    pub fn gensym(&self, val: &str) -> Name {
        let new_idx = self.len() as Name;
        // leave out of .map to avoid colliding
        self.vect.borrow_mut().push(RcStr::new(val));
        new_idx
    }

    // I want these gensyms to share name pointers
    // with existing entries. This would be automatic,
    // except that the existing gensym creates its
    // own managed ptr using to_managed. I think that
    // adding this utility function is the most
    // lightweight way to get what I want, though not
    // necessarily the cleanest.

    /// Create a gensym with the same name as an existing
    /// entry.
    pub fn gensym_copy(&self, idx : Name) -> Name {
        let new_idx = self.len() as Name;
        // leave out of map to avoid colliding
        let mut vect = self.vect.borrow_mut();
        let existing = (*vect.get(idx as uint)).clone();
        vect.push(existing);
        new_idx
    }

    pub fn get(&self, idx: Name) -> RcStr {
        (*self.vect.borrow().get(idx as uint)).clone()
    }

    /// Returns this string with lifetime tied to the interner. Since
    /// strings may never be removed from the interner, this is safe.
    pub fn get_ref<'a>(&'a self, idx: Name) -> &'a str {
        let vect = self.vect.borrow();
        let s: &str = vect.get(idx as uint).as_slice();
        unsafe {
            mem::transmute(s)
        }
    }

    pub fn len(&self) -> uint {
        self.vect.borrow().len()
    }

    pub fn find_equiv<Q:Hash + Equiv<RcStr>>(&self, val: &Q) -> Option<Name> {
        match (*self.map.borrow()).find_equiv(val) {
            Some(v) => Some(*v),
            None => None,
        }
    }

    pub fn clear(&self) {
        *self.map.borrow_mut() = HashMap::new();
        *self.vect.borrow_mut() = Vec::new();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    #[should_fail]
    fn i1 () {
        let i : Interner<RcStr> = Interner::new();
        i.get(13);
    }

    #[test]
    fn interner_tests () {
        let i : Interner<RcStr> = Interner::new();
        // first one is zero:
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // re-use gets the same entry:
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // different string gets a different #:
        assert_eq!(i.intern(RcStr::new("cat")), 1);
        assert_eq!(i.intern(RcStr::new("cat")), 1);
        // dog is still at zero
        assert_eq!(i.intern(RcStr::new("dog")), 0);
        // gensym gets 3
        assert_eq!(i.gensym(RcStr::new("zebra") ), 2);
        // gensym of same string gets new number :
        assert_eq!(i.gensym (RcStr::new("zebra") ), 3);
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym(RcStr::new("dog")), 4);
        assert_eq!(i.get(0), RcStr::new("dog"));
        assert_eq!(i.get(1), RcStr::new("cat"));
        assert_eq!(i.get(2), RcStr::new("zebra"));
        assert_eq!(i.get(3), RcStr::new("zebra"));
        assert_eq!(i.get(4), RcStr::new("dog"));
    }

    #[test]
    fn i3 () {
        let i : Interner<RcStr> = Interner::prefill([
            RcStr::new("Alan"),
            RcStr::new("Bob"),
            RcStr::new("Carol")
        ]);
        assert_eq!(i.get(0), RcStr::new("Alan"));
        assert_eq!(i.get(1), RcStr::new("Bob"));
        assert_eq!(i.get(2), RcStr::new("Carol"));
        assert_eq!(i.intern(RcStr::new("Bob")), 1);
    }

    #[test]
    fn string_interner_tests() {
        let i : StrInterner = StrInterner::new();
        // first one is zero:
        assert_eq!(i.intern("dog"), 0);
        // re-use gets the same entry:
        assert_eq!(i.intern ("dog"), 0);
        // different string gets a different #:
        assert_eq!(i.intern("cat"), 1);
        assert_eq!(i.intern("cat"), 1);
        // dog is still at zero
        assert_eq!(i.intern("dog"), 0);
        // gensym gets 3
        assert_eq!(i.gensym("zebra"), 2);
        // gensym of same string gets new number :
        assert_eq!(i.gensym("zebra"), 3);
        // gensym of *existing* string gets new number:
        assert_eq!(i.gensym("dog"), 4);
        // gensym tests again with gensym_copy:
        assert_eq!(i.gensym_copy(2), 5);
        assert_eq!(i.get(5), RcStr::new("zebra"));
        assert_eq!(i.gensym_copy(2), 6);
        assert_eq!(i.get(6), RcStr::new("zebra"));
        assert_eq!(i.get(0), RcStr::new("dog"));
        assert_eq!(i.get(1), RcStr::new("cat"));
        assert_eq!(i.get(2), RcStr::new("zebra"));
        assert_eq!(i.get(3), RcStr::new("zebra"));
        assert_eq!(i.get(4), RcStr::new("dog"));
    }
}
<|endoftext|>


<commit_before>use std::str::Chars;
use std::io::{BufferedReader, File, IoError};

pub trait CodeReader {
    fn read_char(&mut self) -> Option<char>;
    fn filename(&self) -> &str;
}

pub struct StrReader {
  program: &'static str,
  rest: Chars<'static>
}

impl StrReader {
  pub fn new(program: &'static str) -> StrReader {
    StrReader { program: program, rest: program.chars() }
  }
}

impl CodeReader for StrReader {
  fn read_char(&mut self) -> Option<char> {
    self.rest.next()
  }

  fn filename(&self) -> &str {
    "<code>"
  }
}

pub struct FileReader {
    filename: &'static str,
    reader: BufferedReader<Result<File,IoError>>
}

impl FileReader {
  pub fn new(filename: &'static str) -> FileReader {
    let file = File::open(&Path::new(filename));
    let reader = BufferedReader::new(file);

    FileReader { filename: filename, reader: reader }
  }
}

impl CodeReader for FileReader {
  fn read_char(&mut self) -> Option<char> {
      match self.reader.read_char() {
        Ok(ch) => Some(ch),
        _ => None
      }
  }

  fn filename(&self) -> &str {
    self.filename
  }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn read_from_str() {
        let mut reader = StrReader::new("abc");

        assert_eq!(Some('a'), reader.read_char());
        assert_eq!(Some('b'), reader.read_char());
        assert_eq!(Some('c'), reader.read_char());
        assert_eq!(None, reader.read_char());
    }

    #[test]
    fn read_from_file() {
        let mut reader = FileReader::new("tests/abc.txt");

        assert_eq!(Some('a'), reader.read_char());
        assert_eq!(Some('b'), reader.read_char());
        assert_eq!(Some('c'), reader.read_char());
        assert_eq!(None, reader.read_char());
    }
}
<commit_msg>renamed std::io to std::old_io<commit_after>use std::str::Chars;
use std::old_io::{BufferedReader, File, IoError};

pub trait CodeReader {
    fn read_char(&mut self) -> Option<char>;
    fn filename(&self) -> &str;
}

pub struct StrReader {
  program: &'static str,
  rest: Chars<'static>
}

impl StrReader {
  pub fn new(program: &'static str) -> StrReader {
    StrReader { program: program, rest: program.chars() }
  }
}

impl CodeReader for StrReader {
  fn read_char(&mut self) -> Option<char> {
    self.rest.next()
  }

  fn filename(&self) -> &str {
    "<code>"
  }
}

pub struct FileReader {
    filename: &'static str,
    reader: BufferedReader<Result<File,IoError>>
}

impl FileReader {
  pub fn new(filename: &'static str) -> FileReader {
    let file = File::open(&Path::new(filename));
    let reader = BufferedReader::new(file);

    FileReader { filename: filename, reader: reader }
  }
}

impl CodeReader for FileReader {
  fn read_char(&mut self) -> Option<char> {
      match self.reader.read_char() {
        Ok(ch) => Some(ch),
        _ => None
      }
  }

  fn filename(&self) -> &str {
    self.filename
  }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn read_from_str() {
        let mut reader = StrReader::new("abc");

        assert_eq!(Some('a'), reader.read_char());
        assert_eq!(Some('b'), reader.read_char());
        assert_eq!(Some('c'), reader.read_char());
        assert_eq!(None, reader.read_char());
    }

    #[test]
    fn read_from_file() {
        let mut reader = FileReader::new("tests/abc.txt");

        assert_eq!(Some('a'), reader.read_char());
        assert_eq!(Some('b'), reader.read_char());
        assert_eq!(Some('c'), reader.read_char());
        assert_eq!(None, reader.read_char());
    }
}
<|endoftext|>