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

use dom::audiobuffer::AudioBuffer;
use dom::audioparam::AudioParam;
use dom::audioscheduledsourcenode::AudioScheduledSourceNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceOptions;
use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::buffer_source_node::AudioBufferSourceNodeMessage;
use servo_media::audio::buffer_source_node::AudioBufferSourceNodeOptions;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit};
use servo_media::audio::param::ParamType;
use std::cell::Cell;
use std::f32;

#[dom_struct]
pub struct AudioBufferSourceNode {
    source_node: AudioScheduledSourceNode,
    buffer: MutNullableDom<AudioBuffer>,
    playback_rate: Dom<AudioParam>,
    detune: Dom<AudioParam>,
    loop_enabled: Cell<bool>,
    loop_start: Cell<f64>,
    loop_end: Cell<f64>,
}

impl AudioBufferSourceNode {
    #[allow(unrooted_must_root)]
    fn new_inherited(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<AudioBufferSourceNode> {
        let node_options = Default::default();
        let source_node = AudioScheduledSourceNode::new_inherited(
            AudioNodeInit::AudioBufferSourceNode(options.into()),
            context,
            node_options,
            0, /* inputs */
            1, /* outputs */
        )?;
        let node_id = source_node.node().node_id();
        let playback_rate = AudioParam::new(
            &window,
            context,
            node_id,
            ParamType::PlaybackRate,
            AutomationRate::K_rate,
            *options.playbackRate,
            f32::MIN,
            f32::MAX,
        );
        let detune = AudioParam::new(
            &window,
            context,
            node_id,
            ParamType::Detune,
            AutomationRate::K_rate,
            *options.detune,
            f32::MIN,
            f32::MAX,
        );
        let node = AudioBufferSourceNode {
            source_node,
            buffer: Default::default(),
            playback_rate: Dom::from_ref(&playback_rate),
            detune: Dom::from_ref(&detune),
            loop_enabled: Cell::new(options.loop_),
            loop_start: Cell::new(*options.loopStart),
            loop_end: Cell::new(*options.loopEnd),
        };
        if let Some(ref buffer) = options.buffer {
            if let Some(ref buffer) = buffer {
                if let Err(err) = node.SetBuffer(Some(&**buffer)) {
                    return Err(err);
                }
            }
        }
        Ok(node)
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
        let node = AudioBufferSourceNode::new_inherited(window, context, options)?;
        Ok(reflect_dom_object(
            Box::new(node),
            window,
            AudioBufferSourceNodeBinding::Wrap,
        ))
    }

    pub fn Constructor(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
        AudioBufferSourceNode::new(window, context, options)
    }
}

impl AudioBufferSourceNodeMethods for AudioBufferSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
    fn GetBuffer(&self) -> Fallible<Option<DomRoot<AudioBuffer>>> {
        Ok(self.buffer.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
    fn SetBuffer(&self, new_buffer: Option<&AudioBuffer>) -> Fallible<()> {
        if new_buffer.is_some() && self.buffer.get().is_some() {
            return Err(Error::InvalidState);
        }

        self.buffer.set(new_buffer);

        if self.source_node.started() {
            if let Some(buffer) = self.buffer.get() {
                let buffer = buffer.acquire_contents();
                if buffer.is_some() {
                    self.source_node
                        .node()
                        .message(AudioNodeMessage::AudioBufferSourceNode(
                            AudioBufferSourceNodeMessage::SetBuffer(buffer),
                        ));
                }
            }
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-playbackrate
    fn PlaybackRate(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.playback_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-detune
    fn Detune(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.detune)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loop
    fn Loop(&self) -> bool {
        self.loop_enabled.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loop
    fn SetLoop(&self, should_loop: bool) {
        self.loop_enabled.set(should_loop);
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
    fn LoopStart(&self) -> Finite<f64> {
        Finite::wrap(self.loop_start.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
    fn SetLoopStart(&self, loop_start: Finite<f64>) {
        self.loop_start.set(*loop_start);
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
    fn LoopEnd(&self) -> Finite<f64> {
        Finite::wrap(self.loop_end.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
    fn SetLoopEnd(&self, loop_end: Finite<f64>) {
        self.loop_end.set(*loop_end)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-start
    fn Start(
        &self,
        when: Finite<f64>,
        offset: Option<Finite<f64>>,
        duration: Option<Finite<f64>>,
    ) -> Fallible<()> {
        if *when < 0. {
            return Err(Error::Range("'when' must be a positive value".to_owned()));
        }

        if let Some(offset) = offset {
            if *offset < 0. {
                return Err(Error::Range("'offset' must be a positive value".to_owned()));
            }
        }

        if let Some(duration) = duration {
            if *duration < 0. {
                return Err(Error::Range(
                    "'duration' must be a positive value".to_owned(),
                ));
            }
        }

        if let Some(buffer) = self.buffer.get() {
            let buffer = buffer.acquire_contents();
            if buffer.is_some() {
                self.source_node
                    .node()
                    .message(AudioNodeMessage::AudioBufferSourceNode(
                        AudioBufferSourceNodeMessage::SetBuffer(buffer),
                    ));
            }
        }
        self.source_node
            .upcast::<AudioScheduledSourceNode>()
            .Start(when)
    }
}

impl<'a> From<&'a AudioBufferSourceOptions> for AudioBufferSourceNodeOptions {
    fn from(options: &'a AudioBufferSourceOptions) -> Self {
        Self {
            buffer: if let Some(ref buffer) = options.buffer {
                if let Some(ref buffer) = buffer {
                    Some(buffer.get_channels())
                } else {
                    None
                }
            } else {
                None
            },
            detune: *options.detune,
            loop_enabled: options.loop_,
            loop_end: Some(*options.loopEnd),
            loop_start: Some(*options.loopStart),
            playback_rate: *options.playbackRate,
        }
    }
}
<commit_msg>Use buffer_set flag for AudioBufferSourceNode buffer setter<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/. */

use dom::audiobuffer::AudioBuffer;
use dom::audioparam::AudioParam;
use dom::audioscheduledsourcenode::AudioScheduledSourceNode;
use dom::baseaudiocontext::BaseAudioContext;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceNodeMethods;
use dom::bindings::codegen::Bindings::AudioBufferSourceNodeBinding::AudioBufferSourceOptions;
use dom::bindings::codegen::Bindings::AudioParamBinding::AutomationRate;
use dom::bindings::codegen::Bindings::AudioScheduledSourceNodeBinding::AudioScheduledSourceNodeMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::reflector::reflect_dom_object;
use dom::bindings::root::{Dom, DomRoot, MutNullableDom};
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::buffer_source_node::AudioBufferSourceNodeMessage;
use servo_media::audio::buffer_source_node::AudioBufferSourceNodeOptions;
use servo_media::audio::node::{AudioNodeMessage, AudioNodeInit};
use servo_media::audio::param::ParamType;
use std::cell::Cell;
use std::f32;

#[dom_struct]
pub struct AudioBufferSourceNode {
    source_node: AudioScheduledSourceNode,
    buffer: MutNullableDom<AudioBuffer>,
    buffer_set: Cell<bool>,
    playback_rate: Dom<AudioParam>,
    detune: Dom<AudioParam>,
    loop_enabled: Cell<bool>,
    loop_start: Cell<f64>,
    loop_end: Cell<f64>,
}

impl AudioBufferSourceNode {
    #[allow(unrooted_must_root)]
    fn new_inherited(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<AudioBufferSourceNode> {
        let node_options = Default::default();
        let source_node = AudioScheduledSourceNode::new_inherited(
            AudioNodeInit::AudioBufferSourceNode(options.into()),
            context,
            node_options,
            0, /* inputs */
            1, /* outputs */
        )?;
        let node_id = source_node.node().node_id();
        let playback_rate = AudioParam::new(
            &window,
            context,
            node_id,
            ParamType::PlaybackRate,
            AutomationRate::K_rate,
            *options.playbackRate,
            f32::MIN,
            f32::MAX,
        );
        let detune = AudioParam::new(
            &window,
            context,
            node_id,
            ParamType::Detune,
            AutomationRate::K_rate,
            *options.detune,
            f32::MIN,
            f32::MAX,
        );
        let node = AudioBufferSourceNode {
            source_node,
            buffer: Default::default(),
            buffer_set: Cell::new(false),
            playback_rate: Dom::from_ref(&playback_rate),
            detune: Dom::from_ref(&detune),
            loop_enabled: Cell::new(options.loop_),
            loop_start: Cell::new(*options.loopStart),
            loop_end: Cell::new(*options.loopEnd),
        };
        if let Some(ref buffer) = options.buffer {
            if let Some(ref buffer) = buffer {
                if let Err(err) = node.SetBuffer(Some(&**buffer)) {
                    return Err(err);
                }
            }
        }
        Ok(node)
    }

    #[allow(unrooted_must_root)]
    pub fn new(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
        let node = AudioBufferSourceNode::new_inherited(window, context, options)?;
        Ok(reflect_dom_object(
            Box::new(node),
            window,
            AudioBufferSourceNodeBinding::Wrap,
        ))
    }

    pub fn Constructor(
        window: &Window,
        context: &BaseAudioContext,
        options: &AudioBufferSourceOptions,
    ) -> Fallible<DomRoot<AudioBufferSourceNode>> {
        AudioBufferSourceNode::new(window, context, options)
    }
}

impl AudioBufferSourceNodeMethods for AudioBufferSourceNode {
    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
    fn GetBuffer(&self) -> Fallible<Option<DomRoot<AudioBuffer>>> {
        Ok(self.buffer.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-buffer
    fn SetBuffer(&self, new_buffer: Option<&AudioBuffer>) -> Fallible<()> {
        if new_buffer.is_some() {
            if self.buffer_set.get() {
                // Step 2.
                return Err(Error::InvalidState);
            }
            // Step 3.
            self.buffer_set.set(true);
        }

        // Step 4.
        self.buffer.set(new_buffer);

        // Step 5.
        if self.source_node.started() {
            if let Some(buffer) = self.buffer.get() {
                let buffer = buffer.acquire_contents();
                if buffer.is_some() {
                    self.source_node
                        .node()
                        .message(AudioNodeMessage::AudioBufferSourceNode(
                            AudioBufferSourceNodeMessage::SetBuffer(buffer),
                        ));
                }
            }
        }

        Ok(())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-playbackrate
    fn PlaybackRate(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.playback_rate)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-detune
    fn Detune(&self) -> DomRoot<AudioParam> {
        DomRoot::from_ref(&self.detune)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loop
    fn Loop(&self) -> bool {
        self.loop_enabled.get()
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loop
    fn SetLoop(&self, should_loop: bool) {
        self.loop_enabled.set(should_loop);
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
    fn LoopStart(&self) -> Finite<f64> {
        Finite::wrap(self.loop_start.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopstart
    fn SetLoopStart(&self, loop_start: Finite<f64>) {
        self.loop_start.set(*loop_start);
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
    fn LoopEnd(&self) -> Finite<f64> {
        Finite::wrap(self.loop_end.get())
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-loopend
    fn SetLoopEnd(&self, loop_end: Finite<f64>) {
        self.loop_end.set(*loop_end)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiobuffersourcenode-start
    fn Start(
        &self,
        when: Finite<f64>,
        offset: Option<Finite<f64>>,
        duration: Option<Finite<f64>>,
    ) -> Fallible<()> {
        if *when < 0. {
            return Err(Error::Range("'when' must be a positive value".to_owned()));
        }

        if let Some(offset) = offset {
            if *offset < 0. {
                return Err(Error::Range("'offset' must be a positive value".to_owned()));
            }
        }

        if let Some(duration) = duration {
            if *duration < 0. {
                return Err(Error::Range(
                    "'duration' must be a positive value".to_owned(),
                ));
            }
        }

        if let Some(buffer) = self.buffer.get() {
            let buffer = buffer.acquire_contents();
            if buffer.is_some() {
                self.source_node
                    .node()
                    .message(AudioNodeMessage::AudioBufferSourceNode(
                        AudioBufferSourceNodeMessage::SetBuffer(buffer),
                    ));
            }
        }
        self.source_node
            .upcast::<AudioScheduledSourceNode>()
            .Start(when)
    }
}

impl<'a> From<&'a AudioBufferSourceOptions> for AudioBufferSourceNodeOptions {
    fn from(options: &'a AudioBufferSourceOptions) -> Self {
        Self {
            buffer: if let Some(ref buffer) = options.buffer {
                if let Some(ref buffer) = buffer {
                    Some(buffer.get_channels())
                } else {
                    None
                }
            } else {
                None
            },
            detune: *options.detune,
            loop_enabled: options.loop_,
            loop_end: Some(*options.loopEnd),
            loop_start: Some(*options.loopStart),
            playback_rate: *options.playbackRate,
        }
    }
}
<|endoftext|>


<commit_before>//! Renderer for type aliases.

use hir::{AsAssocItem, HasSource};
use ide_db::SymbolKind;
use syntax::{
    ast::{HasName, TypeAlias},
    display::type_label,
};

use crate::{item::CompletionItem, render::RenderContext};

pub(crate) fn render_type_alias(
    ctx: RenderContext<'_>,
    type_alias: hir::TypeAlias,
) -> Option<CompletionItem> {
    let _p = profile::span("render_type_alias");
    TypeAliasRender::new(ctx, type_alias)?.render(false)
}

pub(crate) fn render_type_alias_with_eq(
    ctx: RenderContext<'_>,
    type_alias: hir::TypeAlias,
) -> Option<CompletionItem> {
    let _p = profile::span("render_type_alias_with_eq");
    TypeAliasRender::new(ctx, type_alias)?.render(true)
}

#[derive(Debug)]
struct TypeAliasRender<'a> {
    ctx: RenderContext<'a>,
    type_alias: hir::TypeAlias,
    ast_node: TypeAlias,
}

impl<'a> TypeAliasRender<'a> {
    fn new(ctx: RenderContext<'a>, type_alias: hir::TypeAlias) -> Option<TypeAliasRender<'a>> {
        let ast_node = type_alias.source(ctx.db())?.value;
        Some(TypeAliasRender { ctx, type_alias, ast_node })
    }

    fn render(self, with_eq: bool) -> Option<CompletionItem> {
        let name = self.ast_node.name().map(|name| {
            if with_eq {
                format!("{} = ", name.text())
            } else {
                name.text().to_string()
            }
        })?;
        let detail = self.detail();

        let mut item =
            CompletionItem::new(SymbolKind::TypeAlias, self.ctx.source_range(), name.clone());
        item.set_documentation(self.ctx.docs(self.type_alias))
            .set_deprecated(
                self.ctx.is_deprecated(self.type_alias)
                    || self.ctx.is_deprecated_assoc_item(self.type_alias),
            )
            .detail(detail);

        let db = self.ctx.db();
        if let Some(actm) = self.type_alias.as_assoc_item(db) {
            if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
                item.trait_name(trt.name(db).to_smol_str());
                item.insert_text(name);
            }
        }

        Some(item.build())
    }

    fn detail(&self) -> String {
        type_label(&self.ast_node)
    }
}
<commit_msg>Simplify type alias rendering, remove constructor structs<commit_after>//! Renderer for type aliases.

use hir::{AsAssocItem, HasSource};
use ide_db::SymbolKind;
use syntax::{ast::HasName, display::type_label};

use crate::{item::CompletionItem, render::RenderContext};

pub(crate) fn render_type_alias(
    ctx: RenderContext<'_>,
    type_alias: hir::TypeAlias,
) -> Option<CompletionItem> {
    let _p = profile::span("render_type_alias");
    render(ctx, type_alias, false)
}

pub(crate) fn render_type_alias_with_eq(
    ctx: RenderContext<'_>,
    type_alias: hir::TypeAlias,
) -> Option<CompletionItem> {
    let _p = profile::span("render_type_alias_with_eq");
    render(ctx, type_alias, true)
}

fn render(
    ctx: RenderContext<'_>,
    type_alias: hir::TypeAlias,
    with_eq: bool,
) -> Option<CompletionItem> {
    let db = ctx.db();

    // FIXME: This parses the file!
    let ast_node = type_alias.source(db)?.value;
    let name = ast_node.name().map(|name| {
        if with_eq {
            format!("{} = ", name.text())
        } else {
            name.text().to_string()
        }
    })?;
    let detail = type_label(&ast_node);

    let mut item = CompletionItem::new(SymbolKind::TypeAlias, ctx.source_range(), name.clone());
    item.set_documentation(ctx.docs(type_alias))
        .set_deprecated(ctx.is_deprecated(type_alias) || ctx.is_deprecated_assoc_item(type_alias))
        .detail(detail);

    if let Some(actm) = type_alias.as_assoc_item(db) {
        if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
            item.trait_name(trt.name(db).to_smol_str());
            item.insert_text(name);
        }
    }

    Some(item.build())
}
<|endoftext|>


<commit_before>use std::io::Cursor;

use msgpack::Marker;
use msgpack::decode::*;

#[test]
fn from_fixstr_min_read_str_len() {
    let buf: &[u8] = &[0xa0];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_fixstr_rnd_read_str_len() {
    let buf: &[u8] = &[0xaa];
    let mut cur = Cursor::new(buf);

    assert_eq!(10, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_fixstr_max_read_str_len() {
    let buf: &[u8] = &[0xbf];
    let mut cur = Cursor::new(buf);

    assert_eq!(31, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_str8_min_read_str_len() {
    let buf: &[u8] = &[0xd9, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str8_rnd_read_str_len() {
    let buf: &[u8] = &[0xd9, 0x0a];
    let mut cur = Cursor::new(buf);

    assert_eq!(10, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str8_read_str_len_eof() {
    let buf: &[u8] = &[0xd9];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str8_max_read_str_len() {
    let buf: &[u8] = &[0xd9, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(255, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str16_min_read_str_len() {
    let buf: &[u8] = &[0xda, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(3, cur.position());
}

#[test]
fn from_str16_max_read_str_len() {
    let buf: &[u8] = &[0xda, 0xff, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(65535, read_str_len(&mut cur).unwrap());
    assert_eq!(3, cur.position());
}

#[test]
fn from_str16_read_str_len_eof() {
    let buf: &[u8] = &[0xda, 0x00];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(2, cur.position());
}

#[test]
fn from_str32_min_read_str_len() {
    let buf: &[u8] = &[0xdb, 0x00, 0x00, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(5, cur.position());
}

#[test]
fn from_str32_max_read_str_len() {
    let buf: &[u8] = &[0xdb, 0xff, 0xff, 0xff, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(4294967295, read_str_len(&mut cur).unwrap());
    assert_eq!(5, cur.position());
}

#[test]
fn from_str32_read_str_len_eof() {
    let buf: &[u8] = &[0xdb, 0x00, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(4, cur.position());
}

#[test]
fn from_null_read_str_len() {
    let buf: &[u8] = &[0xc0];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::TypeMismatch(Marker::Null)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str_strfix() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_extra_data() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x00];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_exact_buffer() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 10];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_insufficient_bytes() {
    // The buffer contains "le messag", which length is 9, but the total size endoded is 10.
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::InvalidDataCopy(actual, _)) => {
            assert_eq!(&[0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67], &actual[..]);
        },
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(10, cur.position());
}

#[test]
fn from_str_strfix_invalid_utf8() {
    // Invalid 2 Octet Sequence.
    let buf: &[u8] = &[0xa2, 0xc3, 0x28];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::InvalidUtf8(raw, _)) => {
            assert_eq!(&[0xc3, 0x28], raw);
        }
        other => panic!("unexpected result: {:?}", other)
    }

    assert_eq!(3, cur.position());
}

#[test]
fn from_str_strfix_buffer_too_small() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 9];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::BufferSizeTooSmall(10)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str_strfix_ref() {
    let buf = [0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];

    let out = read_str_ref(&buf[..]).unwrap();

    assert_eq!(10, out.len());
    assert!(buf[1..11] == out[0..10])
}
<commit_msg>[UT] API notice.<commit_after>use std::io::Cursor;

use msgpack::Marker;
use msgpack::decode::*;

#[test]
fn from_fixstr_min_read_str_len() {
    let buf: &[u8] = &[0xa0];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_fixstr_rnd_read_str_len() {
    let buf: &[u8] = &[0xaa];
    let mut cur = Cursor::new(buf);

    assert_eq!(10, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_fixstr_max_read_str_len() {
    let buf: &[u8] = &[0xbf];
    let mut cur = Cursor::new(buf);

    assert_eq!(31, read_str_len(&mut cur).unwrap());
    assert_eq!(1, cur.position());
}

#[test]
fn from_str8_min_read_str_len() {
    let buf: &[u8] = &[0xd9, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str8_rnd_read_str_len() {
    let buf: &[u8] = &[0xd9, 0x0a];
    let mut cur = Cursor::new(buf);

    assert_eq!(10, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str8_read_str_len_eof() {
    let buf: &[u8] = &[0xd9];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str8_max_read_str_len() {
    let buf: &[u8] = &[0xd9, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(255, read_str_len(&mut cur).unwrap());
    assert_eq!(2, cur.position());
}

#[test]
fn from_str16_min_read_str_len() {
    let buf: &[u8] = &[0xda, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(3, cur.position());
}

#[test]
fn from_str16_max_read_str_len() {
    let buf: &[u8] = &[0xda, 0xff, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(65535, read_str_len(&mut cur).unwrap());
    assert_eq!(3, cur.position());
}

#[test]
fn from_str16_read_str_len_eof() {
    let buf: &[u8] = &[0xda, 0x00];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(2, cur.position());
}

#[test]
fn from_str32_min_read_str_len() {
    let buf: &[u8] = &[0xdb, 0x00, 0x00, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    assert_eq!(0, read_str_len(&mut cur).unwrap());
    assert_eq!(5, cur.position());
}

#[test]
fn from_str32_max_read_str_len() {
    let buf: &[u8] = &[0xdb, 0xff, 0xff, 0xff, 0xff];
    let mut cur = Cursor::new(buf);

    assert_eq!(4294967295, read_str_len(&mut cur).unwrap());
    assert_eq!(5, cur.position());
}

#[test]
fn from_str32_read_str_len_eof() {
    let buf: &[u8] = &[0xdb, 0x00, 0x00, 0x00];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::InvalidDataRead(ReadError::UnexpectedEOF)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(4, cur.position());
}

#[test]
fn from_null_read_str_len() {
    let buf: &[u8] = &[0xc0];
    let mut cur = Cursor::new(buf);

    match read_str_len(&mut cur) {
        Err(ValueReadError::TypeMismatch(Marker::Null)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str_strfix() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_extra_data() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x00];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_exact_buffer() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 10];

    assert_eq!("le message", read_str(&mut cur, &mut out).unwrap());
    assert_eq!(11, cur.position());
}

#[test]
fn from_str_strfix_insufficient_bytes() {
    // The buffer contains "le messag", which length is 9, but the total size endoded is 10.
    // TODO: The result should be: InvalidDataCopy (EOF)
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::InvalidDataCopy(actual, _)) => {
            assert_eq!(&[0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67], &actual[..]);
        },
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(10, cur.position());
}

#[test]
fn from_str_strfix_invalid_utf8() {
    // Invalid 2 Octet Sequence.
    let buf: &[u8] = &[0xa2, 0xc3, 0x28];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 16];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::InvalidUtf8(raw, _)) => {
            assert_eq!(&[0xc3, 0x28], raw);
        }
        other => panic!("unexpected result: {:?}", other)
    }

    assert_eq!(3, cur.position());
}

#[test]
fn from_str_strfix_buffer_too_small() {
    let buf: &[u8] = &[0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];
    let mut cur = Cursor::new(buf);

    let mut out: &mut [u8] = &mut [0u8; 9];

    match read_str(&mut cur, &mut out) {
        Err(DecodeStringError::BufferSizeTooSmall(10)) => (),
        other => panic!("unexpected result: {:?}", other)
    }
    assert_eq!(1, cur.position());
}

#[test]
fn from_str_strfix_ref() {
    let buf = [0xaa, 0x6c, 0x65, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65];

    let out = read_str_ref(&buf[..]).unwrap();

    assert_eq!(10, out.len());
    assert!(buf[1..11] == out[0..10])
}
<|endoftext|>


<commit_before>use cargo_update::ops::get_index_path;
use std::path::{PathBuf, Path};
use std::fs::{self, File};
use std::time::Duration;
use std::thread::sleep;
use std::env::temp_dir;

#[test]
fn nonexistant() {
    let indices = prep_indices("nonexistant");

    assert_eq!(get_index_path(&indices), Err("index directory nonexistant"));
}

#[test]
fn empty() {
    let indices = prep_indices("empty");

    prepare_indices(&indices, &[]);

    assert_eq!(get_index_path(&indices), Err("empty index directory"));
}

#[test]
fn single() {
    let indices = prep_indices("single");

    prepare_indices(&indices, &["1ecc6299db9ec823"]);

    assert_eq!(get_index_path(&indices),
               Ok(indices.join("registry").join("index").join("github.com-1ecc6299db9ec823")));
}

#[test]
fn double() {
    let indices = prep_indices("double");

    prepare_indices(&indices, &["1ecc6299db9ec823", "48ad6e4054423464"]);

    assert_eq!(get_index_path(&indices),
               Ok(indices.join("registry").join("index").join("github.com-48ad6e4054423464")));
}

#[test]
fn triple() {
    let indices = prep_indices("triple");

    prepare_indices(&indices, &["1ecc6299db9ec823", "88ac128001ac3a9a", "48ad6e4054423464"]);

    assert_eq!(get_index_path(&indices),
               Ok(indices.join("registry").join("index").join("github.com-48ad6e4054423464")));
}

#[test]
fn with_file() {
    let indices = prep_indices("with_file");

    prepare_indices(&indices, &["1ecc6299db9ec823", "88ac128001ac3a9a"]);
    File::create(indices.join("registry").join("index").join("I-am-a-random-file-yes")).unwrap();

    assert_eq!(get_index_path(&indices),
               Ok(indices.join("registry").join("index").join("github.com-88ac128001ac3a9a")));
}

fn prep_indices(subname: &str) -> PathBuf {
    let mut td = temp_dir();
    let _ = fs::create_dir(&td);
    td.push("cargo_update-test");
    let _ = fs::create_dir(&td);
    td.push(format!("get_index_path-{}", subname));
    let _ = fs::create_dir(&td);
    td
}

fn prepare_indices(index: &Path, hashes: &[&str]) {
    let mut index = index.to_path_buf();
    index.push("registry");
    let _ = fs::create_dir(&index);
    index.push("index");
    let _ = fs::create_dir(&index);

    for hash in hashes {
        let _ = fs::create_dir(index.join(format!("github.com-{}", hash)));
        sleep(Duration::from_millis(10));
    }
}
<commit_msg>Fix tests<commit_after>use cargo_update::ops::get_index_path;
use std::path::{PathBuf, Path};
use std::fs::{self, File};
use std::time::Duration;
use std::thread::sleep;
use std::env::temp_dir;

#[test]
fn nonexistant() {
    let indices = prep_indices("nonexistant");

    assert_eq!(get_index_path(&indices, None), Err("index directory nonexistant"));
}

#[test]
fn empty() {
    let indices = prep_indices("empty");

    prepare_indices(&indices, &[]);

    assert_eq!(get_index_path(&indices, None), Err("empty index directory"));
}

#[test]
fn single() {
    let indices = prep_indices("single");

    prepare_indices(&indices, &["1ecc6299db9ec823"]);

    assert_eq!(get_index_path(&indices, None),
               Ok(indices.join("registry").join("index").join("github.com-1ecc6299db9ec823")));
}

#[test]
fn double() {
    let indices = prep_indices("double");

    prepare_indices(&indices, &["1ecc6299db9ec823", "48ad6e4054423464"]);

    assert_eq!(get_index_path(&indices, None),
               Ok(indices.join("registry").join("index").join("github.com-48ad6e4054423464")));
}

#[test]
fn triple() {
    let indices = prep_indices("triple");

    prepare_indices(&indices, &["1ecc6299db9ec823", "88ac128001ac3a9a", "48ad6e4054423464"]);

    assert_eq!(get_index_path(&indices, None),
               Ok(indices.join("registry").join("index").join("github.com-48ad6e4054423464")));
}

#[test]
fn with_file() {
    let indices = prep_indices("with_file");

    prepare_indices(&indices, &["1ecc6299db9ec823", "88ac128001ac3a9a"]);
    File::create(indices.join("registry").join("index").join("I-am-a-random-file-yes")).unwrap();

    assert_eq!(get_index_path(&indices, None),
               Ok(indices.join("registry").join("index").join("github.com-88ac128001ac3a9a")));
}

fn prep_indices(subname: &str) -> PathBuf {
    let mut td = temp_dir();
    let _ = fs::create_dir(&td);
    td.push("cargo_update-test");
    let _ = fs::create_dir(&td);
    td.push(format!("get_index_path-{}", subname));
    let _ = fs::create_dir(&td);
    td
}

fn prepare_indices(index: &Path, hashes: &[&str]) {
    let mut index = index.to_path_buf();
    index.push("registry");
    let _ = fs::create_dir(&index);
    index.push("index");
    let _ = fs::create_dir(&index);

    for hash in hashes {
        let _ = fs::create_dir(index.join(format!("github.com-{}", hash)));
        sleep(Duration::from_millis(10));
    }
}
<|endoftext|>


<commit_before>use std::env;

use crate::support::project;

#[test]
fn profile_overrides() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = 1
            debug = false
            rpath = true
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level=1 \
        -C debug-assertions=on \
        -C metadata=[..] \
        -C rpath \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] dev [optimized] target(s) in [..]
",
        )
        .run();
}

#[test]
fn opt_level_override_0() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = 0
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
        )
        .run();
}

#[test]
fn debug_override_1() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            debug = 1
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C debuginfo=1 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
        )
        .run();
}

fn check_opt_level_override(profile_level: &str, rustc_level: &str) {
    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = {level}
        "#,
                level = profile_level
            ),
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(&format!(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level={level} \
        -C debuginfo=2 \
        -C debug-assertions=on \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
            level = rustc_level
        ))
        .run();
}

#[test]
fn opt_level_overrides() {
    for &(profile_level, rustc_level) in &[
        ("1", "1"),
        ("2", "2"),
        ("3", "3"),
        ("\"s\"", "s"),
        ("\"z\"", "z"),
    ] {
        check_opt_level_override(profile_level, rustc_level)
    }
}

#[test]
fn top_level_overrides_deps() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.release]
            opt-level = 1
            debug = true

            [dependencies.foo]
            path = "foo"
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            "foo/Cargo.toml",
            r#"
            [package]

            name = "foo"
            version = "0.0.0"
            authors = []

            [profile.release]
            opt-level = 0
            debug = false

            [lib]
            name = "foo"
            crate_type = ["dylib", "rlib"]
        "#,
        )
        .file("foo/src/lib.rs", "")
        .build();
    p.cargo("build -v --release")
        .with_stderr(&format!(
            "\
[COMPILING] foo v0.0.0 ([CWD]/foo)
[RUNNING] `rustc --crate-name foo foo/src/lib.rs --color never \
        --crate-type dylib --crate-type rlib \
        --emit=[..]link \
        -C prefer-dynamic \
        -C opt-level=1 \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [CWD]/target/release/deps \
        -L dependency=[CWD]/target/release/deps`
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level=1 \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/release/deps \
        --extern foo=[CWD]/target/release/deps/\
                     {prefix}foo[..]{suffix} \
        --extern foo=[CWD]/target/release/deps/libfoo.rlib`
[FINISHED] release [optimized + debuginfo] target(s) in [..]
",
            prefix = env::consts::DLL_PREFIX,
            suffix = env::consts::DLL_SUFFIX
        ))
        .run();
}

#[test]
fn profile_in_non_root_manifest_triggers_a_warning() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [workspace]
            members = ["bar"]

            [profile.dev]
            debug = false
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []
            workspace = ".."

            [profile.dev]
            opt-level = 1
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -v")
        .cwd("bar")
        .with_stderr(
            "\
[WARNING] profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   [..]
workspace: [..]
[COMPILING] bar v0.1.0 ([..])
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized] target(s) in [..]",
        )
        .run();
}

#[test]
fn profile_in_virtual_manifest_works() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["bar"]

            [profile.dev]
            opt-level = 1
            debug = false
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []
            workspace = ".."
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -v")
        .cwd("bar")
        .with_stderr(
            "\
[COMPILING] bar v0.1.0 ([..])
[RUNNING] `rustc [..]`
[FINISHED] dev [optimized] target(s) in [..]",
        )
        .run();
}

#[test]
fn profile_panic_test_bench() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [profile.test]
            panic = "abort"

            [profile.bench]
            panic = "abort"
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build")
        .with_stderr_contains(
            "\
[WARNING] `panic` setting is ignored for `test` profile
[WARNING] `panic` setting is ignored for `bench` profile
",
        )
        .run();
}

#[test]
fn profile_doc_deprecated() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [profile.doc]
            opt-level = 0
            inherits = "dev"
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build")
        .with_stderr_contains("[WARNING] profile `doc` is deprecated and has no effect")
        .run();
}

#[test]
fn panic_unwind_does_not_build_twice() {
    // Check for a bug where `lib` was built twice, once with panic set and
    // once without. Since "unwind" is the default, they are the same and
    // should only be built once.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [profile.dev]
            panic = "unwind"
            "#,
        )
        .file("src/lib.rs", "")
        .file("src/main.rs", "fn main() {}")
        .file("tests/t1.rs", "")
        .build();

    p.cargo("test -v --tests --no-run")
        .with_stderr_unordered(
            "\
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..] --test [..]
[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin [..]
[RUNNING] `rustc --crate-name foo src/main.rs [..] --test [..]
[RUNNING] `rustc --crate-name t1 tests/t1.rs [..]
[FINISHED] [..]
",
        )
        .run();
}

#[test]
fn debug_0_report() {
    // The finished line handles 0 correctly.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [profile.dev]
            debug = 0
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C debuginfo=0 [..]
[FINISHED] dev [unoptimized] target(s) in [..]
",
        )
        .run();
}
<commit_msg>tests: adjust profiles::profile_panic_test_bench for sorted output<commit_after>use std::env;

use crate::support::project;

#[test]
fn profile_overrides() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = 1
            debug = false
            rpath = true
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level=1 \
        -C debug-assertions=on \
        -C metadata=[..] \
        -C rpath \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] dev [optimized] target(s) in [..]
",
        )
        .run();
}

#[test]
fn opt_level_override_0() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = 0
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
        )
        .run();
}

#[test]
fn debug_override_1() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            debug = 1
        "#,
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C debuginfo=1 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
        )
        .run();
}

fn check_opt_level_override(profile_level: &str, rustc_level: &str) {
    let p = project()
        .file(
            "Cargo.toml",
            &format!(
                r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.dev]
            opt-level = {level}
        "#,
                level = profile_level
            ),
        )
        .file("src/lib.rs", "")
        .build();
    p.cargo("build -v")
        .with_stderr(&format!(
            "\
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level={level} \
        -C debuginfo=2 \
        -C debug-assertions=on \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/debug/deps`
[FINISHED] [..] target(s) in [..]
",
            level = rustc_level
        ))
        .run();
}

#[test]
fn opt_level_overrides() {
    for &(profile_level, rustc_level) in &[
        ("1", "1"),
        ("2", "2"),
        ("3", "3"),
        ("\"s\"", "s"),
        ("\"z\"", "z"),
    ] {
        check_opt_level_override(profile_level, rustc_level)
    }
}

#[test]
fn top_level_overrides_deps() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]

            name = "test"
            version = "0.0.0"
            authors = []

            [profile.release]
            opt-level = 1
            debug = true

            [dependencies.foo]
            path = "foo"
        "#,
        )
        .file("src/lib.rs", "")
        .file(
            "foo/Cargo.toml",
            r#"
            [package]

            name = "foo"
            version = "0.0.0"
            authors = []

            [profile.release]
            opt-level = 0
            debug = false

            [lib]
            name = "foo"
            crate_type = ["dylib", "rlib"]
        "#,
        )
        .file("foo/src/lib.rs", "")
        .build();
    p.cargo("build -v --release")
        .with_stderr(&format!(
            "\
[COMPILING] foo v0.0.0 ([CWD]/foo)
[RUNNING] `rustc --crate-name foo foo/src/lib.rs --color never \
        --crate-type dylib --crate-type rlib \
        --emit=[..]link \
        -C prefer-dynamic \
        -C opt-level=1 \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [CWD]/target/release/deps \
        -L dependency=[CWD]/target/release/deps`
[COMPILING] test v0.0.0 ([CWD])
[RUNNING] `rustc --crate-name test src/lib.rs --color never --crate-type lib \
        --emit=[..]link \
        -C opt-level=1 \
        -C debuginfo=2 \
        -C metadata=[..] \
        --out-dir [..] \
        -L dependency=[CWD]/target/release/deps \
        --extern foo=[CWD]/target/release/deps/\
                     {prefix}foo[..]{suffix} \
        --extern foo=[CWD]/target/release/deps/libfoo.rlib`
[FINISHED] release [optimized + debuginfo] target(s) in [..]
",
            prefix = env::consts::DLL_PREFIX,
            suffix = env::consts::DLL_SUFFIX
        ))
        .run();
}

#[test]
fn profile_in_non_root_manifest_triggers_a_warning() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [project]
            name = "foo"
            version = "0.1.0"
            authors = []

            [workspace]
            members = ["bar"]

            [profile.dev]
            debug = false
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []
            workspace = ".."

            [profile.dev]
            opt-level = 1
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -v")
        .cwd("bar")
        .with_stderr(
            "\
[WARNING] profiles for the non root package will be ignored, specify profiles at the workspace root:
package:   [..]
workspace: [..]
[COMPILING] bar v0.1.0 ([..])
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized] target(s) in [..]",
        )
        .run();
}

#[test]
fn profile_in_virtual_manifest_works() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [workspace]
            members = ["bar"]

            [profile.dev]
            opt-level = 1
            debug = false
        "#,
        )
        .file("src/main.rs", "fn main() {}")
        .file(
            "bar/Cargo.toml",
            r#"
            [project]
            name = "bar"
            version = "0.1.0"
            authors = []
            workspace = ".."
        "#,
        )
        .file("bar/src/main.rs", "fn main() {}")
        .build();

    p.cargo("build -v")
        .cwd("bar")
        .with_stderr(
            "\
[COMPILING] bar v0.1.0 ([..])
[RUNNING] `rustc [..]`
[FINISHED] dev [optimized] target(s) in [..]",
        )
        .run();
}

#[test]
fn profile_panic_test_bench() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [profile.test]
            panic = "abort"

            [profile.bench]
            panic = "abort"
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build")
        .with_stderr_contains(
            "\
[WARNING] `panic` setting is ignored for `bench` profile
[WARNING] `panic` setting is ignored for `test` profile
",
        )
        .run();
}

#[test]
fn profile_doc_deprecated() {
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.0.1"

            [profile.doc]
            opt-level = 0
            inherits = "dev"
        "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build")
        .with_stderr_contains("[WARNING] profile `doc` is deprecated and has no effect")
        .run();
}

#[test]
fn panic_unwind_does_not_build_twice() {
    // Check for a bug where `lib` was built twice, once with panic set and
    // once without. Since "unwind" is the default, they are the same and
    // should only be built once.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [profile.dev]
            panic = "unwind"
            "#,
        )
        .file("src/lib.rs", "")
        .file("src/main.rs", "fn main() {}")
        .file("tests/t1.rs", "")
        .build();

    p.cargo("test -v --tests --no-run")
        .with_stderr_unordered(
            "\
[COMPILING] foo [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]--crate-type lib [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..] --test [..]
[RUNNING] `rustc --crate-name foo src/main.rs [..]--crate-type bin [..]
[RUNNING] `rustc --crate-name foo src/main.rs [..] --test [..]
[RUNNING] `rustc --crate-name t1 tests/t1.rs [..]
[FINISHED] [..]
",
        )
        .run();
}

#[test]
fn debug_0_report() {
    // The finished line handles 0 correctly.
    let p = project()
        .file(
            "Cargo.toml",
            r#"
            [package]
            name = "foo"
            version = "0.1.0"

            [profile.dev]
            debug = 0
            "#,
        )
        .file("src/lib.rs", "")
        .build();

    p.cargo("build -v")
        .with_stderr(
            "\
[COMPILING] foo v0.1.0 [..]
[RUNNING] `rustc --crate-name foo src/lib.rs [..]-C debuginfo=0 [..]
[FINISHED] dev [unoptimized] target(s) in [..]
",
        )
        .run();
}
<|endoftext|>


<commit_before>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use std::path::Path;
use std::fs::File;
use std::io::Read;

use proc_macro::TokenStream;

#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = {
        let src = syn_item.attrs.iter().filter_map(|attr| {
            match attr.value {
                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                    Some(val.clone())
                },
                _ => None
            }
        }).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");

        if Path::new(&src[..]).is_file() {
            let mut buf = String::new();
            File::open(src).and_then(|mut file| file.read_to_string(&mut buf)).expect("Unable to read source from given file");
            buf
        } else {
            src
        }
    };

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<commit_msg>Find path relative to Cargo.toml<commit_after>extern crate glsl_to_spirv;
extern crate proc_macro;
extern crate syn;
extern crate vulkano_shaders;

use std::path::Path;
use std::fs::File;
use std::io::Read;

use proc_macro::TokenStream;

#[proc_macro_derive(VulkanoShader, attributes(src, ty))]
pub fn derive(input: TokenStream) -> TokenStream {
    let syn_item = syn::parse_macro_input(&input.to_string()).unwrap();

    let src = {
        let src = syn_item.attrs.iter().filter_map(|attr| {
            match attr.value {
                syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "src" => {
                    Some(val.clone())
                },
                _ => None
            }
        }).next().expect("Can't find `src` attribute ; put #[src = \"...\"] for example.");

        let root = std::env::var("CARGO_MANIFEST_DIR").unwrap_or(".".into());
        let path = Path::new(&root).join(&src[..]);

        if path.is_file() {
            let mut buf = String::new();
            File::open(path).and_then(|mut file| file.read_to_string(&mut buf)).expect("Unable to read source from given file");
            buf
        } else {
            src
        }
    };

    let ty_str = syn_item.attrs.iter().filter_map(|attr| {
        match attr.value {
            syn::MetaItem::NameValue(ref i, syn::Lit::Str(ref val, _)) if i == "ty" => {
                Some(val.clone())
            },
            _ => None
        }
    }).next().expect("Can't find `ty` attribute ; put #[ty = \"vertex\"] for example.");

    let ty = match &ty_str[..] {
        "vertex" => glsl_to_spirv::ShaderType::Vertex,
        "fragment" => glsl_to_spirv::ShaderType::Fragment,
        "geometry" => glsl_to_spirv::ShaderType::Geometry,
        "tess_ctrl" => glsl_to_spirv::ShaderType::TessellationControl,
        "tess_eval" => glsl_to_spirv::ShaderType::TessellationEvaluation,
        "compute" => glsl_to_spirv::ShaderType::Compute,
        _ => panic!("Unexpected shader type ; valid values: vertex, fragment, geometry, tess_ctrl, tess_eval, compute")
    };

    let spirv_data = match glsl_to_spirv::compile(&src, ty) {
        Ok(compiled) => compiled,
        Err(message) => panic!("{}\nfailed to compile shader", message),
    };

    vulkano_shaders::reflect("Shader", spirv_data).unwrap().parse().unwrap()
}
<|endoftext|>


<commit_before>extern crate rustogram;
extern crate rustc_serialize;
static SERIALISED_FORM: &'static str = "HISTEwAAAAQAAAAAAAAABQAAAAABMS0AAAAAAAX14QA/8AAAAAAAAAAEBQI=";

use rustogram::encoding::*;
use rustogram::histogram::*;
use rustc_serialize::base64::*;

#[test]
fn test_zig_zag_encoding_for_single_value() {
	let mut buffer : Vec<u8> = Vec::new();

	let value: i64 = 982374923847239;
	encode(value, &mut buffer);

	let (decoded_value, bytes_read) = decode(&buffer, 0);
	assert_eq!(value, decoded_value);
	assert_eq!(8, bytes_read);
}

#[test]
fn test_zig_zag_encoding_for_multiple_values() {
	let mut buffer : Vec<u8> = Vec::new();

	let value0: i64 = 47;
	encode(value0, &mut buffer);

	let value1: i64 = 23746;
	encode(value1, &mut buffer);

	let (decoded_value0, bytes_read0) = decode(&buffer, 0);
	let (decoded_value1, bytes_read1) = decode(&buffer, bytes_read0);

	assert_eq!(value0, decoded_value0);
	assert_eq!(1, bytes_read0);

	assert_eq!(value1, decoded_value1);
	assert_eq!(3, bytes_read1);
}

#[ignore]
#[test]
fn test_deserialise() {
    let mut histogram = new_histogram_lower_bound(20000000, 100000000, 5);
    histogram.record_value(100000000);
    histogram.record_value(20000000);
    histogram.record_value(30000000);

	let byte_array = SERIALISED_FORM.from_base64().unwrap();

	let deserialised_histogram = deserialise_histogram(&byte_array).unwrap();

}<commit_msg>add limits test for long encoding<commit_after>extern crate rustogram;
extern crate rustc_serialize;
static SERIALISED_FORM: &'static str = "HISTEwAAAAQAAAAAAAAABQAAAAABMS0AAAAAAAX14QA/8AAAAAAAAAAEBQI=";

use rustogram::encoding::*;
use rustogram::histogram::*;
use rustc_serialize::base64::*;

#[test]
fn test_zig_zag_encoding_for_single_value() {
	let mut buffer : Vec<u8> = Vec::new();

	let value: i64 = 982374923847239;
	encode(value, &mut buffer);

	let (decoded_value, bytes_read) = decode(&buffer, 0);
	assert_eq!(value, decoded_value);
	assert_eq!(8, bytes_read);
}

#[test]
fn test_zig_zag_encoding_for_multiple_values() {
	let mut buffer : Vec<u8> = Vec::new();

	let value0: i64 = 47;
	encode(value0, &mut buffer);

	let value1: i64 = 23746;
	encode(value1, &mut buffer);

	let (decoded_value0, bytes_read0) = decode(&buffer, 0);
	let (decoded_value1, bytes_read1) = decode(&buffer, bytes_read0);

	assert_eq!(value0, decoded_value0);
	assert_eq!(1, bytes_read0);

	assert_eq!(value1, decoded_value1);
	assert_eq!(3, bytes_read1);
}

#[test]
fn test_zig_zag_encoding_for_limits() {
	let mut buffer : Vec<u8> = Vec::new();

	let value0: i64 = std::i64::MAX;
	encode(value0, &mut buffer);

	let value1: i64 = std::i64::MIN;
	encode(value1, &mut buffer);

	let (decoded_value0, bytes_read0) = decode(&buffer, 0);
	let (decoded_value1, bytes_read1) = decode(&buffer, bytes_read0);

	assert_eq!(value0, decoded_value0);
	assert_eq!(9, bytes_read0);

	assert_eq!(value1, decoded_value1);
	assert_eq!(9, bytes_read1);

}

#[ignore]
#[test]
fn test_deserialise() {
    let mut histogram = new_histogram_lower_bound(20000000, 100000000, 5);
    histogram.record_value(100000000);
    histogram.record_value(20000000);
    histogram.record_value(30000000);

	let byte_array = SERIALISED_FORM.from_base64().unwrap();

	let deserialised_histogram = deserialise_histogram(&byte_array).unwrap();

}<|endoftext|>


<commit_before>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide](https://developer.arm.com/docs/100067/0610)

#[cfg(test)]
use stdsimd_test::assert_instr;

/// This intrinsic inserts a BKPT instruction into the instruction stream generated by the compiler
///
/// It enables you to include a breakpoint instruction in your Rust code
///
/// `val` is a compile-time constant integer whose range is:
///
/// - `0...65535` if you are compiling source as A32 or A64 code.
/// - `0...255` if you are compiling source as T32 code.
///
/// [ARM's documentation](https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic)
///
/// **NOTE**: Due to compiler limitations this function only supports the range `0...255` in A32 and
/// A64 mode.
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    #[cfg(target_arch = "arm")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    #[cfg(target_arch = "aarch64")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
        }
    }

    // validate range
    assert!(val >= 0 && val <= 255);

    constify_imm8!(val, call);
}
<commit_msg>do not validate the argument to the __breakpoint intrinsic<commit_after>//! ARM compiler specific intrinsics
//!
//! # References
//!
//! - [ARM Compiler v 6.10 - armclang Reference Guide][arm_comp_ref]
//!
//! [arm_comp_ref]: https://developer.arm.com/docs/100067/0610

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Inserts a breakpoint instruction.
///
/// `val` is a compile-time constant integer in range `[0, 255]`.
///
/// The breakpoint instruction inserted is:
///
/// * `BKPT` when compiling as T32,
/// * `BRK` when compiling as A32 or A64.
///
/// # Safety
///
/// If `val` is out-of-range the behavior is **undefined**.
///
/// # Note
///
/// [ARM's documentation][arm_docs] defines that `__breakpoint` accepts the
/// following values for `val`:
///
/// - `0...65535` when compiling as A32 or A64,
/// - `0...255` when compiling as T32.
///
/// The current implementation only accepts values in range `[0, 255]` - if the
/// value is out-of-range the behavior is **undefined**.
///
/// [arm_docs]: https://developer.arm.com/docs/100067/latest/compiler-specific-intrinsics/__breakpoint-intrinsic
#[cfg_attr(all(test, target_arch = "arm"), assert_instr(bkpt, val = 0))]
#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(brk, val = 0))]
#[inline(always)]
#[rustc_args_required_const(0)]
pub unsafe fn __breakpoint(val: i32) {
    #[cfg(target_arch = "arm")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BKPT ", stringify!($imm8)) : : : : "volatile")
        }
    }

    #[cfg(target_arch = "aarch64")]
    macro_rules! call {
        ($imm8:expr) => {
            asm!(concat!("BRK ", stringify!($imm8)) : : : : "volatile")
        }
    }

    // We can't `panic!` inside this intrinsic, so we can't really validate the
    // arguments here. If `val` is out-of-range this macro uses `val == 255`:
    constify_imm8!(val, call);
}
<|endoftext|>


<commit_before>use crate::try_stream::TryStreamExt;
use core::pin::Pin;
use futures_core::stream::TryStream;
use futures_core::task::{Context, Poll};
use futures_io::{AsyncRead, AsyncBufRead};
use std::cmp;
use std::io::{Error, Result};

/// An `AsyncRead` for the [`into_async_read`](super::TryStreamExt::into_async_read) combinator.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    stream: St,
    state: ReadState<St::Ok>,
}

impl<St> Unpin for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
}

#[derive(Debug)]
enum ReadState<T: AsRef<[u8]>> {
    Ready { chunk: T, chunk_start: usize },
    PendingChunk,
    Eof,
}

impl<St> IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    pub(super) fn new(stream: St) -> Self {
        IntoAsyncRead {
            stream,
            state: ReadState::PendingChunk,
        }
    }
}

impl<St> AsyncRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        loop {
            match &mut self.state {
                ReadState::Ready { chunk, chunk_start } => {
                    let chunk = chunk.as_ref();
                    let len = cmp::min(buf.len(), chunk.len() - *chunk_start);

                    buf[..len].copy_from_slice(
                        &chunk[*chunk_start..*chunk_start + len],
                    );
                    *chunk_start += len;

                    if chunk.len() == *chunk_start {
                        self.state = ReadState::PendingChunk;
                    }

                    return Poll::Ready(Ok(len));
                }
                ReadState::PendingChunk => {
                    match ready!(self.stream.try_poll_next_unpin(cx)) {
                        Some(Ok(chunk)) => {
                            if !chunk.as_ref().is_empty() {
                                self.state = ReadState::Ready {
                                    chunk,
                                    chunk_start: 0,
                                };
                            }
                        }
                        Some(Err(err)) => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Err(err));
                        }
                        None => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Ok(0));
                        }
                    }
                }
                ReadState::Eof => {
                    return Poll::Ready(Ok(0));
                }
            }
        }
    }
}

impl<St> AsyncBufRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_fill_buf<'a>(
        mut self: Pin<&'a mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<&'a [u8]>> {
        while let ReadState::PendingChunk = self.state {
            match ready!(self.stream.try_poll_next_unpin(cx)) {
                Some(Ok(chunk)) => {
                    if !chunk.as_ref().is_empty() {
                        self.state = ReadState::Ready {
                            chunk,
                            chunk_start: 0,
                        };
                    }
                }
                Some(Err(err)) => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Err(err));
                }
                None => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Ok(&[]));
                }
            }
        }

        if let ReadState::Ready { ref chunk, chunk_start } = self.into_ref().get_ref().state {
            let chunk = chunk.as_ref();
            return Poll::Ready(Ok(&chunk[chunk_start..]));
        }

        // To get to this point we must be in ReadState::Eof
        Poll::Ready(Ok(&[]))
    }

    fn consume(
        mut self: Pin<&mut Self>,
        amount: usize,
    ) {
         // https://github.com/rust-lang-nursery/futures-rs/pull/1556#discussion_r281644295
        if amount == 0 { return }
        if let ReadState::Ready { chunk, chunk_start } = &mut self.state {
            *chunk_start += amount;
            debug_assert!(*chunk_start <= chunk.as_ref().len());
            if *chunk_start >= chunk.as_ref().len() {
                self.state = ReadState::PendingChunk;
            }
        } else {
            debug_assert!(false, "Attempted to consume from IntoAsyncRead without chunk");
        }
    }
}
<commit_msg>Add AsyncWrite implementation for IntoAsyncRead<commit_after>use crate::try_stream::TryStreamExt;
use core::pin::Pin;
use futures_core::stream::TryStream;
use futures_core::task::{Context, Poll};
use futures_io::{AsyncRead, AsyncWrite, AsyncBufRead};
use std::cmp;
use std::io::{Error, Result};

/// An `AsyncRead` for the [`into_async_read`](super::TryStreamExt::into_async_read) combinator.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    stream: St,
    state: ReadState<St::Ok>,
}

impl<St> Unpin for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
}

