<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/. */

extern mod freetype;

use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
use font::{FontWeight700, FontWeight800, FontWeight900};
use geometry::Au;
use geometry;
use platform::font_context::FontContextHandle;
use text::glyph::GlyphIndex;
use text::util::{float_to_fixed, fixed_to_float};

use freetype::freetype::bindgen::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::bindgen::{FT_Load_Glyph, FT_Set_Char_Size};
use freetype::freetype::bindgen::{FT_New_Face, FT_Get_Sfnt_Table};
use freetype::freetype::bindgen::{FT_New_Memory_Face, FT_Done_Face};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
use freetype::freetype::{FT_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

pub struct FontTable {
    bogus: ()
}

impl FontTableMethods for FontTable {
    fn with_buffer(&self, _blk: &fn(*u8, uint)) {
        fail!()
    }
}

enum FontSource {
    FontSourceMem(~[u8]),
    FontSourceFile(~str)
}

pub struct FontHandle {
    // The font binary. This must stay valid for the lifetime of the font,
    // if the font is created using FT_Memory_Face.
    source: FontSource,
    face: FT_Face,
}

#[unsafe_destructor]
impl Drop for FontHandle {
    fn finalize(&self) {
        assert!(self.face.is_not_null());
        if !FT_Done_Face(self.face).succeeded() {
            fail!(~"FT_Done_Face failed");
        }
    }
}

impl FontHandleMethods for FontHandle {
    pub fn new_from_buffer(fctx: &FontContextHandle,
                           buf: ~[u8],
                           style: &SpecifiedFontStyle)
                        -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let face_result = do vec::as_imm_buf(buf) |bytes: *u8, len: uint| {
            create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
        };

        // TODO: this could be more simply written as result::chain
        // and moving buf into the struct ctor, but cant' move out of
        // captured binding.
        return match face_result {
            Ok(face) => Ok(FontHandle { face: face, source: FontSourceMem(buf) }),
            Err(()) => Err(())
        };

         fn create_face_from_buffer(lib: FT_Library,
                                    cbuf: *u8, cbuflen: uint, pt_size: float)
             -> Result<FT_Face, ()> {

             let mut face: FT_Face = ptr::null();
             let face_index = 0 as FT_Long;
             let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
                                             face_index, ptr::to_unsafe_ptr(&face));

             if !result.succeeded() || face.is_null() {
                 return Err(());
             }
             if FontHandle::set_char_size(face, pt_size).is_ok() {
                 Ok(face)
             } else {
                 Err(())
             }
         }
    }

    // an identifier usable by FontContextHandle to recreate this FontHandle.
    fn face_identifier(&self) -> ~str {
        /* FT_Get_Postscript_Name seems like a better choice here, but it
           doesn't give usable results for fontconfig when deserializing. */
        unsafe { str::raw::from_c_str((*self.face).family_name) }
    }
    fn family_name(&self) -> ~str {
        unsafe { str::raw::from_c_str((*self.face).family_name) }
    }
    fn face_name(&self) -> ~str {
        unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
    }
    fn is_italic(&self) -> bool {
        unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
    }
    fn boldness(&self) -> CSSFontWeight {
        let default_weight = FontWeight400;
        if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
            default_weight
        } else {
            let os2 = unsafe { FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *TT_OS2 };
            let valid = os2.is_not_null() && unsafe { (*os2).version != 0xffff };
            if valid {
                let weight = unsafe { (*os2).usWeightClass };
                match weight {
                  1 | 100..199 => FontWeight100,
                  2 | 200..299 => FontWeight200,
                  3 | 300..399 => FontWeight300,
                  4 | 400..499 => FontWeight400,
                  5 | 500..599 => FontWeight500,
                  6 | 600..699 => FontWeight600,
                  7 | 700..799 => FontWeight700,
                  8 | 800..899 => FontWeight800,
                  9 | 900..999 => FontWeight900,
                  _ => default_weight
                }
            } else {
                default_weight
            }
        }
    }

    fn clone_with_style(&self,
                        fctx: &FontContextHandle,
                        style: &UsedFontStyle) -> Result<FontHandle, ()> {
        match self.source {
            FontSourceMem(ref buf) => {
                FontHandleMethods::new_from_buffer(fctx, buf.clone(), style)
            }
            FontSourceFile(copy file) => {
                FontHandle::new_from_file(fctx, file, style)
            }
        }
    }

    pub fn glyph_index(&self,
                       codepoint: char) -> Option<GlyphIndex> {
        assert!(self.face.is_not_null());
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    pub fn glyph_h_advance(&self,
                           glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert!(self.face.is_not_null());
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = cast::transmute(void_glyph);
                assert!(slot.is_not_null());
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    pub fn get_metrics(&self) -> FontMetrics {
        /* TODO(Issue #76): complete me */
        let face = self.get_face_rec();

        let underline_size = self.font_units_to_au(face.underline_thickness as float);
        let underline_offset = self.font_units_to_au(face.underline_position as float);
        let em_size = self.font_units_to_au(face.units_per_EM as float);
        let ascent = self.font_units_to_au(face.ascender as float);
        let descent = self.font_units_to_au(face.descender as float);
        let max_advance = self.font_units_to_au(face.max_advance_width as float);

        return FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            leading:          geometry::from_pt(0.0), //FIXME
            x_height:         geometry::from_pt(0.0), //FIXME
            em_size:          em_size,
            ascent:           ascent,
            descent:          descent,
            max_advance:      max_advance
        }
    }

    fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
        None
    }
}

pub impl FontHandle {
    priv fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
        let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
        let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
        let h_dpi = 72;
        let v_dpi = 72;

        let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
        if result.succeeded() { Ok(()) } else { Err(()) }
    }

    pub fn new_from_file(fctx: &FontContextHandle, file: ~str,
                         style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let mut face: FT_Face = ptr::null();
        let face_index = 0 as FT_Long;
        do str::as_c_str(file) |file_str| {
            FT_New_Face(ft_ctx, file_str,
                        face_index, ptr::to_unsafe_ptr(&face));
        }
        if face.is_null() {
            return Err(());
        }
        if FontHandle::set_char_size(face, style.pt_size).is_ok() {
            Ok(FontHandle { source: FontSourceFile(file), face: face })
        } else {
            Err(())
        }
    }

    pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
                               -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let mut face: FT_Face = ptr::null();
        let face_index = 0 as FT_Long;
        do str::as_c_str(file) |file_str| {
            FT_New_Face(ft_ctx, file_str,
                        face_index, ptr::to_unsafe_ptr(&face));
        }
        if face.is_null() {
            return Err(());
        }

        Ok(FontHandle { source: FontSourceFile(file), face: face })
    }

    priv fn get_face_rec(&self) -> &'self FT_FaceRec {
        unsafe {
            &(*self.face)
        }
    }

    priv fn font_units_to_au(&self, value: float) -> Au {
        let face = self.get_face_rec();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { cast::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = unsafe { &((*size).metrics) };

        let em_size = face.units_per_EM as float;
        let x_scale = (metrics.x_ppem as float) / em_size as float;

        // If this isn't true then we're scaling one of the axes wrong
        assert!(metrics.x_ppem == metrics.y_ppem);

        return geometry::from_frac_px(value * x_scale);
    }
}

<commit_msg>fix build err<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/. */

extern mod freetype;

use font::{CSSFontWeight, FontHandleMethods, FontMetrics, FontTableMethods};
use font::{FontTableTag, FractionalPixel, SpecifiedFontStyle, UsedFontStyle, FontWeight100};
use font::{FontWeight200, FontWeight300, FontWeight400, FontWeight500, FontWeight600};
use font::{FontWeight700, FontWeight800, FontWeight900};
use geometry::Au;
use geometry;
use platform::font_context::FontContextHandle;
use text::glyph::GlyphIndex;
use text::util::{float_to_fixed, fixed_to_float};

use freetype::freetype::bindgen::{FT_Get_Char_Index, FT_Get_Postscript_Name};
use freetype::freetype::bindgen::{FT_Load_Glyph, FT_Set_Char_Size};
use freetype::freetype::bindgen::{FT_New_Face, FT_Get_Sfnt_Table};
use freetype::freetype::bindgen::{FT_New_Memory_Face, FT_Done_Face};
use freetype::freetype::{FTErrorMethods, FT_F26Dot6, FT_Face, FT_FaceRec};
use freetype::freetype::{FT_GlyphSlot, FT_Library, FT_Long, FT_ULong};
use freetype::freetype::{FT_STYLE_FLAG_ITALIC, FT_STYLE_FLAG_BOLD};
use freetype::freetype::{FT_SizeRec, FT_UInt, FT_Size_Metrics};
use freetype::freetype::{ft_sfnt_os2};
use freetype::tt_os2::TT_OS2;