#[derive(Debug)]
enum ReadState<T: AsRef<[u8]>> {
    Ready { chunk: T, chunk_start: usize },
    PendingChunk,
    Eof,
}

impl<St> IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    pub(super) fn new(stream: St) -> Self {
        IntoAsyncRead {
            stream,
            state: ReadState::PendingChunk,
        }
    }
}

impl<St> AsyncRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut [u8],
    ) -> Poll<Result<usize>> {
        loop {
            match &mut self.state {
                ReadState::Ready { chunk, chunk_start } => {
                    let chunk = chunk.as_ref();
                    let len = cmp::min(buf.len(), chunk.len() - *chunk_start);

                    buf[..len].copy_from_slice(
                        &chunk[*chunk_start..*chunk_start + len],
                    );
                    *chunk_start += len;

                    if chunk.len() == *chunk_start {
                        self.state = ReadState::PendingChunk;
                    }

                    return Poll::Ready(Ok(len));
                }
                ReadState::PendingChunk => {
                    match ready!(self.stream.try_poll_next_unpin(cx)) {
                        Some(Ok(chunk)) => {
                            if !chunk.as_ref().is_empty() {
                                self.state = ReadState::Ready {
                                    chunk,
                                    chunk_start: 0,
                                };
                            }
                        }
                        Some(Err(err)) => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Err(err));
                        }
                        None => {
                            self.state = ReadState::Eof;
                            return Poll::Ready(Ok(0));
                        }
                    }
                }
                ReadState::Eof => {
                    return Poll::Ready(Ok(0));
                }
            }
        }
    }
}