fn float_to_fixed_ft(f: float) -> i32 {
    float_to_fixed(6, f)
}

fn fixed_to_float_ft(f: i32) -> float {
    fixed_to_float(6, f)
}

pub struct FontTable {
    bogus: ()
}

impl FontTableMethods for FontTable {
    fn with_buffer(&self, _blk: &fn(*u8, uint)) {
        fail!()
    }
}

enum FontSource {
    FontSourceMem(~[u8]),
    FontSourceFile(~str)
}

pub struct FontHandle {
    // The font binary. This must stay valid for the lifetime of the font,
    // if the font is created using FT_Memory_Face.
    source: FontSource,
    face: FT_Face,
}

#[unsafe_destructor]
impl Drop for FontHandle {
    fn finalize(&self) {
        assert!(self.face.is_not_null());
        if !FT_Done_Face(self.face).succeeded() {
            fail!(~"FT_Done_Face failed");
        }
    }
}

impl FontHandleMethods for FontHandle {
    pub fn new_from_buffer(fctx: &FontContextHandle,
                           buf: ~[u8],
                           style: &SpecifiedFontStyle)
                        -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let face_result = do vec::as_imm_buf(buf) |bytes: *u8, len: uint| {
            create_face_from_buffer(ft_ctx, bytes, len, style.pt_size)
        };

        // TODO: this could be more simply written as result::chain
        // and moving buf into the struct ctor, but cant' move out of
        // captured binding.
        return match face_result {
            Ok(face) => Ok(FontHandle { face: face, source: FontSourceMem(buf) }),
            Err(()) => Err(())
        };

         fn create_face_from_buffer(lib: FT_Library,
                                    cbuf: *u8, cbuflen: uint, pt_size: float)
             -> Result<FT_Face, ()> {

             let mut face: FT_Face = ptr::null();
             let face_index = 0 as FT_Long;
             let result = FT_New_Memory_Face(lib, cbuf, cbuflen as FT_Long,
                                             face_index, ptr::to_unsafe_ptr(&face));

             if !result.succeeded() || face.is_null() {
                 return Err(());
             }
             if FontHandle::set_char_size(face, pt_size).is_ok() {
                 Ok(face)
             } else {
                 Err(())
             }
         }
    }

    // an identifier usable by FontContextHandle to recreate this FontHandle.
    fn face_identifier(&self) -> ~str {
        /* FT_Get_Postscript_Name seems like a better choice here, but it
           doesn't give usable results for fontconfig when deserializing. */
        unsafe { str::raw::from_c_str((*self.face).family_name) }
    }
    fn family_name(&self) -> ~str {
        unsafe { str::raw::from_c_str((*self.face).family_name) }
    }
    fn face_name(&self) -> ~str {
        unsafe { str::raw::from_c_str(FT_Get_Postscript_Name(self.face)) }
    }
    fn is_italic(&self) -> bool {
        unsafe { (*self.face).style_flags & FT_STYLE_FLAG_ITALIC != 0 }
    }
    fn boldness(&self) -> CSSFontWeight {
        let default_weight = FontWeight400;
        if unsafe { (*self.face).style_flags & FT_STYLE_FLAG_BOLD == 0 } {
            default_weight
        } else {
            let os2 = unsafe { FT_Get_Sfnt_Table(self.face, ft_sfnt_os2) as *TT_OS2 };
            let valid = os2.is_not_null() && unsafe { (*os2).version != 0xffff };
            if valid {
                let weight = unsafe { (*os2).usWeightClass };
                match weight {
                  1 | 100..199 => FontWeight100,
                  2 | 200..299 => FontWeight200,
                  3 | 300..399 => FontWeight300,
                  4 | 400..499 => FontWeight400,
                  5 | 500..599 => FontWeight500,
                  6 | 600..699 => FontWeight600,
                  7 | 700..799 => FontWeight700,
                  8 | 800..899 => FontWeight800,
                  9 | 900..999 => FontWeight900,
                  _ => default_weight
                }
            } else {
                default_weight
            }
        }
    }

    fn clone_with_style(&self,
                        fctx: &FontContextHandle,
                        style: &UsedFontStyle) -> Result<FontHandle, ()> {
        match self.source {
            FontSourceMem(ref buf) => {
                FontHandleMethods::new_from_buffer(fctx, buf.clone(), style)
            }
            FontSourceFile(copy file) => {
                FontHandle::new_from_file(fctx, file, style)
            }
        }
    }

    pub fn glyph_index(&self,
                       codepoint: char) -> Option<GlyphIndex> {
        assert!(self.face.is_not_null());
        let idx = FT_Get_Char_Index(self.face, codepoint as FT_ULong);
        return if idx != 0 as FT_UInt {
            Some(idx as GlyphIndex)
        } else {
            debug!("Invalid codepoint: %?", codepoint);
            None
        };
    }

    pub fn glyph_h_advance(&self,
                           glyph: GlyphIndex) -> Option<FractionalPixel> {
        assert!(self.face.is_not_null());
        let res =  FT_Load_Glyph(self.face, glyph as FT_UInt, 0);
        if res.succeeded() {
            unsafe {
                let void_glyph = (*self.face).glyph;
                let slot: FT_GlyphSlot = cast::transmute(void_glyph);
                assert!(slot.is_not_null());
                debug!("metrics: %?", (*slot).metrics);
                let advance = (*slot).metrics.horiAdvance;
                debug!("h_advance for %? is %?", glyph, advance);
                let advance = advance as i32;
                return Some(fixed_to_float_ft(advance) as FractionalPixel);
            }
        } else {
            debug!("Unable to load glyph %?. reason: %?", glyph, res);
            return None;
        }
    }

    pub fn get_metrics(&self) -> FontMetrics {
        /* TODO(Issue #76): complete me */
        let face = self.get_face_rec();

        let underline_size = self.font_units_to_au(face.underline_thickness as float);
        let underline_offset = self.font_units_to_au(face.underline_position as float);
        let em_size = self.font_units_to_au(face.units_per_EM as float);
        let ascent = self.font_units_to_au(face.ascender as float);
        let descent = self.font_units_to_au(face.descender as float);
        let max_advance = self.font_units_to_au(face.max_advance_width as float);

        return FontMetrics {
            underline_size:   underline_size,
            underline_offset: underline_offset,
            leading:          geometry::from_pt(0.0), //FIXME
            x_height:         geometry::from_pt(0.0), //FIXME
            em_size:          em_size,
            ascent:           ascent,
            descent:          descent,
            max_advance:      max_advance
        }
    }

    fn get_table_for_tag(&self, _: FontTableTag) -> Option<FontTable> {
        None
    }
}

pub impl<'self> FontHandle {
    priv fn set_char_size(face: FT_Face, pt_size: float) -> Result<(), ()>{
        let char_width = float_to_fixed_ft(pt_size) as FT_F26Dot6;
        let char_height = float_to_fixed_ft(pt_size) as FT_F26Dot6;
        let h_dpi = 72;
        let v_dpi = 72;

        let result = FT_Set_Char_Size(face, char_width, char_height, h_dpi, v_dpi);
        if result.succeeded() { Ok(()) } else { Err(()) }
    }

    pub fn new_from_file(fctx: &FontContextHandle, file: ~str,
                         style: &SpecifiedFontStyle) -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let mut face: FT_Face = ptr::null();
        let face_index = 0 as FT_Long;
        do str::as_c_str(file) |file_str| {
            FT_New_Face(ft_ctx, file_str,
                        face_index, ptr::to_unsafe_ptr(&face));
        }
        if face.is_null() {
            return Err(());
        }
        if FontHandle::set_char_size(face, style.pt_size).is_ok() {
            Ok(FontHandle { source: FontSourceFile(file), face: face })
        } else {
            Err(())
        }
    }

    pub fn new_from_file_unstyled(fctx: &FontContextHandle, file: ~str)
                               -> Result<FontHandle, ()> {
        let ft_ctx: FT_Library = fctx.ctx.ctx;
        if ft_ctx.is_null() { return Err(()); }

        let mut face: FT_Face = ptr::null();
        let face_index = 0 as FT_Long;
        do str::as_c_str(file) |file_str| {
            FT_New_Face(ft_ctx, file_str,
                        face_index, ptr::to_unsafe_ptr(&face));
        }
        if face.is_null() {
            return Err(());
        }

        Ok(FontHandle { source: FontSourceFile(file), face: face })
    }

    priv fn get_face_rec(&'self self) -> &'self FT_FaceRec {
        unsafe {
            &(*self.face)
        }
    }

    priv fn font_units_to_au(&self, value: float) -> Au {
        let face = self.get_face_rec();

        // face.size is a *c_void in the bindings, presumably to avoid
        // recursive structural types
        let size: &FT_SizeRec = unsafe { cast::transmute(&(*face.size)) };
        let metrics: &FT_Size_Metrics = unsafe { &((*size).metrics) };

        let em_size = face.units_per_EM as float;
        let x_scale = (metrics.x_ppem as float) / em_size as float;

        // If this isn't true then we're scaling one of the axes wrong
        assert!(metrics.x_ppem == metrics.y_ppem);

        return geometry::from_frac_px(value * x_scale);
    }
}

<|endoftext|>


<commit_before>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::{BitSet, HashSet, VecMap};
use std::num::Int;

use constants::{BLOCK_SIZE, LINE_SIZE, NUM_LINES_PER_BLOCK};
use gc_object::GCObjectRef;

/// A per block object map.
struct ObjectMap {
    set: BitSet,
}

impl ObjectMap {
    /// Create a new `ObjectMap`.
    fn new() -> ObjectMap {
        return ObjectMap {
            set: BitSet::with_capacity(BLOCK_SIZE),
        };
    }

    /// Reduce the objects address to an offset within the block.
    fn index(object: GCObjectRef) -> usize {
        return (object as usize) % BLOCK_SIZE;
    }

    /// Set the address as a valid object.
    fn set_object(&mut self, object: GCObjectRef) {
        self.set.insert(ObjectMap::index(object));
    }

    /// Unset the address as a valid object.
    fn unset_object(&mut self, object: GCObjectRef) {
        self.set.remove(&ObjectMap::index(object));
    }

    /// Return `true` is the address is a valid object.
    fn is_object(&self, object: GCObjectRef) -> bool {
        return self.set.contains(&ObjectMap::index(object));
    }

    /// Update this `ObjectMap` with the difference of this `ObjectMap` and
    /// the other.
    fn difference(&mut self, other: &ObjectMap) {
        self.set.difference_with(&other.set);
    }

    /// Clear all entries.
    fn clear(&mut self) {
        self.set.clear();
    }

    /// Retrieve the values as a `HashSet`.
    fn as_hashset(&self, base: *mut u8) -> HashSet<GCObjectRef> {
        return self.set.iter()
                       .map(|i| unsafe{ base.offset(i as isize) as GCObjectRef})
                       .collect();
    }
}

/// A `BlockInfo` contains management information for the immix garbage
/// collectors.
///
/// It is the first bytes in a chunk of memory of size `BLOCK_SIZE` and must
/// not exeed `LINE_SIZE` bytes in size.
pub struct BlockInfo {
    /// A counter of live objects for every line in this block.
    line_counter: VecMap<u8>,

    /// A set of addresses that are valid objects. Needed for the conservative
    /// part.
    object_map: ObjectMap,

    /// Objects in this block that were never touched by the garbage
    /// collector.
    new_objects: ObjectMap,

    /// If this block is actually in use.
    allocated: bool,

    /// How many holen are in this block.
    hole_count: u8,

    /// If this block is a candidate for opportunistic evacuation.
    evacuation_candidate: bool,
}

impl BlockInfo {
    /// Create a new `BlockInfo`.
    pub fn new() -> BlockInfo {
        let mut line_counter = VecMap::with_capacity(NUM_LINES_PER_BLOCK);
        for index in (0..NUM_LINES_PER_BLOCK) {
            line_counter.insert(index, 0);
        }
        return BlockInfo {
            line_counter: line_counter,
            object_map: ObjectMap::new(),
            new_objects: ObjectMap::new(),
            allocated: false,
            hole_count: 0,
            evacuation_candidate: false,
        };
    }

    /// Set this block as allocated (actually in use).
    pub fn set_allocated(&mut self) {
        self.allocated = true;
    }

    /// Set an address in this block as a valid object.
    pub fn set_gc_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "set_gc_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.object_map.set_object(object);
    }

    /// Unset an address in this block as a valid object.
    pub fn unset_gc_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "unset_gc_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.object_map.unset_object(object);
    }

    /// Return if an address in this block is a valid object.
    pub fn is_gc_object(&self, object: GCObjectRef) -> bool {
        if self.is_in_block(object) {
            return self.object_map.is_object(object);
        }
        return false;
    }

    /// Get a copy of the object map.
    pub fn get_object_map(&mut self) -> HashSet<GCObjectRef> {
        return self.object_map.as_hashset(self as *mut BlockInfo as *mut u8);
    }

    /// Clear the object map.
    pub fn clear_object_map(&mut self) {
        self.object_map.clear();
    }

    /// Set an object in this block as new (not the `GCHeader.new` bit).
    pub fn set_new_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "set_new_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.new_objects.set_object(object);
    }

    /// Get the new objects in this block.
    pub fn get_new_objects(&mut self) -> HashSet<GCObjectRef> {
        return self.new_objects.as_hashset(self as *mut BlockInfo as *mut u8);
    }

    /// Remove all the new objects from the object map and clear the new
    /// objects set.
    pub fn remove_new_objects_from_map(&mut self) {
        self.object_map.difference(&self.new_objects);
        self.new_objects.clear();
    }

    /// Set as an evacuation candidate if this block has at least `hole_count`
    /// holes.
    pub fn set_evacuation_candidate(&mut self, hole_count: u8) {
        debug!("Set block {:p} to evacuation_candidate={} ({} holes)",
               &self, self.hole_count >= hole_count, self.hole_count);
        self.evacuation_candidate = self.hole_count >= hole_count;
    }

    /// Return if this is an evacuation candidate.
    pub fn is_evacuation_candidate(&self) -> bool{
        return self.evacuation_candidate;
    }

    /// Increment the lines on which the object is allocated.
    pub fn increment_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, true);
    }

    /// Decrement the lines on which the object is allocated.
    pub fn decrement_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, false);
    }

    /// Return the number of holes and marked lines in this block.
    ///
    /// A marked line is a line with a count of at least one.
    ///
    /// _Note_: You must call count_holes() bevorhand to set the number of
    /// holes.
    pub fn count_holes_and_marked_lines(&self) -> (u8, u8) {
        return (self.hole_count,
                self.line_counter.values().filter(|&e| *e != 0).count() as u8);
    }

    /// Return the number of holes and available lines in this block.
    ///
    /// An available line is a line with a count of zero.
    ///
    /// _Note_: You must call count_holes() bevorhand to set the number of
    /// holes.
    pub fn count_holes_and_available_lines(&self) -> (u8, u8) {
        return (self.hole_count,
                self.line_counter.values().filter(|&e| *e == 0).count() as u8);
    }

    /// Clear the line counter map.
    pub fn clear_line_counts(&mut self) {
        for index in (0..NUM_LINES_PER_BLOCK) {
            self.line_counter.insert(index, 0);
        }
    }

    /// Reset all member field for this block.
    pub fn reset(&mut self) {
        self.clear_line_counts();
        self.clear_object_map();
        self.allocated = false;
        self.hole_count = 0;
        self.evacuation_candidate = false;
    }

    /// Return true if no line is marked (every line has a count of zero).
    pub fn is_empty(&self) -> bool {
        return self.line_counter.values().all(|v| *v == 0);
    }

    /// Get a pointer to an address `offset` bytes into this block.
    pub fn offset(&mut self, offset: usize) -> GCObjectRef {
        let self_ptr = self as *mut BlockInfo;
        let object = unsafe { (self_ptr as *mut u8).offset(offset as isize) };
        return object as GCObjectRef;
    }

    /// Scan the block for a hole to allocate into.
    ///
    /// The scan will start at `last_high_offset` bytes into the block and
    /// return a tuple of `low_offset`, `high_offset` as the lowest and
    /// highest usable offsets for a hole.
    ///
    /// `None` is returned if no hole was found.
    pub fn scan_block(&self, last_high_offset: u16) -> Option<(u16, u16)> {
        let last_high_index = last_high_offset as usize / LINE_SIZE;
        debug!("Scanning block {:p} for a hole with last_high_offset {}",
               self, last_high_index);
        let mut low_index = NUM_LINES_PER_BLOCK - 1;
        for index in ((last_high_index + 1)..NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(true, |c| *c == 0) {
                // +1 to skip the next line in case an object straddles lines
                low_index = index + 1;
                break;
            }
        }
        let mut high_index = NUM_LINES_PER_BLOCK;
        for index in (low_index..NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(false, |c| *c != 0) {
                high_index = index;
                break;
            }
        }
        if low_index == high_index && high_index != (NUM_LINES_PER_BLOCK - 1) {
            debug!("Rescan: Found single line hole? in block {:p}", self);
            return self.scan_block((high_index * LINE_SIZE - 1) as u16);
        } else if low_index < (NUM_LINES_PER_BLOCK - 1) {
            debug!("Found low index {} and high index {} in block {:p}",
                   low_index, high_index, self);
            return Some(((low_index * LINE_SIZE) as u16,
                         (high_index * LINE_SIZE - 1) as u16));
        }
        debug!("Found no hole in block {:p}", self);
        return None;
    }

    /// Count the holes in this block.
    ///
    /// Holes are lines with no objects allocated.
    pub fn count_holes(&mut self) {
        let holes = self.line_counter.values()
            .fold((0, false), |(holes, in_hole), &elem|
                  match (in_hole, elem) {
                    (false, 0) => (holes + 1, true),
                    (_, _) => (holes, false),
                  }).0;
        self.hole_count = holes;
    }
}