impl<St> AsyncWrite for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + AsyncWrite + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8]
    ) -> Poll<Result<usize>> {
        Pin::new( &mut self.stream ).poll_write( cx, buf )
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Result<()>> {
        Pin::new( &mut self.stream ).poll_flush( cx )
    }

    fn poll_close(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>
    ) -> Poll<Result<()>> {
        Pin::new( &mut self.stream ).poll_close( cx )
    }
}

impl<St> AsyncBufRead for IntoAsyncRead<St>
where
    St: TryStream<Error = Error> + Unpin,
    St::Ok: AsRef<[u8]>,
{
    fn poll_fill_buf<'a>(
        mut self: Pin<&'a mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<&'a [u8]>> {
        while let ReadState::PendingChunk = self.state {
            match ready!(self.stream.try_poll_next_unpin(cx)) {
                Some(Ok(chunk)) => {
                    if !chunk.as_ref().is_empty() {
                        self.state = ReadState::Ready {
                            chunk,
                            chunk_start: 0,
                        };
                    }
                }
                Some(Err(err)) => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Err(err));
                }
                None => {
                    self.state = ReadState::Eof;
                    return Poll::Ready(Ok(&[]));
                }
            }
        }

        if let ReadState::Ready { ref chunk, chunk_start } = self.into_ref().get_ref().state {
            let chunk = chunk.as_ref();
            return Poll::Ready(Ok(&chunk[chunk_start..]));
        }

        // To get to this point we must be in ReadState::Eof
        Poll::Ready(Ok(&[]))
    }

    fn consume(
        mut self: Pin<&mut Self>,
        amount: usize,
    ) {
         // https://github.com/rust-lang-nursery/futures-rs/pull/1556#discussion_r281644295
        if amount == 0 { return }
        if let ReadState::Ready { chunk, chunk_start } = &mut self.state {
            *chunk_start += amount;
            debug_assert!(*chunk_start <= chunk.as_ref().len());
            if *chunk_start >= chunk.as_ref().len() {
                self.state = ReadState::PendingChunk;
            }
        } else {
            debug_assert!(false, "Attempted to consume from IntoAsyncRead without chunk");
        }
    }
}
<|endoftext|>