impl BlockInfo{
    /// Returns true if this block is allocated and the address is within the
    /// bounds of this block.
    fn is_in_block(&self, object: GCObjectRef) -> bool {
        // This works because we get zeroed memory from the OS, so
        // self.allocated will be false if this block is not initialized and
        // this method gets only called for objects within the ImmixSpace.
        // After the first initialization the field is properly managed.
        if self.allocated {
            let self_ptr = self as *const BlockInfo as *const u8;
            let self_bound = unsafe{ self_ptr.offset(BLOCK_SIZE as isize)};
            return self_ptr < (object as *const u8)
                && (object as *const u8) <  self_bound;
        }
        return false;
    }

    /// Convert an address on this block into a line number.
    fn object_to_line_num(object: GCObjectRef) -> usize {
        return (object as usize % BLOCK_SIZE) / LINE_SIZE;
    }

    /// Update the line counter for the given object.
    ///
    /// Increment if `increment`, otherwise do a saturating substraction.
    fn update_line_nums(&mut self, object: GCObjectRef, increment: bool) {
        // This calculates how many lines are affected starting from a
        // LINE_SIZE aligned address. So it might not mark enough lines. But
        // that does not matter as we always skip a line in scan_block()
        let line_num = BlockInfo::object_to_line_num(object);
        let object_size = unsafe{ (*object).object_size() };
        for line in line_num..(line_num + (object_size / LINE_SIZE) + 1) {
            match increment {
                true => {
                    if self.line_counter.contains_key(&line) {
                        if let Some(val) = self.line_counter.get_mut(&line) {
                            *val += 1;
                        }
                    } else { self.line_counter.insert(line, 1); }
                    debug!("Incremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                },
                false => {
                    if self.line_counter.contains_key(&line) {
                        if let Some(val) = self.line_counter.get_mut(&line) {
                            *val = Int::saturating_sub(*val, 1);
                        }
                    } else { self.line_counter.insert(line, 0); }
                    debug!("Decremented line count for line {} to {}", line,
                           self.line_counter.get(&line).unwrap());
                }
            }
        }
    }
}
<commit_msg>Use Entry API for VecMap in BlockInfo<commit_after>// Copyright (c) <2015> <lummax>
// Licensed under MIT (http://opensource.org/licenses/MIT)

use std::collections::{BitSet, HashSet, VecMap};
use std::collections::vec_map::Entry;
use std::num::Int;

use constants::{BLOCK_SIZE, LINE_SIZE, NUM_LINES_PER_BLOCK};
use gc_object::GCObjectRef;

/// A per block object map.
struct ObjectMap {
    set: BitSet,
}

impl ObjectMap {
    /// Create a new `ObjectMap`.
    fn new() -> ObjectMap {
        return ObjectMap {
            set: BitSet::with_capacity(BLOCK_SIZE),
        };
    }

    /// Reduce the objects address to an offset within the block.
    fn index(object: GCObjectRef) -> usize {
        return (object as usize) % BLOCK_SIZE;
    }

    /// Set the address as a valid object.
    fn set_object(&mut self, object: GCObjectRef) {
        self.set.insert(ObjectMap::index(object));
    }

    /// Unset the address as a valid object.
    fn unset_object(&mut self, object: GCObjectRef) {
        self.set.remove(&ObjectMap::index(object));
    }

    /// Return `true` is the address is a valid object.
    fn is_object(&self, object: GCObjectRef) -> bool {
        return self.set.contains(&ObjectMap::index(object));
    }

    /// Update this `ObjectMap` with the difference of this `ObjectMap` and
    /// the other.
    fn difference(&mut self, other: &ObjectMap) {
        self.set.difference_with(&other.set);
    }

    /// Clear all entries.
    fn clear(&mut self) {
        self.set.clear();
    }

    /// Retrieve the values as a `HashSet`.
    fn as_hashset(&self, base: *mut u8) -> HashSet<GCObjectRef> {
        return self.set.iter()
                       .map(|i| unsafe{ base.offset(i as isize) as GCObjectRef})
                       .collect();
    }
}

/// A `BlockInfo` contains management information for the immix garbage
/// collectors.
///
/// It is the first bytes in a chunk of memory of size `BLOCK_SIZE` and must
/// not exeed `LINE_SIZE` bytes in size.
pub struct BlockInfo {
    /// A counter of live objects for every line in this block.
    line_counter: VecMap<u8>,

    /// A set of addresses that are valid objects. Needed for the conservative
    /// part.
    object_map: ObjectMap,

    /// Objects in this block that were never touched by the garbage
    /// collector.
    new_objects: ObjectMap,

    /// If this block is actually in use.
    allocated: bool,

    /// How many holen are in this block.
    hole_count: u8,

    /// If this block is a candidate for opportunistic evacuation.
    evacuation_candidate: bool,
}

impl BlockInfo {
    /// Create a new `BlockInfo`.
    pub fn new() -> BlockInfo {
        let mut line_counter = VecMap::with_capacity(NUM_LINES_PER_BLOCK);
        for index in (0..NUM_LINES_PER_BLOCK) {
            line_counter.insert(index, 0);
        }
        return BlockInfo {
            line_counter: line_counter,
            object_map: ObjectMap::new(),
            new_objects: ObjectMap::new(),
            allocated: false,
            hole_count: 0,
            evacuation_candidate: false,
        };
    }

    /// Set this block as allocated (actually in use).
    pub fn set_allocated(&mut self) {
        self.allocated = true;
    }

    /// Set an address in this block as a valid object.
    pub fn set_gc_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "set_gc_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.object_map.set_object(object);
    }

    /// Unset an address in this block as a valid object.
    pub fn unset_gc_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "unset_gc_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.object_map.unset_object(object);
    }

    /// Return if an address in this block is a valid object.
    pub fn is_gc_object(&self, object: GCObjectRef) -> bool {
        if self.is_in_block(object) {
            return self.object_map.is_object(object);
        }
        return false;
    }

    /// Get a copy of the object map.
    pub fn get_object_map(&mut self) -> HashSet<GCObjectRef> {
        return self.object_map.as_hashset(self as *mut BlockInfo as *mut u8);
    }

    /// Clear the object map.
    pub fn clear_object_map(&mut self) {
        self.object_map.clear();
    }

    /// Set an object in this block as new (not the `GCHeader.new` bit).
    pub fn set_new_object(&mut self, object: GCObjectRef) {
        debug_assert!(self.is_in_block(object),
            "set_new_object() on invalid block: {:p} (allocated={})",
            self, self.allocated);
        self.new_objects.set_object(object);
    }

    /// Get the new objects in this block.
    pub fn get_new_objects(&mut self) -> HashSet<GCObjectRef> {
        return self.new_objects.as_hashset(self as *mut BlockInfo as *mut u8);
    }

    /// Remove all the new objects from the object map and clear the new
    /// objects set.
    pub fn remove_new_objects_from_map(&mut self) {
        self.object_map.difference(&self.new_objects);
        self.new_objects.clear();
    }

    /// Set as an evacuation candidate if this block has at least `hole_count`
    /// holes.
    pub fn set_evacuation_candidate(&mut self, hole_count: u8) {
        debug!("Set block {:p} to evacuation_candidate={} ({} holes)",
               &self, self.hole_count >= hole_count, self.hole_count);
        self.evacuation_candidate = self.hole_count >= hole_count;
    }