<commit_before>//! An implementation of a buddy allocator.

use core::ptr;
use core::mem;
use core::cmp;

use intrusive::link::Link;
use intrusive::list::{List, Node};

use Allocator;

pub type FreeBlock = PhantomNode;
pub type FreeList = List<ptr::Unique<FreeBlock>, FreeBlock>;

#[allow(dead_code)]
pub struct Buddy<'a> {
    min_block_size: usize,
    min_block_order: u32,
    max_order: u32,
    heap_base: *mut u8,
    free_lists: &'a mut [FreeList]
}

impl<'a> Buddy<'a> {
    pub unsafe fn new(mut r_start: usize, r_size: usize, min_block_size: usize,
                      max_order: u32,
                      free_lists: &'a mut [FreeList]) -> Self {
        let max_block_size = min_block_size * 2usize.pow(max_order);
        let r_limit = r_start + r_size;

        assert!(min_block_size >= ::core::mem::size_of::<FreeBlock>());

        let mut ret = Buddy {
            min_block_size: min_block_size,
            min_block_order: Buddy::log2(min_block_size) as u32,
            max_order: max_order,
            heap_base: r_start as *mut u8,
            free_lists: free_lists,
        };

        // This algorithm only deals with max block at init, so return an empty
        // allocator if the region is not big enough
        if r_size < max_block_size {
            return ret;
        }

        while r_start < r_limit {
            ret.add_block(max_order, r_start as *mut u8);

            r_start += max_block_size;
        }

        ret
    }