    /// Return if this is an evacuation candidate.
    pub fn is_evacuation_candidate(&self) -> bool{
        return self.evacuation_candidate;
    }

    /// Increment the lines on which the object is allocated.
    pub fn increment_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, true);
    }

    /// Decrement the lines on which the object is allocated.
    pub fn decrement_lines(&mut self, object: GCObjectRef) {
        self.update_line_nums(object, false);
    }

    /// Return the number of holes and marked lines in this block.
    ///
    /// A marked line is a line with a count of at least one.
    ///
    /// _Note_: You must call count_holes() bevorhand to set the number of
    /// holes.
    pub fn count_holes_and_marked_lines(&self) -> (u8, u8) {
        return (self.hole_count,
                self.line_counter.values().filter(|&e| *e != 0).count() as u8);
    }

    /// Return the number of holes and available lines in this block.
    ///
    /// An available line is a line with a count of zero.
    ///
    /// _Note_: You must call count_holes() bevorhand to set the number of
    /// holes.
    pub fn count_holes_and_available_lines(&self) -> (u8, u8) {
        return (self.hole_count,
                self.line_counter.values().filter(|&e| *e == 0).count() as u8);
    }

    /// Clear the line counter map.
    pub fn clear_line_counts(&mut self) {
        for index in (0..NUM_LINES_PER_BLOCK) {
            self.line_counter.insert(index, 0);
        }
    }

    /// Reset all member field for this block.
    pub fn reset(&mut self) {
        self.clear_line_counts();
        self.clear_object_map();
        self.allocated = false;
        self.hole_count = 0;
        self.evacuation_candidate = false;
    }

    /// Return true if no line is marked (every line has a count of zero).
    pub fn is_empty(&self) -> bool {
        return self.line_counter.values().all(|v| *v == 0);
    }

    /// Get a pointer to an address `offset` bytes into this block.
    pub fn offset(&mut self, offset: usize) -> GCObjectRef {
        let self_ptr = self as *mut BlockInfo;
        let object = unsafe { (self_ptr as *mut u8).offset(offset as isize) };
        return object as GCObjectRef;
    }

    /// Scan the block for a hole to allocate into.
    ///
    /// The scan will start at `last_high_offset` bytes into the block and
    /// return a tuple of `low_offset`, `high_offset` as the lowest and
    /// highest usable offsets for a hole.
    ///
    /// `None` is returned if no hole was found.
    pub fn scan_block(&self, last_high_offset: u16) -> Option<(u16, u16)> {
        let last_high_index = last_high_offset as usize / LINE_SIZE;
        debug!("Scanning block {:p} for a hole with last_high_offset {}",
               self, last_high_index);
        let mut low_index = NUM_LINES_PER_BLOCK - 1;
        for index in ((last_high_index + 1)..NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(true, |c| *c == 0) {
                // +1 to skip the next line in case an object straddles lines
                low_index = index + 1;
                break;
            }
        }
        let mut high_index = NUM_LINES_PER_BLOCK;
        for index in (low_index..NUM_LINES_PER_BLOCK) {
            if self.line_counter.get(&index).map_or(false, |c| *c != 0) {
                high_index = index;
                break;
            }
        }
        if low_index == high_index && high_index != (NUM_LINES_PER_BLOCK - 1) {
            debug!("Rescan: Found single line hole? in block {:p}", self);
            return self.scan_block((high_index * LINE_SIZE - 1) as u16);
        } else if low_index < (NUM_LINES_PER_BLOCK - 1) {
            debug!("Found low index {} and high index {} in block {:p}",
                   low_index, high_index, self);
            return Some(((low_index * LINE_SIZE) as u16,
                         (high_index * LINE_SIZE - 1) as u16));
        }
        debug!("Found no hole in block {:p}", self);
        return None;
    }

    /// Count the holes in this block.
    ///
    /// Holes are lines with no objects allocated.
    pub fn count_holes(&mut self) {
        let holes = self.line_counter.values()
            .fold((0, false), |(holes, in_hole), &elem|
                  match (in_hole, elem) {
                    (false, 0) => (holes + 1, true),
                    (_, _) => (holes, false),
                  }).0;
        self.hole_count = holes;
    }
}

impl BlockInfo{
    /// Returns true if this block is allocated and the address is within the
    /// bounds of this block.
    fn is_in_block(&self, object: GCObjectRef) -> bool {
        // This works because we get zeroed memory from the OS, so
        // self.allocated will be false if this block is not initialized and
        // this method gets only called for objects within the ImmixSpace.
        // After the first initialization the field is properly managed.
        if self.allocated {
            let self_ptr = self as *const BlockInfo as *const u8;
            let self_bound = unsafe{ self_ptr.offset(BLOCK_SIZE as isize)};
            return self_ptr < (object as *const u8)
                && (object as *const u8) <  self_bound;
        }
        return false;
    }

    /// Convert an address on this block into a line number.
    fn object_to_line_num(object: GCObjectRef) -> usize {
        return (object as usize % BLOCK_SIZE) / LINE_SIZE;
    }

    /// Update the line counter for the given object.
    ///
    /// Increment if `increment`, otherwise do a saturating substraction.
    fn update_line_nums(&mut self, object: GCObjectRef, increment: bool) {
        // This calculates how many lines are affected starting from a
        // LINE_SIZE aligned address. So it might not mark enough lines. But
        // that does not matter as we always skip a line in scan_block()
        let line_num = BlockInfo::object_to_line_num(object);
        let object_size = unsafe{ (*object).object_size() };
        for line in line_num..(line_num + (object_size / LINE_SIZE) + 1) {
            match self.line_counter.entry(line) {
                Entry::Vacant(view) => { view.insert(if increment { 1 } else { 0 }); },
                Entry::Occupied(mut view) => {
                    let val = view.get_mut();
                    if increment {
                        *val += 1;
                    } else {
                        *val = Int::saturating_sub(*val, 1);
                    }
                }
            };
            if increment {
                debug!("Incremented line count for line {} to {}", line,
                       self.line_counter.get(&line).unwrap());
            } else {
                debug!("Decremented line count for line {} to {}", line,
                       self.line_counter.get(&line).unwrap());
            }
        }
    }
}
<|endoftext|>


<commit_before>// xfail-stage0

// These are attributes of the implicit crate. Really this just needs to parse
// for completeness since .rs files linked from .rc files support this
// notation to specify their module's attributes
#[attr1 = "val"];
#[attr2 = "val"];

// These are are attributes of the following mod
#[attr1 = "val"]
#[attr2 = "val"]
mod test_first_item_in_file_mod {
}

mod test_single_attr_outer {

    #[attr = "val"]
    const int x = 10;

    #[attr = "val"]
    fn f() {}

    #[attr = "val"]
    mod mod1 {
    }

    #[attr = "val"]
    native "rust" mod rustrt { }

    #[attr = "val"]
    type t = obj { };

    #[attr = "val"]
    obj o() { }
}

mod test_multi_attr_outer {

    #[attr1 = "val"]
    #[attr2 = "val"]
    const int x = 10;

    #[attr1 = "val"]
    #[attr2 = "val"]
    fn f() {}

    #[attr1 = "val"]
    #[attr2 = "val"]
    mod mod1 {
    }

    #[attr1 = "val"]
    #[attr2 = "val"]
    native "rust" mod rustrt { }

    #[attr1 = "val"]
    #[attr2 = "val"]
    type t = obj { };

    #[attr1 = "val"]
    #[attr2 = "val"]
    obj o() { }
}

mod test_stmt_single_attr_outer {

    fn f() {

        #[attr = "val"]
        const int x = 10;

        #[attr = "val"]
        fn f() {}

        /* FIXME: Issue #493
        #[attr = "val"]
        mod mod1 {
        }

        #[attr = "val"]
        native "rust" mod rustrt {
        }
        */

        #[attr = "val"]
        type t = obj { };

        #[attr = "val"]
        obj o() { }

    }
}

mod test_stmt_multi_attr_outer {

    fn f() {

        #[attr1 = "val"]
        #[attr2 = "val"]
        const int x = 10;

        #[attr1 = "val"]
        #[attr2 = "val"]
        fn f() {}

        /* FIXME: Issue #493
        #[attr1 = "val"]
        #[attr2 = "val"]
        mod mod1 {
        }

        #[attr1 = "val"]
        #[attr2 = "val"]
        native "rust" mod rustrt {
        }
        */

        #[attr1 = "val"]
        #[attr2 = "val"]
        type t = obj { };

        #[attr1 = "val"]
        #[attr2 = "val"]
        obj o() { }

    }
}