    #[allow(exceeding_bitshifts)]
    pub fn next_power_of_two(mut num: usize) -> usize {
        if num == 0 {
            return 1;
        }

        num -= 1;

        num |= num >> 1;
        num |= num >> 2;
        num |= num >> 4;
        num |= num >> 8;
        num |= num >> 16;

        if mem::size_of::<usize>() == mem::size_of::<u64>() {
            num |= num >> 32;
        }

        num + 1
    }

    pub fn log2(mut num: usize) -> usize {
        let mut res = 0;

        loop {
            num >>= 1;

            if num == 0 {
                break;
            }

            res += 1;
        }

        res
    }

    unsafe fn add_block(&mut self, order: u32, start: *mut u8) {
        let link = ptr::Unique::new(start as *mut FreeBlock);

        self.free_lists[order as usize].push_front(link);
    }

    unsafe fn split_block(&mut self, block: *mut u8, mut order: u32,
                          target_order: u32) {
        while order > target_order {
            order -= 1;

            let buddy_offset = self.get_size_from_order(order);
            let buddy_ptr = block.offset(buddy_offset as isize);

            self.add_block(order, buddy_ptr);
        }
    }

    unsafe fn find_and_pop_buddy(&mut self, ptr: *mut u8,
                                 order: u32) -> *mut u8{
        // Max order blocks are not merged
        if order == self.max_order {
            return ptr::null_mut();
        }

        let size = self.get_size_from_order(order);
        let ptr_from_base = ptr as usize - self.heap_base as usize;
        let buddy_ptr = self.heap_base.offset((ptr_from_base ^ size) as isize);
        let mut cursor = self.free_lists[order as usize].cursor();
        let mut found = false;

        loop {
            match cursor.next_peek() {
                None => break,
                Some(blk) => {
                    if blk as *const FreeBlock as *const u8 == buddy_ptr {
                        found = true;
                        break;
                    }
                }
            }

            cursor.next();
        }

        if found {
            cursor.remove();
            return buddy_ptr
        }

        ptr::null_mut()
    }

    fn get_order_from_size(&self, mut size: usize, _align: usize) -> u32 {
        size = Buddy::next_power_of_two(size);

        size = cmp::max(size, self.min_block_size);

        Buddy::log2(size) as u32 - self.min_block_order
    }

    fn get_size_from_order(&self, order: u32) -> usize {
        self.min_block_size * 2usize.pow(order)
    }
}

impl<'a> Allocator for Buddy<'a> {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> *mut u8 {
        let order = self.get_order_from_size(size, align);

        if order > self.max_order {
            return ptr::null_mut();
        }

        for i in order..(self.max_order + 1) {
            let mut tmp = self.free_lists[i as usize].pop_front();

            if let Some(block) = tmp.as_mut() {
                let ptr = block.get_mut() as *mut FreeBlock as *mut u8;

                if i > order {
                    self.split_block(ptr, i, order);
                }

                return ptr
            }
        }

        ptr::null_mut()
    }

    unsafe fn deallocate(&mut self, mut ptr: *mut u8, old_size: usize,
                         align: usize) {
        let mut order = self.get_order_from_size(old_size, align);

        loop {
            let buddy = self.find_and_pop_buddy(ptr, order);

            if buddy == ptr::null_mut() {
                break;
            }

            ptr = cmp::min(ptr, buddy);

            order += 1;
        }

        self.add_block(order, ptr);
    }
}