mod test_attr_inner {

    mod m {
        // This is an attribute of mod m
        #[attr = "val"];
    }
}

mod test_attr_inner_then_outer {

    mod m {
        // This is an attribute of mod m
        #[attr = "val"];
        // This is an attribute of fn f
        #[attr = "val"]
        fn f() {
        }
    }
}

mod test_attr_inner_then_outer_multi {
    mod m {
        // This is an attribute of mod m
        #[attr1 = "val"];
        #[attr2 = "val"];
        // This is an attribute of fn f
        #[attr1 = "val"]
        #[attr2 = "val"]
        fn f() {
        }
    }
}

fn main() {
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>test: Add a test for distinguishing attributes from extensions<commit_after>// xfail-stage0

// These are attributes of the implicit crate. Really this just needs to parse
// for completeness since .rs files linked from .rc files support this
// notation to specify their module's attributes
#[attr1 = "val"];
#[attr2 = "val"];

// These are are attributes of the following mod
#[attr1 = "val"]
#[attr2 = "val"]
mod test_first_item_in_file_mod {
}

mod test_single_attr_outer {

    #[attr = "val"]
    const int x = 10;

    #[attr = "val"]
    fn f() {}

    #[attr = "val"]
    mod mod1 {
    }

    #[attr = "val"]
    native "rust" mod rustrt { }

    #[attr = "val"]
    type t = obj { };

    #[attr = "val"]
    obj o() { }
}

mod test_multi_attr_outer {

    #[attr1 = "val"]
    #[attr2 = "val"]
    const int x = 10;

    #[attr1 = "val"]
    #[attr2 = "val"]
    fn f() {}

    #[attr1 = "val"]
    #[attr2 = "val"]
    mod mod1 {
    }

    #[attr1 = "val"]
    #[attr2 = "val"]
    native "rust" mod rustrt { }

    #[attr1 = "val"]
    #[attr2 = "val"]
    type t = obj { };

    #[attr1 = "val"]
    #[attr2 = "val"]
    obj o() { }
}

mod test_stmt_single_attr_outer {

    fn f() {

        #[attr = "val"]
        const int x = 10;

        #[attr = "val"]
        fn f() {}

        /* FIXME: Issue #493
        #[attr = "val"]
        mod mod1 {
        }

        #[attr = "val"]
        native "rust" mod rustrt {
        }
        */

        #[attr = "val"]
        type t = obj { };

        #[attr = "val"]
        obj o() { }

    }
}

mod test_stmt_multi_attr_outer {

    fn f() {

        #[attr1 = "val"]
        #[attr2 = "val"]
        const int x = 10;

        #[attr1 = "val"]
        #[attr2 = "val"]
        fn f() {}

        /* FIXME: Issue #493
        #[attr1 = "val"]
        #[attr2 = "val"]
        mod mod1 {
        }

        #[attr1 = "val"]
        #[attr2 = "val"]
        native "rust" mod rustrt {
        }
        */

        #[attr1 = "val"]
        #[attr2 = "val"]
        type t = obj { };

        #[attr1 = "val"]
        #[attr2 = "val"]
        obj o() { }

    }
}

mod test_attr_inner {

    mod m {
        // This is an attribute of mod m
        #[attr = "val"];
    }
}

mod test_attr_inner_then_outer {

    mod m {
        // This is an attribute of mod m
        #[attr = "val"];
        // This is an attribute of fn f
        #[attr = "val"]
        fn f() {
        }
    }
}

mod test_attr_inner_then_outer_multi {
    mod m {
        // This is an attribute of mod m
        #[attr1 = "val"];
        #[attr2 = "val"];
        // This is an attribute of fn f
        #[attr1 = "val"]
        #[attr2 = "val"]
        fn f() {
        }
    }
}

mod test_distinguish_syntax_ext {

    use std;

    fn f() {
        #fmt("test%s", "s");
        #[attr = "val"]
        fn g() {
        }
    }
}

fn main() {
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>// Copyright 2015 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.

// compile-flags: -C debug-assertions

// Check that we do *not* overflow on a number of edge cases.
// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)

fn main() {
    test_left_shift();
    test_right_shift();
}

fn test_left_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
            let x = (1 as $iN) << 0;
            assert_eq!(x, 1);
            let x = (1 as $uN) << 0;
            assert_eq!(x, 1);
            let x = (1 as $iN) << $max_rhs;
            assert_eq!(x, $expect_i);
            let x = (1 as $uN) << $max_rhs;
            assert_eq!(x, $expect_u);
            // high-order bits on LHS are silently discarded without panic.
            let x = (3 as $iN) << $max_rhs;
            assert_eq!(x, $expect_i);
            let x = (3 as $uN) << $max_rhs;
            assert_eq!(x, $expect_u);
        } }
    }

    let x = 1_i8 << 0;
    assert_eq!(x, 1);
    let x = 1_u8 << 0;
    assert_eq!(x, 1);
    let x = 1_i8 << 7;
    assert_eq!(x, std::i8::MIN);
    let x = 1_u8 << 7;
    assert_eq!(x, 0x80);
    // high-order bits on LHS are silently discarded without panic.
    let x = 3_i8 << 7;
    assert_eq!(x, std::i8::MIN);
    let x = 3_u8 << 7;
    assert_eq!(x, 0x80);

    // above is (approximately) expanded from:
    tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);

    tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
}

fn test_right_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr,
         $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
        { {
            let x = (1 as $iN) >> 0;
            assert_eq!(x, 1);
            let x = (1 as $uN) >> 0;
            assert_eq!(x, 1);
            let x = ($highbit_i) >> $max_rhs-1;
            assert_eq!(x, 1);
            let x = ($highbit_u) >> $max_rhs;
            assert_eq!(x, 1);
            // sign-bit is carried by arithmetic right shift
            let x = ($signbit_i) >> $max_rhs;
            assert_eq!(x, -1);
            // low-order bits on LHS are silently discarded without panic.
            let x = ($highbit_i + 1) >> $max_rhs-1;
            assert_eq!(x, 1);
            let x = ($highbit_u + 1) >> $max_rhs;
            assert_eq!(x, 1);
            let x = ($signbit_i + 1) >> $max_rhs;
            assert_eq!(x, -1);
        } }
    }

    tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
    tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN,
           0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
}
<commit_msg>Auto merge of #30085 - oli-obk:fix/pnkfelix_test, r=pnkfelix<commit_after>// Copyright 2015 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.

// compile-flags: -C debug-assertions

// Check that we do *not* overflow on a number of edge cases.
// (compare with test/run-fail/overflowing-{lsh,rsh}*.rs)

fn main() {
    test_left_shift();
    test_right_shift();
}

pub static mut HACK: i32 = 0;

// Work around constant-evaluation
// The point of this test is to exercise the code generated for execution at runtime,
// `id` can never be flagged as a const fn by future aggressive analyses...
// due to the modification of the static
#[inline(never)]
fn id<T>(x: T) -> T {
    unsafe { HACK += 1; }
    x
}

fn test_left_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr, $expect_i:expr, $expect_u:expr) => { {
            let x = (1 as $iN) << id(0);
            assert_eq!(x, 1);
            let x = (1 as $uN) << id(0);
            assert_eq!(x, 1);
            let x = (1 as $iN) << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = (1 as $uN) << id($max_rhs);
            assert_eq!(x, $expect_u);
            // high-order bits on LHS are silently discarded without panic.
            let x = (3 as $iN) << id($max_rhs);
            assert_eq!(x, $expect_i);
            let x = (3 as $uN) << id($max_rhs);
            assert_eq!(x, $expect_u);
        } }
    }

    let x = 1_i8 << id(0);
    assert_eq!(x, 1);
    let x = 1_u8 << id(0);
    assert_eq!(x, 1);
    let x = 1_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 1_u8 << id(7);
    assert_eq!(x, 0x80);
    // high-order bits on LHS are silently discarded without panic.
    let x = 3_i8 << id(7);
    assert_eq!(x, std::i8::MIN);
    let x = 3_u8 << id(7);
    assert_eq!(x, 0x80);

    // above is (approximately) expanded from:
    tests!(i8, u8, 7, std::i8::MIN, 0x80_u8);

    tests!(i16, u16, 15, std::i16::MIN, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN, 0x8000_0000_0000_0000_u64);
}