pub struct PhantomNode {
    prev: Link<PhantomNode>,
    next: Link<PhantomNode>,
}

impl Node for PhantomNode {
    fn prev(&self) -> &Link<PhantomNode> {
        &self.prev
    }

    fn next(&self) -> &Link<PhantomNode> {
        &self.next
    }

    fn prev_mut(&mut self) -> &mut Link<PhantomNode> {
        &mut self.prev
    }

    fn next_mut(&mut self) -> &mut Link<PhantomNode> {
        &mut self.next
    }
}

#[cfg(test)]
mod test {
    use core::mem;
    use core::ptr;

    use Allocator;

    use super::{Buddy, FreeList};

    const HEAP_ALIGN: usize = 4096;
    const HEAP_SIZE: usize = 4096;

    // HEAP_ORDER = 5 & MIN_BLOCK_SIZE = 32 => max alloc 1024
    const HEAP_ORDER: u32 = 5;
    const MIN_BLOCK_SIZE: usize = 32;

    extern "C" {
        fn memalign(alignment: usize, size: usize) -> *mut u8;
        fn free(ptr: *mut u8);
    }

    #[test]
    fn test_buddy_next_power_of_two() {
        assert_eq!(Buddy::next_power_of_two(0), 1);
        assert_eq!(Buddy::next_power_of_two(2), 2);
        assert_eq!(Buddy::next_power_of_two(3), 4);
        assert_eq!(Buddy::next_power_of_two(5678), 8192);
        assert_eq!(Buddy::next_power_of_two(8192), 8192);
    }

    #[test]
    fn test_buddy_log2() {
        assert_eq!(Buddy::log2(0), 0);
        assert_eq!(Buddy::log2(1), 0);
        assert_eq!(Buddy::log2(2), 1);
        assert_eq!(Buddy::log2(4), 2);
        assert_eq!(Buddy::log2(8), 3);
        assert_eq!(Buddy::log2(16), 4);
        assert_eq!(Buddy::log2(0x87654321), 31);
    }

    #[test]
    fn test_buddy_alloc_dealloc() {
        unsafe {
            let heap = memalign(HEAP_ALIGN, HEAP_SIZE);
            let mut free_lists: [_; (HEAP_ORDER + 1) as usize];

            free_lists = mem::uninitialized();

            for i in 0..(HEAP_ORDER + 1) {
                free_lists[i as usize] = FreeList::new();
            }

            let max_size = MIN_BLOCK_SIZE * 2usize.pow(HEAP_ORDER);

            let mut alloc = Buddy::new(heap as usize, HEAP_SIZE, MIN_BLOCK_SIZE,
                                       HEAP_ORDER, &mut free_lists[..]);

            // Allocation is too big
            assert_eq!(alloc.allocate(max_size + 1, 1), ptr::null_mut());

            {
                let max_blk = alloc.allocate(max_size, 1);
                let last_blk_offset = ((HEAP_SIZE / max_size) - 1) * max_size;

                // Due to Buddy::new using push front, the first allocated block
                // is gonna be the last pushed
                assert_eq!(max_blk, heap.offset(last_blk_offset as isize));

                alloc.deallocate(max_blk, max_size, 1);
            }

            let blk_32_1 = alloc.allocate(32, 1);
            let blk_32_2 = alloc.allocate(32, 1);

            assert_eq!(blk_32_1.offset(32), blk_32_2);

            let blk_64_1 = alloc.allocate(64, 1);

            assert_eq!(blk_32_1.offset(64), blk_64_1);

            alloc.deallocate(blk_32_1, 32, 1);
            alloc.deallocate(blk_32_2, 32, 1);

            let blk_32_1_1 = alloc.allocate(32, 1);
            let blk_32_2_1 = alloc.allocate(32, 1);

            assert_eq!(blk_32_1_1, blk_32_1);
            assert_eq!(blk_32_2_1, blk_32_2);

            alloc.deallocate(blk_32_2_1, 32, 1);
            alloc.deallocate(blk_32_1_1, 32, 1);

            let blk_64_2 = alloc.allocate(64, 1);

            assert_eq!(blk_64_2, blk_32_1);

            let blk_128 = alloc.allocate(128, 1);

            assert_eq!(blk_128, blk_64_1.offset(64));

            alloc.deallocate(blk_64_1, 64, 1);
            alloc.deallocate(blk_64_2, 64, 1);
            alloc.deallocate(blk_128, 128, 1);

            free(heap);
        }
    }
}
<commit_msg>heap: Fix a bug in the buddy system<commit_after>//! An implementation of a buddy allocator.

use core::ptr;
use core::mem;
use core::cmp;

use intrusive::link::Link;
use intrusive::list::{List, Node};

use Allocator;

pub type FreeBlock = PhantomNode;
pub type FreeList = List<ptr::Unique<FreeBlock>, FreeBlock>;

#[allow(dead_code)]
pub struct Buddy<'a> {
    min_block_size: usize,
    min_block_order: u32,
    max_order: u32,
    heap_base: *mut u8,
    free_lists: &'a mut [FreeList]
}

impl<'a> Buddy<'a> {
    pub unsafe fn new(mut r_start: usize, r_size: usize, min_block_size: usize,
                      max_order: u32,
                      free_lists: &'a mut [FreeList]) -> Self {
        let max_block_size = min_block_size * 2usize.pow(max_order);
        let r_limit = r_start + r_size;

        assert!(min_block_size >= ::core::mem::size_of::<FreeBlock>());

        let mut ret = Buddy {
            min_block_size: min_block_size,
            min_block_order: Buddy::log2(min_block_size) as u32,
            max_order: max_order,
            heap_base: r_start as *mut u8,
            free_lists: free_lists,
        };

        // This algorithm only deals with max block at init, so return an empty
        // allocator if the region is not big enough
        if r_size < max_block_size {
            return ret;
        }

        while r_start + max_block_size <= r_limit {
            ret.add_block(max_order, r_start as *mut u8);

            r_start += max_block_size;
        }

        ret
    }

    #[allow(exceeding_bitshifts)]
    pub fn next_power_of_two(mut num: usize) -> usize {
        if num == 0 {
            return 1;
        }

        num -= 1;

        num |= num >> 1;
        num |= num >> 2;
        num |= num >> 4;
        num |= num >> 8;
        num |= num >> 16;

        if mem::size_of::<usize>() == mem::size_of::<u64>() {
            num |= num >> 32;
        }

        num + 1
    }

    pub fn log2(mut num: usize) -> usize {
        let mut res = 0;

        loop {
            num >>= 1;

            if num == 0 {
                break;
            }

            res += 1;
        }

        res
    }

    unsafe fn add_block(&mut self, order: u32, start: *mut u8) {
        let link = ptr::Unique::new(start as *mut FreeBlock);

        self.free_lists[order as usize].push_front(link);
    }

    unsafe fn split_block(&mut self, block: *mut u8, mut order: u32,
                          target_order: u32) {
        while order > target_order {
            order -= 1;

            let buddy_offset = self.get_size_from_order(order);
            let buddy_ptr = block.offset(buddy_offset as isize);

            self.add_block(order, buddy_ptr);
        }
    }

    unsafe fn find_and_pop_buddy(&mut self, ptr: *mut u8,
                                 order: u32) -> *mut u8{
        // Max order blocks are not merged
        if order == self.max_order {
            return ptr::null_mut();
        }

        let size = self.get_size_from_order(order);
        let ptr_from_base = ptr as usize - self.heap_base as usize;
        let buddy_ptr = self.heap_base.offset((ptr_from_base ^ size) as isize);
        let mut cursor = self.free_lists[order as usize].cursor();
        let mut found = false;

        loop {
            match cursor.next_peek() {
                None => break,
                Some(blk) => {
                    if blk as *const FreeBlock as *const u8 == buddy_ptr {
                        found = true;
                        break;
                    }
                }
            }

            cursor.next();
        }

        if found {
            cursor.remove();
            return buddy_ptr
        }

        ptr::null_mut()
    }

    fn get_order_from_size(&self, mut size: usize, _align: usize) -> u32 {
        size = Buddy::next_power_of_two(size);

        size = cmp::max(size, self.min_block_size);

        Buddy::log2(size) as u32 - self.min_block_order
    }

    fn get_size_from_order(&self, order: u32) -> usize {
        self.min_block_size * 2usize.pow(order)
    }
}

impl<'a> Allocator for Buddy<'a> {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> *mut u8 {
        let order = self.get_order_from_size(size, align);

        if order > self.max_order {
            return ptr::null_mut();
        }

        for i in order..(self.max_order + 1) {
            let mut tmp = self.free_lists[i as usize].pop_front();

            if let Some(block) = tmp.as_mut() {
                let ptr = block.get_mut() as *mut FreeBlock as *mut u8;

                if i > order {
                    self.split_block(ptr, i, order);
                }

                return ptr
            }
        }

        ptr::null_mut()
    }

    unsafe fn deallocate(&mut self, mut ptr: *mut u8, old_size: usize,
                         align: usize) {
        let mut order = self.get_order_from_size(old_size, align);

        loop {
            let buddy = self.find_and_pop_buddy(ptr, order);

            if buddy == ptr::null_mut() {
                break;
            }

            ptr = cmp::min(ptr, buddy);

            order += 1;
        }

        self.add_block(order, ptr);
    }
}

pub struct PhantomNode {
    prev: Link<PhantomNode>,
    next: Link<PhantomNode>,
}

impl Node for PhantomNode {
    fn prev(&self) -> &Link<PhantomNode> {
        &self.prev
    }

    fn next(&self) -> &Link<PhantomNode> {
        &self.next
    }

    fn prev_mut(&mut self) -> &mut Link<PhantomNode> {
        &mut self.prev
    }

    fn next_mut(&mut self) -> &mut Link<PhantomNode> {
        &mut self.next
    }
}

#[cfg(test)]
mod test {
    use core::mem;
    use core::ptr;

    use Allocator;

    use super::{Buddy, FreeList};

    const HEAP_ALIGN: usize = 4096;
    const HEAP_SIZE: usize = 4096;

    // HEAP_ORDER = 5 & MIN_BLOCK_SIZE = 32 => max alloc 1024
    const HEAP_ORDER: u32 = 5;
    const MIN_BLOCK_SIZE: usize = 32;

    extern "C" {
        fn memalign(alignment: usize, size: usize) -> *mut u8;
        fn free(ptr: *mut u8);
    }

    #[test]
    fn test_buddy_next_power_of_two() {
        assert_eq!(Buddy::next_power_of_two(0), 1);
        assert_eq!(Buddy::next_power_of_two(2), 2);
        assert_eq!(Buddy::next_power_of_two(3), 4);
        assert_eq!(Buddy::next_power_of_two(5678), 8192);
        assert_eq!(Buddy::next_power_of_two(8192), 8192);
    }

    #[test]
    fn test_buddy_log2() {
        assert_eq!(Buddy::log2(0), 0);
        assert_eq!(Buddy::log2(1), 0);
        assert_eq!(Buddy::log2(2), 1);
        assert_eq!(Buddy::log2(4), 2);
        assert_eq!(Buddy::log2(8), 3);
        assert_eq!(Buddy::log2(16), 4);
        assert_eq!(Buddy::log2(0x87654321), 31);
    }

    #[test]
    fn test_buddy_alloc_dealloc() {
        unsafe {
            let heap = memalign(HEAP_ALIGN, HEAP_SIZE);
            let mut free_lists: [_; (HEAP_ORDER + 1) as usize];

            free_lists = mem::uninitialized();

            for i in 0..(HEAP_ORDER + 1) {
                free_lists[i as usize] = FreeList::new();
            }

            let max_size = MIN_BLOCK_SIZE * 2usize.pow(HEAP_ORDER);

            let mut alloc = Buddy::new(heap as usize, HEAP_SIZE, MIN_BLOCK_SIZE,
                                       HEAP_ORDER, &mut free_lists[..]);

            // Allocation is too big
            assert_eq!(alloc.allocate(max_size + 1, 1), ptr::null_mut());

            {
                let max_blk = alloc.allocate(max_size, 1);
                let last_blk_offset = ((HEAP_SIZE / max_size) - 1) * max_size;

                // Due to Buddy::new using push front, the first allocated block
                // is gonna be the last pushed
                assert_eq!(max_blk, heap.offset(last_blk_offset as isize));

                alloc.deallocate(max_blk, max_size, 1);
            }

            let blk_32_1 = alloc.allocate(32, 1);
            let blk_32_2 = alloc.allocate(32, 1);

            assert_eq!(blk_32_1.offset(32), blk_32_2);

            let blk_64_1 = alloc.allocate(64, 1);

            assert_eq!(blk_32_1.offset(64), blk_64_1);

            alloc.deallocate(blk_32_1, 32, 1);
            alloc.deallocate(blk_32_2, 32, 1);

            let blk_32_1_1 = alloc.allocate(32, 1);
            let blk_32_2_1 = alloc.allocate(32, 1);

            assert_eq!(blk_32_1_1, blk_32_1);
            assert_eq!(blk_32_2_1, blk_32_2);

            alloc.deallocate(blk_32_2_1, 32, 1);
            alloc.deallocate(blk_32_1_1, 32, 1);

            let blk_64_2 = alloc.allocate(64, 1);

            assert_eq!(blk_64_2, blk_32_1);

            let blk_128 = alloc.allocate(128, 1);

            assert_eq!(blk_128, blk_64_1.offset(64));

            alloc.deallocate(blk_64_1, 64, 1);
            alloc.deallocate(blk_64_2, 64, 1);
            alloc.deallocate(blk_128, 128, 1);

            free(heap);
        }
    }
}
<|endoftext|>