fn test_right_shift() {
    // negative rhs can panic, but values in [0,N-1] are okay for iN

    macro_rules! tests {
        ($iN:ty, $uN:ty, $max_rhs:expr,
         $signbit_i:expr, $highbit_i:expr, $highbit_u:expr) =>
        { {
            let x = (1 as $iN) >> id(0);
            assert_eq!(x, 1);
            let x = (1 as $uN) >> id(0);
            assert_eq!(x, 1);
            let x = ($highbit_i) >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = ($highbit_u) >> id($max_rhs);
            assert_eq!(x, 1);
            // sign-bit is carried by arithmetic right shift
            let x = ($signbit_i) >> id($max_rhs);
            assert_eq!(x, -1);
            // low-order bits on LHS are silently discarded without panic.
            let x = ($highbit_i + 1) >> id($max_rhs-1);
            assert_eq!(x, 1);
            let x = ($highbit_u + 1) >> id($max_rhs);
            assert_eq!(x, 1);
            let x = ($signbit_i + 1) >> id($max_rhs);
            assert_eq!(x, -1);
        } }
    }

    tests!(i8, u8, 7, std::i8::MIN, 0x40_i8, 0x80_u8);
    tests!(i16, u16, 15, std::i16::MIN, 0x4000_u16, 0x8000_u16);
    tests!(i32, u32, 31, std::i32::MIN, 0x4000_0000_u32, 0x8000_0000_u32);
    tests!(i64, u64, 63, std::i64::MIN,
           0x4000_0000_0000_0000_u64, 0x8000_0000_0000_0000_u64);
}
<|endoftext|>


<commit_before>//! This module is an attempt to provide a friendly, rust-esque interface to Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2)
//! and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// The input and output **Scope**s.
///
/// More info [here](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/constant_group/Audio_Unit_Scopes)
/// and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the **Input** and **Output** **Element**s.
///
/// These are used when specifying which **Element** we're setting the properties of.
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different kinds of Audio Units that are available.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

/// The number of frames available in some buffer.
pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
///
/// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

macro_rules! try_os_status {
    ($expr:expr) => (try!(Error::from_os_status($expr)))
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => return Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => component,
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            try_os_status!(au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit));
            // Initialise the audio unit!
            try_os_status!(au::AudioUnitInitialize(instance));
            Ok(AudioUnit {
                instance: instance,
                callback: None
            })
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { Box::from_raw(callback as *mut Box<RenderCallback>) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        unsafe {
            // Setup render callback. Notice that we relinquish ownership of the Callback
            // here so that it can be used as the C render callback via a void pointer.
            // We do however store the *mut so that we can convert back to a
            // Box<Box<RenderCallback>> within our AudioUnit's Drop implementation
            // (otherwise it would leak). The double-boxing is due to incompleteness with
            // Rust's FnMut implemetation and is necessary to be able to convert to the
            // correct pointer size.
            let callback_ptr = match f {
                Some(x) => Box::into_raw(Box::new(x)) as *mut libc::c_void,
                _ => ptr::null_mut()
            };
            let render_callback = au::AURenderCallbackStruct {
                inputProc: Some(input_proc),
                inputProcRefCon: callback_ptr
            };

            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32));

            self.free_render_callback();
            self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
            Ok(())
        }
    }

    /// Start the audio unit.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); }
        Ok(())
    }

    /// Stop the audio unit.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); }
        Ok(())
    }

    /// Set the audio unit's sample rate.
    pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> {
        unsafe {
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &sample_rate as *const _ as *const libc::c_void,
                mem::size_of::<f64>() as u32));
            Ok(())
        }
    }

    /// Get the audio unit's sample rate.
    pub fn sample_rate(&self) -> Result<f64, Error> {
        unsafe {
            let mut sample_rate: f64 = 0.0;
            let mut size: u32 = mem::size_of::<f64>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &mut sample_rate as *mut _ as *mut libc::c_void,
                &mut size as *mut _));
            Ok(sample_rate)
        }
    }

    /// Sets the current Stream Format for the AudioUnit.
    pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> {
        unsafe {
            let mut asbd = stream_format.to_asbd();
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                au::kAudioUnitScope_Input,
                0,
                &mut asbd as *mut _ as *mut libc::c_void,
                mem::size_of::<au::AudioStreamBasicDescription>() as u32));
            Ok(())
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> Result<StreamFormat, Error> {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                Scope::Output as libc::c_uint,
                Element::Output as libc::c_uint,
                &mut asbd as *mut _ as *mut libc::c_void,
                &mut size as *mut au::UInt32));
            Ok(StreamFormat::from_asbd(asbd))
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    // TODO: the size of this buffer needs to be calculated properly based on the stream format.
                    // Currently this won't be correct in at least this case:
                    /*
                    stream_format::StreamFormat {
                        sample_rate: 44100.0,
                        audio_format: audio_format::AudioFormat::LinearPCM(Some(audio_format::LinearPCMFlag::IsFloat)),
                        bytes_per_packet: 2 * 4,
                        frames_per_packet: 1,
                        bytes_per_frame: 2 * 4,
                        channels_per_frame: 2,
                        bits_per_channel: 32
                    }
                     */
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<commit_msg>Moved into_raw call into safe code<commit_after>//! This module is an attempt to provide a friendly, rust-esque interface to Apple's Audio Unit API.
//!
//! Learn more about the Audio Unit API [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40003278-CH1-SW2)
//! and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).

use bindings::audio_unit as au;
use error::{Error, AudioUnitError};
use libc;
use self::stream_format::StreamFormat;
use std::mem;
use std::ptr;

pub mod audio_format;
pub mod stream_format;

/// The input and output **Scope**s.
///
/// More info [here](https://developer.apple.com/library/ios/documentation/AudioUnit/Reference/AudioUnitPropertiesReference/index.html#//apple_ref/doc/constant_group/Audio_Unit_Scopes)
/// and [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
#[derive(Copy, Clone, Debug)]
pub enum Scope {
    Output = 0,
    Input  = 1,
}

/// Represents the **Input** and **Output** **Element**s.
///
/// These are used when specifying which **Element** we're setting the properties of.
#[derive(Copy, Clone, Debug)]
pub enum Element {
    Output = 0,
    Input  = 1,
}

/// Represents the different kinds of Audio Units that are available.
#[derive(Copy, Clone, Debug)]
pub enum Type {
    Output          = 1635086197,
    MusicDevice     = 1635085685,
    MusicEffect     = 1635085670,
    FormatConverter = 1635083875,
    Effect          = 1635083896,
    Mixer           = 1635085688,
    Panner          = 1635086446,
    Generator       = 1635084142,
    OfflineEffect   = 1635086188,
    MidiProcessor   = 1635085673,
}

/// Represents the different audio unit sub types.
#[derive(Copy, Clone, Debug)]
pub enum SubType {
    GenericOutput        = 1734700658,
    HalOutput            = 1634230636,
    DefaultOutput        = 1684366880,
    SystemOutput         = 1937339168,
    VoiceProcessingIO    = 1987078511,
    DLSSynth             = 1684828960,
    Sampler              = 1935764848,
    MIDISynth            = 1836284270,
    AUConverter          = 1668247158,
    Varispeed            = 1986097769,
    DeferredRenderer     = 1684366962,
    Splitter             = 1936747636,
    Merger               = 1835364967,
    NewTimePitch         = 1853191280,
    AUiPodTimeOther      = 1768977519,
    RoundTripAAC         = 1918984547,
    PeakLimiter          = 1819112562,
    DynamicsProcessor    = 1684237680,
    LowPassFilter        = 1819304307,
    HighPassFilter       = 1752195443,
    BandPassFilter       = 1651532147,
    HighShelfFilter      = 1752393830,
    LowShelfFilter       = 1819502694,
    ParametricEQ         = 1886217585,
    Distortion           = 1684632436,
    Delay                = 1684368505,
    SampleDelay          = 1935961209,
    GraphicEQ            = 1735550321,
    MultiBandCompressor  = 1835232624,
    MatrixReverb         = 1836213622,
    Pitch                = 1953329268,
    AUFilter             = 1718185076,
    NetSend              = 1853058660,
    RogerBeep            = 1919903602,
    NBandEQ              = 1851942257,
    MultiChannelMixer    = 1835232632,
    MatrixMixer          = 1836608888,
    SpatialMixer         = 862217581,
    StereoMixer          = 1936554098,
    Mixer3D              = 862219640,
    SphericalHeadPanner  = 1936746610,
    VectorPanner         = 1986158963,
    SoundFieldPanner     = 1634558569,
    HRTFPanner           = 1752331366,
    NetReceive           = 1852990326,
    ScheduledSoundPlayer = 1936945260,
    AudioFilePlayer      = 1634103404,
}

/// The number of frames available in some buffer.
pub type NumFrames = usize;

/// A type representing a render callback (aka "Input Procedure")
/// If set on an AudioUnit, this will be called every time the AudioUnit requests audio.
/// The first arg is [frames[channels]]; the second is the number of frames to render.
pub type RenderCallback = FnMut(&mut[&mut[f32]], NumFrames) -> Result<(), String>;

/// A rust representation of the au::AudioUnit, including a pointer to the current rendering callback.
///
/// Find the original Audio Unit Programming Guide [here](https://developer.apple.com/library/mac/documentation/MusicAudio/Conceptual/AudioUnitProgrammingGuide/TheAudioUnit/TheAudioUnit.html).
pub struct AudioUnit {
    instance: au::AudioUnit,
    callback: Option<*mut libc::c_void>
}

macro_rules! try_os_status {
    ($expr:expr) => (try!(Error::from_os_status($expr)))
}

impl AudioUnit {

    /// Construct a new AudioUnit.
    pub fn new(au_type: Type, sub_type: SubType) -> Result<AudioUnit, Error> {

        // A description of the audio unit we desire.
        let desc = au::AudioComponentDescription {
            componentType         : au_type as libc::c_uint,
            componentSubType      : sub_type as libc::c_uint,
            componentManufacturer : au::kAudioUnitManufacturer_Apple,
            componentFlags        : 0,
            componentFlagsMask    : 0,
        };

        unsafe {
            // Find the default audio unit for the description.
            let component = match au::AudioComponentFindNext(ptr::null_mut(), &desc as *const _) {
                component if component.is_null() => return Err(Error::NoMatchingDefaultAudioUnitFound),
                component                        => component,
            };

            // Get an instance of the default audio unit using the component.
            let mut instance: au::AudioUnit = mem::uninitialized();

            try_os_status!(au::AudioComponentInstanceNew(component, &mut instance as *mut au::AudioUnit));
            // Initialise the audio unit!
            try_os_status!(au::AudioUnitInitialize(instance));
            Ok(AudioUnit {
                instance: instance,
                callback: None
            })
        }
    }

    fn free_render_callback(&self) {
        if let Some(callback) = self.callback {
            // Here, we transfer ownership of the callback back to the current scope so that it
            // is dropped and cleaned up. Without this line, we would leak the Boxed callback.
            let _: Box<Box<RenderCallback>> = unsafe { Box::from_raw(callback as *mut Box<RenderCallback>) };
        }
    }

    /// Pass a render callback (aka "Input Procedure") to the audio unit.
    pub fn render_callback(&mut self, f: Option<Box<RenderCallback>>) -> Result<(), Error>
    {
        // Setup render callback. Notice that we relinquish ownership of the Callback
        // here so that it can be used as the C render callback via a void pointer.
        // We do however store the *mut so that we can convert back to a
        // Box<Box<RenderCallback>> within our AudioUnit's Drop implementation
        // (otherwise it would leak). The double-boxing is due to incompleteness with
        // Rust's FnMut implemetation and is necessary to be able to convert to the
        // correct pointer size.
        let callback_ptr = match f {
            Some(x) => Box::into_raw(Box::new(x)) as *mut libc::c_void,
            _ => ptr::null_mut()
        };
        let render_callback = au::AURenderCallbackStruct {
            inputProc: Some(input_proc),
            inputProcRefCon: callback_ptr
        };

        unsafe {
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SetRenderCallback,
                Scope::Input as libc::c_uint,
                Element::Output as libc::c_uint,
                &render_callback as *const _ as *const libc::c_void,
                mem::size_of::<au::AURenderCallbackStruct>() as u32));
        }

        self.free_render_callback();
        self.callback = if !callback_ptr.is_null() { Some(callback_ptr) } else { None };
        Ok(())
    }

    /// Start the audio unit.
    pub fn start(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStart(self.instance)); }
        Ok(())
    }

    /// Stop the audio unit.
    pub fn stop(&self) -> Result<(), Error> {
        unsafe { try_os_status!(au::AudioOutputUnitStop(self.instance)); }
        Ok(())
    }

    /// Set the audio unit's sample rate.
    pub fn set_sample_rate(&self, sample_rate: f64) -> Result<(), Error> {
        unsafe {
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &sample_rate as *const _ as *const libc::c_void,
                mem::size_of::<f64>() as u32));
            Ok(())
        }
    }

    /// Get the audio unit's sample rate.
    pub fn sample_rate(&self) -> Result<f64, Error> {
        unsafe {
            let mut sample_rate: f64 = 0.0;
            let mut size: u32 = mem::size_of::<f64>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_SampleRate,
                au::kAudioUnitScope_Input,
                0,
                &mut sample_rate as *mut _ as *mut libc::c_void,
                &mut size as *mut _));
            Ok(sample_rate)
        }
    }

    /// Sets the current Stream Format for the AudioUnit.
    pub fn set_stream_format(&self, stream_format: StreamFormat) -> Result<(), Error> {
        unsafe {
            let mut asbd = stream_format.to_asbd();
            try_os_status!(au::AudioUnitSetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                au::kAudioUnitScope_Input,
                0,
                &mut asbd as *mut _ as *mut libc::c_void,
                mem::size_of::<au::AudioStreamBasicDescription>() as u32));
            Ok(())
        }
    }

    /// Return the current Stream Format for the AudioUnit.
    pub fn stream_format(&self) -> Result<StreamFormat, Error> {
        unsafe {
            let mut asbd: au::AudioStreamBasicDescription = mem::uninitialized();
            let mut size = ::std::mem::size_of::<au::AudioStreamBasicDescription>() as u32;
            try_os_status!(au::AudioUnitGetProperty(
                self.instance,
                au::kAudioUnitProperty_StreamFormat,
                Scope::Output as libc::c_uint,
                Element::Output as libc::c_uint,
                &mut asbd as *mut _ as *mut libc::c_void,
                &mut size as *mut au::UInt32));
            Ok(StreamFormat::from_asbd(asbd))
        }
    }

}

impl Drop for AudioUnit {
    fn drop(&mut self) {
        unsafe {
            use error;
            use std::error::Error;
            if let Err(err) = self.stop() {
                panic!("{:?}", err.description());
            }
            if let Err(err) = error::Error::from_os_status(au::AudioUnitUninitialize(self.instance)) {
                panic!("{:?}", err.description());
            }
            self.free_render_callback();
        }
    }
}

/// Callback procedure that will be called each time our audio_unit requests audio.
extern "C" fn input_proc(in_ref_con: *mut libc::c_void,
                         _io_action_flags: *mut au::AudioUnitRenderActionFlags,
                         _in_time_stamp: *const au::AudioTimeStamp,
                         _in_bus_number: au::UInt32,
                         in_number_frames: au::UInt32,
                         io_data: *mut au::AudioBufferList) -> au::OSStatus {
    let callback: *mut Box<RenderCallback> = in_ref_con as *mut _;
    unsafe {
        let num_channels = (*io_data).mNumberBuffers as usize;

        // FIXME: We shouldn't need a Vec for this, it should probably be something like
        // `&[&mut [f32]]` instead.
        let mut channels: Vec<&mut [f32]> =
            (0..num_channels)
                .map(|i| {
                    let slice_ptr = (*io_data).mBuffers[i].mData as *mut libc::c_float;
                    // TODO: the size of this buffer needs to be calculated properly based on the stream format.
                    // Currently this won't be correct in at least this case:
                    /*
                    stream_format::StreamFormat {
                        sample_rate: 44100.0,
                        audio_format: audio_format::AudioFormat::LinearPCM(Some(audio_format::LinearPCMFlag::IsFloat)),
                        bytes_per_packet: 2 * 4,
                        frames_per_packet: 1,
                        bytes_per_frame: 2 * 4,
                        channels_per_frame: 2,
                        bits_per_channel: 32
                    }
                     */
                    ::std::slice::from_raw_parts_mut(slice_ptr, in_number_frames as usize)
                })
                .collect();

        match (*callback)(&mut channels[..], in_number_frames as usize) {
            Ok(()) => 0 as au::OSStatus,
            Err(description) => {
                use std::io::Write;
                writeln!(::std::io::stderr(), "{:?}", description).unwrap();
                AudioUnitError::NoConnection as au::OSStatus
            },
        }
    }
}
<|endoftext|>