<commit_before>// TODO: Doc the rest

use core::{cmp, intrinsics, mem};
use core::ops::{Index, IndexMut};
use core::ptr;

use scheduler;

use common::paging::PAGE_END;

pub const CLUSTER_ADDRESS: usize = PAGE_END;
pub const CLUSTER_COUNT: usize = 1024 * 1024; // 4 GiB
pub const CLUSTER_SIZE: usize = 4096; // Of 4 K chunks

/// A wrapper around raw pointers
pub struct Memory<T> {
    pub ptr: *mut T,
}

impl<T> Memory<T> {
    /// Create an empty
    pub fn new(count: usize) -> Option<Self> {
        let alloc = unsafe { alloc(count * mem::size_of::<T>()) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    pub fn new_align(count: usize, align: usize) -> Option<Self> {
        let alloc = unsafe { alloc_aligned(count * mem::size_of::<T>(), align) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    /// Renew the memory
    pub fn renew(&mut self, count: usize) -> bool {
        let address = unsafe { realloc(self.ptr as usize, count * mem::size_of::<T>()) };
        if address > 0 {
            self.ptr = address as *mut T;
            true
        } else {
            false
        }
    }

    /// Get the size in bytes
    pub fn size(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) }
    }

    /// Get the length in T elements
    pub fn length(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) / mem::size_of::<T>() }
    }

    /// Get the address
    pub unsafe fn address(&self) -> usize {
        self.ptr as usize
    }

    /// Read the memory
    pub unsafe fn read(&self, i: usize) -> T {
        ptr::read(self.ptr.offset(i as isize))
    }

    /// Load the memory
    pub unsafe fn load(&self, i: usize) -> T {
        intrinsics::atomic_singlethreadfence();
        ptr::read(self.ptr.offset(i as isize))
    }

    /// Overwrite the memory
    pub unsafe fn write(&mut self, i: usize, value: T) {
        ptr::write(self.ptr.offset(i as isize), value);
    }

    /// Store the memory
    pub unsafe fn store(&mut self, i: usize, value: T) {
        intrinsics::atomic_singlethreadfence();
        ptr::write(self.ptr.offset(i as isize), value)
    }

    /// Convert into a raw pointer
    pub unsafe fn into_raw(&mut self) -> *mut T {
        let ptr = self.ptr;
        self.ptr = 0 as *mut T;
        ptr
    }
}

impl<T> Drop for Memory<T> {
    fn drop(&mut self) {
        if self.ptr as usize > 0 {
            unsafe { unalloc(self.ptr as usize) };
        }
    }
}

impl<T> Index<usize> for Memory<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: usize) -> &'a T {
        unsafe { &*self.ptr.offset(_index as isize) }
    }
}

impl<T> IndexMut<usize> for Memory<T> {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut T {
        unsafe { &mut *self.ptr.offset(_index as isize) }
    }
}

/// A memory map entry
#[repr(packed)]
struct MemoryMapEntry {
    base: u64,
    len: u64,
    class: u32,
    acpi: u32,
}

const MEMORY_MAP: *const MemoryMapEntry = 0x500 as *const MemoryMapEntry;

pub unsafe fn cluster(number: usize) -> usize {
    if number < CLUSTER_COUNT {
        ptr::read((CLUSTER_ADDRESS + number * mem::size_of::<usize>()) as *const usize)
    } else {
        0
    }
}

pub unsafe fn set_cluster(number: usize, address: usize) {
    if number < CLUSTER_COUNT {
        ptr::write((CLUSTER_ADDRESS + number * mem::size_of::<usize>()) as *mut usize,
                   address);
    }
}

pub unsafe fn address_to_cluster(address: usize) -> usize {
    if address >= CLUSTER_ADDRESS + CLUSTER_COUNT * mem::size_of::<usize>() {
        (address - CLUSTER_ADDRESS - CLUSTER_COUNT * mem::size_of::<usize>()) / CLUSTER_SIZE
    } else {
        0
    }
}

pub unsafe fn cluster_to_address(number: usize) -> usize {
    CLUSTER_ADDRESS + CLUSTER_COUNT * mem::size_of::<usize>() + number * CLUSTER_SIZE
}

pub unsafe fn cluster_init() {
    // First, set all clusters to the not present value
    for cluster in 0..CLUSTER_COUNT {
        set_cluster(cluster, 0xFFFFFFFF);
    }

    // Next, set all valid clusters to the free value
    // TODO: Optimize this function
    for i in 0..((0x5000 - 0x500) / mem::size_of::<MemoryMapEntry>()) {
        let entry = &*MEMORY_MAP.offset(i as isize);
        if entry.len > 0 && entry.class == 1 {
            for cluster in 0..CLUSTER_COUNT {
                let address = cluster_to_address(cluster);
                if address as u64 >= entry.base &&
                   (address as u64 + CLUSTER_SIZE as u64) <= (entry.base + entry.len) {
                    set_cluster(cluster, 0);
                }
            }
        }
    }
}

/// Allocate memory
pub unsafe fn alloc(size: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            ::memset(address as *mut u8, 0, count * CLUSTER_SIZE);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_aligned(size: usize, align: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 && (count > 0 || cluster_to_address(i) % align == 0) {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            ::memset(address as *mut u8, 0, count * CLUSTER_SIZE);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_type<T>() -> *mut T {
    alloc(mem::size_of::<T>()) as *mut T
}

pub unsafe fn alloc_size(ptr: usize) -> usize {
    let mut size = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                size += CLUSTER_SIZE;
            } else {
                break;
            }
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    size
}

pub unsafe fn unalloc(ptr: usize) {
    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                set_cluster(i, 0);
            } else {
                break;
            }
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);
}

pub unsafe fn realloc(ptr: usize, size: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size == 0 {
        if ptr > 0 {
            unalloc(ptr);
        }
    } else {
        let old_size = alloc_size(ptr);
        if size <= old_size {
            ret = ptr;
        } else {
            ret = alloc(size);
            if ptr > 0 {
                if ret > 0 {
                    let copy_size = cmp::min(old_size, size);

                    ::memmove(ret as *mut u8, ptr as *const u8, copy_size);
                }
                unalloc(ptr);
            }
        }
    }

    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn realloc_inplace(ptr: usize, size: usize) -> usize {
    let old_size = alloc_size(ptr);
    if size <= old_size {
        size
    } else {
        old_size
    }
}

pub fn memory_used() -> usize {
    let mut ret = 0;
    unsafe {
        // Memory allocation must be atomic
        let reenable = scheduler::start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) != 0 && cluster(i) != 0xFFFFFFFF {
                ret += CLUSTER_SIZE;
            }
        }

        // Memory allocation must be atomic
        scheduler::end_no_ints(reenable);
    }
    ret
}

pub fn memory_free() -> usize {
    let mut ret = 0;
    unsafe {
        // Memory allocation must be atomic
        let reenable = scheduler::start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                ret += CLUSTER_SIZE;
            }
        }

        // Memory allocation must be atomic
        scheduler::end_no_ints(reenable);
    }
    ret
}
<commit_msg>Speed up the memory management by not zeroing out on alloc<commit_after>// TODO: Doc the rest

use core::{cmp, intrinsics, mem};
use core::ops::{Index, IndexMut};
use core::ptr;

use scheduler;

use common::paging::PAGE_END;

pub const CLUSTER_ADDRESS: usize = PAGE_END;
pub const CLUSTER_COUNT: usize = 1024 * 1024; // 4 GiB
pub const CLUSTER_SIZE: usize = 4096; // Of 4 K chunks

/// A wrapper around raw pointers
pub struct Memory<T> {
    pub ptr: *mut T,
}

impl<T> Memory<T> {
    /// Create an empty
    pub fn new(count: usize) -> Option<Self> {
        let alloc = unsafe { alloc(count * mem::size_of::<T>()) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    pub fn new_align(count: usize, align: usize) -> Option<Self> {
        let alloc = unsafe { alloc_aligned(count * mem::size_of::<T>(), align) };
        if alloc > 0 {
            Some(Memory { ptr: alloc as *mut T })
        } else {
            None
        }
    }

    /// Renew the memory
    pub fn renew(&mut self, count: usize) -> bool {
        let address = unsafe { realloc(self.ptr as usize, count * mem::size_of::<T>()) };
        if address > 0 {
            self.ptr = address as *mut T;
            true
        } else {
            false
        }
    }

    /// Get the size in bytes
    pub fn size(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) }
    }

    /// Get the length in T elements
    pub fn length(&self) -> usize {
        unsafe { alloc_size(self.ptr as usize) / mem::size_of::<T>() }
    }

    /// Get the address
    pub unsafe fn address(&self) -> usize {
        self.ptr as usize
    }

    /// Read the memory
    pub unsafe fn read(&self, i: usize) -> T {
        ptr::read(self.ptr.offset(i as isize))
    }

    /// Load the memory
    pub unsafe fn load(&self, i: usize) -> T {
        intrinsics::atomic_singlethreadfence();
        ptr::read(self.ptr.offset(i as isize))
    }

    /// Overwrite the memory
    pub unsafe fn write(&mut self, i: usize, value: T) {
        ptr::write(self.ptr.offset(i as isize), value);
    }

    /// Store the memory
    pub unsafe fn store(&mut self, i: usize, value: T) {
        intrinsics::atomic_singlethreadfence();
        ptr::write(self.ptr.offset(i as isize), value)
    }

    /// Convert into a raw pointer
    pub unsafe fn into_raw(&mut self) -> *mut T {
        let ptr = self.ptr;
        self.ptr = 0 as *mut T;
        ptr
    }
}

impl<T> Drop for Memory<T> {
    fn drop(&mut self) {
        if self.ptr as usize > 0 {
            unsafe { unalloc(self.ptr as usize) };
        }
    }
}

impl<T> Index<usize> for Memory<T> {
    type Output = T;

    fn index<'a>(&'a self, _index: usize) -> &'a T {
        unsafe { &*self.ptr.offset(_index as isize) }
    }
}

impl<T> IndexMut<usize> for Memory<T> {
    fn index_mut<'a>(&'a mut self, _index: usize) -> &'a mut T {
        unsafe { &mut *self.ptr.offset(_index as isize) }
    }
}

/// A memory map entry
#[repr(packed)]
struct MemoryMapEntry {
    base: u64,
    len: u64,
    class: u32,
    acpi: u32,
}

const MEMORY_MAP: *const MemoryMapEntry = 0x500 as *const MemoryMapEntry;

pub unsafe fn cluster(number: usize) -> usize {
    if number < CLUSTER_COUNT {
        ptr::read((CLUSTER_ADDRESS + number * mem::size_of::<usize>()) as *const usize)
    } else {
        0
    }
}

pub unsafe fn set_cluster(number: usize, address: usize) {
    if number < CLUSTER_COUNT {
        ptr::write((CLUSTER_ADDRESS + number * mem::size_of::<usize>()) as *mut usize,
                   address);
    }
}

pub unsafe fn address_to_cluster(address: usize) -> usize {
    if address >= CLUSTER_ADDRESS + CLUSTER_COUNT * mem::size_of::<usize>() {
        (address - CLUSTER_ADDRESS - CLUSTER_COUNT * mem::size_of::<usize>()) / CLUSTER_SIZE
    } else {
        0
    }
}

pub unsafe fn cluster_to_address(number: usize) -> usize {
    CLUSTER_ADDRESS + CLUSTER_COUNT * mem::size_of::<usize>() + number * CLUSTER_SIZE
}

pub unsafe fn cluster_init() {
    // First, set all clusters to the not present value
    for cluster in 0..CLUSTER_COUNT {
        set_cluster(cluster, 0xFFFFFFFF);
    }

    // Next, set all valid clusters to the free value
    // TODO: Optimize this function
    for i in 0..((0x5000 - 0x500) / mem::size_of::<MemoryMapEntry>()) {
        let entry = &*MEMORY_MAP.offset(i as isize);
        if entry.len > 0 && entry.class == 1 {
            for cluster in 0..CLUSTER_COUNT {
                let address = cluster_to_address(cluster);
                if address as u64 >= entry.base &&
                   (address as u64 + CLUSTER_SIZE as u64) <= (entry.base + entry.len) {
                    set_cluster(cluster, 0);
                }
            }
        }
    }
}

/// Allocate memory
pub unsafe fn alloc(size: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_aligned(size: usize, align: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size > 0 {
        let mut number = 0;
        let mut count = 0;

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 && (count > 0 || cluster_to_address(i) % align == 0) {
                if count == 0 {
                    number = i;
                }
                count += 1;
                if count * CLUSTER_SIZE > size {
                    break;
                }
            } else {
                count = 0;
            }
        }
        if count * CLUSTER_SIZE > size {
            let address = cluster_to_address(number);
            for i in number..number + count {
                set_cluster(i, address);
            }
            ret = address;
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn alloc_type<T>() -> *mut T {
    alloc(mem::size_of::<T>()) as *mut T
}

pub unsafe fn alloc_size(ptr: usize) -> usize {
    let mut size = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                size += CLUSTER_SIZE;
            } else {
                break;
            }
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);

    size
}

pub unsafe fn unalloc(ptr: usize) {
    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if ptr > 0 {
        for i in address_to_cluster(ptr)..CLUSTER_COUNT {
            if cluster(i) == ptr {
                set_cluster(i, 0);
            } else {
                break;
            }
        }
    }

    // Memory allocation must be atomic
    scheduler::end_no_ints(reenable);
}

pub unsafe fn realloc(ptr: usize, size: usize) -> usize {
    let mut ret = 0;

    // Memory allocation must be atomic
    let reenable = scheduler::start_no_ints();

    if size == 0 {
        if ptr > 0 {
            unalloc(ptr);
        }
    } else {
        let old_size = alloc_size(ptr);
        if size <= old_size {
            ret = ptr;
        } else {
            ret = alloc(size);
            if ptr > 0 {
                if ret > 0 {
                    let copy_size = cmp::min(old_size, size);

                    ::memmove(ret as *mut u8, ptr as *const u8, copy_size);
                }
                unalloc(ptr);
            }
        }
    }

    scheduler::end_no_ints(reenable);

    ret
}

pub unsafe fn realloc_inplace(ptr: usize, size: usize) -> usize {
    let old_size = alloc_size(ptr);
    if size <= old_size {
        size
    } else {
        old_size
    }
}

pub fn memory_used() -> usize {
    let mut ret = 0;
    unsafe {
        // Memory allocation must be atomic
        let reenable = scheduler::start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) != 0 && cluster(i) != 0xFFFFFFFF {
                ret += CLUSTER_SIZE;
            }
        }

        // Memory allocation must be atomic
        scheduler::end_no_ints(reenable);
    }
    ret
}

pub fn memory_free() -> usize {
    let mut ret = 0;
    unsafe {
        // Memory allocation must be atomic
        let reenable = scheduler::start_no_ints();

        for i in 0..CLUSTER_COUNT {
            if cluster(i) == 0 {
                ret += CLUSTER_SIZE;
            }
        }

        // Memory allocation must be atomic
        scheduler::end_no_ints(reenable);
    }
    ret
}
<|endoftext|>


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

#![feature(nll)]

use std::collections::HashMap;

fn get_default(map: &mut HashMap<usize, String>, key: usize) -> &mut String {
    match map.get_mut(&key) {
        Some(value) => value,
        None => {
            map.insert(key, "".to_string());
            map.get_mut(&key).unwrap()
        }
    }
}

fn main() {
    let map = &mut HashMap::new();
    map.insert(22, format!("Hello, world"));
    map.insert(44, format!("Goodbye, world"));
    assert_eq!(&*get_default(map, 22), "Hello, world");
    assert_eq!(&*get_default(map, 66), "");
}
<commit_msg>kill get-default run-pass test<commit_after><|endoftext|>


<commit_before><commit_msg>Add test for eval order for a+=b<commit_after>// Test evaluation order of operands of the compound assignment operators

// run-pass

use std::ops::AddAssign;

enum Side {
    Lhs,
    Rhs,
}

// In the following tests, we place our value into a wrapper type so that we
// can do an element access as the outer place expression. If we just had the
// block expression, it'd be a value expression and not compile.
struct Wrapper<T>(T);

// Evaluation order for `a op= b` where typeof(a) and typeof(b) are primitives
// is first `b` then `a`.
fn primitive_compound() {
    let mut side_order = vec![];
    let mut int = Wrapper(0);

    {
        side_order.push(Side::Lhs);
        int
    }.0 += {
        side_order.push(Side::Rhs);
        0
    };

    assert!(matches!(side_order[..], [Side::Rhs, Side::Lhs]));
}

// Evaluation order for `a op=b` otherwise is first `a` then `b`.
fn generic_compound<T: AddAssign<T> + Default>() {
    let mut side_order = vec![];
    let mut add_assignable: Wrapper<T> = Wrapper(Default::default());

    {
        side_order.push(Side::Lhs);
        add_assignable
    }.0 += {
        side_order.push(Side::Rhs);
        Default::default()
    };

    assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
}

fn custom_compound() {
    struct Custom;

    impl AddAssign<()> for Custom {
        fn add_assign(&mut self, _: ()) {
            // this block purposely left blank
        }
    }

    let mut side_order = vec![];
    let mut custom = Wrapper(Custom);

    {
        side_order.push(Side::Lhs);
        custom
    }.0 += {
        side_order.push(Side::Rhs);
    };

    assert!(matches!(side_order[..], [Side::Lhs, Side::Rhs]));
}

fn main() {
    primitive_compound();
    generic_compound::<i32>();
    custom_compound();
}
<|endoftext|>


<commit_before>use super::*;

impl Editor {
    /// Go to next char
    pub fn next(&mut self) {
        if self.x() == self.text[self.y()].len() {
            if self.y() >= self.text.len() {
                self.text.push_back(VecDeque::new())
            }
            if self.y() < self.text.len() - 1 {
                self.cursor_mut().x = 0;
                self.cursor_mut().y += 1;
            }

        } else {
            self.cursor_mut().x += 1;
        }
    }

    /// Go to previous char
    pub fn previous(&mut self) {
        if self.x() == 0 {
            if self.y() > 0 {
                self.cursor_mut().y -= 1;
                self.cursor_mut().x = self.text[self.y() - 1].len();
            }
        } else {
            self.cursor_mut().y -= 1;
        }

    }

    /// Go right
    pub fn right(&mut self, n: usize) {
        let x = self.x() + n;
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.x += n;

        if x > text[y].len() {
            curs.x = text[y].len();
        }
    }
    /// Go left
    pub fn left(&mut self, n: usize) {
        let x = self.x();
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        if n <= x {
            curs.x -= n;
        } else {
            curs.x = 0;
        }

    }
    /// Go up
    pub fn up(&mut self, n: usize) {
        let y = self.y();
        let curs = self.cursor_mut();
        if n <= y {
            curs.y -= n;
        } else {
            curs.y = 0;
        }
    }
    /// Go down
    pub fn down(&mut self, n: usize) {
        let x = self.x();
        let y = self.y() + n;

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.y += n;

        if y >= text.len() {
            curs.y = text.len() - 1;
        }
    }
}
<commit_msg>Fix movement<commit_after>use super::*;

impl Editor {
    /// Go to next char
    pub fn next(&mut self) {
        if self.x() == self.text[self.y()].len() {
            if self.y() >= self.text.len() {
                self.text.push_back(VecDeque::new())
            }
            if self.y() < self.text.len() - 1 {
                self.cursor_mut().x = 0;
                self.cursor_mut().y += 1;
            }

        } else {
            self.cursor_mut().x += 1;
        }
    }

    /// Go to previous char
    pub fn previous(&mut self) {
        if self.x() == 0 {
            if self.y() > 0 {
                self.cursor_mut().y -= 1;
                self.cursor_mut().x = self.text[self.y() - 1].len();
            }
        } else {
            self.cursor_mut().y -= 1;
        }

    }

    /// Go right
    pub fn right(&mut self, n: usize) {
        let x = self.x() + n;
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.x += n;

        if x > text[y].len() {
            curs.x = text[y].len();
        }
    }
    /// Go left
    pub fn left(&mut self, n: usize) {
        let x = self.x();
        let y = self.y();

        let text = self.text.clone();
        let curs = self.cursor_mut();

        if n <= x {
            curs.x = x - n;
        } else {
            curs.x = 0;
        }

    }
    /// Go up
    pub fn up(&mut self, n: usize) {
        let y = self.y();
        let curs = self.cursor_mut();
        if n <= y {
            curs.y -= n;
        } else {
            curs.y = 0;
        }
    }
    /// Go down
    pub fn down(&mut self, n: usize) {
        let x = self.x();
        let y = self.y() + n;

        let text = self.text.clone();
        let curs = self.cursor_mut();

        curs.y += n;

        if y >= text.len() {
            curs.y = text.len() - 1;
        }
    }
}
<|endoftext|>


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

// xfail-test

// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print x
// check:$1 = false
// debugger:print y
// check:$2 = true

// debugger:run
// debugger:finish
// debugger:print x
// check:$3 = 10

// debugger:run
// debugger:finish
// debugger:print x
// check:$4 = false
// debugger:print y
// check:$5 = 11

fn main() {
    let x = false;
    let y = true;

    zzz();

    {
        let x = 10;
        zzz();
    }

    let y = 11;
    zzz();
}

fn zzz() {()}
<|endoftext|>


<commit_before><commit_msg>Rewrite Hasher::hash() for MailHasher<commit_after><|endoftext|>


<commit_before><commit_msg>add exchange_delete rustdoc as PoC<commit_after>/// Delete an exchange
<|endoftext|>


<commit_before><commit_msg>Check that statics are sized. Closes #26<commit_after>#[macro_use]
extern crate lazy_static;

lazy_static! {
    pub static ref FOO: str = panic!();
}
//^ ERROR `str` does not have a constant size known at compile-time

fn main() {
}
<|endoftext|>


<commit_before><commit_msg>implemented e2e tests<commit_after>#![cfg(all(test, feature = "test_e2e"))]
use azure_sdk_cosmos::prelude::*;

mod setup;

#[tokio::test]
async fn users() {
    const DATABASE_NAME: &str = "cosmos-test-db-users";
    const USER_NAME: &str = "someone@cool.net";
    const USER_NAME_REPLACED: &str = "someone.else@cool.net";

    let client = setup::initialize().unwrap();

    // create a temp database
    let _create_database_response = client
        .create_database()
        .with_database_name(&DATABASE_NAME)
        .execute()
        .await
        .unwrap();

    let database_client = client.with_database(&DATABASE_NAME);
    let user_client = database_client.with_user(&USER_NAME);

    let _create_user_response = user_client.create_user().execute().await.unwrap();

    let list_users_response = database_client.list_users().execute().await.unwrap();
    assert_eq!(list_users_response.users.len(), 1);

    let get_user_response = user_client.get_user().execute().await.unwrap();
    assert!(get_user_response.is_some());
    let retrieved_user = get_user_response.unwrap();
    assert_eq!(retrieved_user.user.id, USER_NAME);

    let _replace_user_response = user_client
        .replace_user()
        .with_user_name(&USER_NAME_REPLACED)
        .execute()
        .await
        .unwrap();

    let user_client = database_client.with_user(&USER_NAME_REPLACED);

    let _delete_user_response = user_client.delete_user().execute().await.unwrap();

    let list_users_response = database_client.list_users().execute().await.unwrap();
    assert_eq!(list_users_response.users.len(), 0);

    // delete the database
    client
        .with_database(&DATABASE_NAME)
        .delete_database()
        .execute()
        .await
        .unwrap();
    let _databases = client.list_databases().execute().await.unwrap();
}
<|endoftext|>


<commit_before><commit_msg>22 - freeze<commit_after>fn main() {
    let mut _integer = 5i;

    {
        // Borrow `integer`
        let _ref_to_integer = &_integer;

        // Error! `integer` is frozen in this scope
        // _integer = 4;
        // FIXME ^ Comment out this line

        // `ref_to_integer` goes out of scope
    }

    // Ok! `integer` is not frozen in this scope
    _integer = 4;
}
<|endoftext|>


<commit_before><commit_msg> removed filter for testing<commit_after><|endoftext|>


<commit_before><commit_msg>an empy message<commit_after><|endoftext|>


<commit_before><commit_msg>simple generics added<commit_after><|endoftext|>


<commit_before><commit_msg>16 - destructuring structs<commit_after>fn main() {
    struct Foo { x: (uint, uint), y: uint }

    // destructure members of the struct
    let foo = Foo { x: (1, 2), y: 3 };
    let Foo { x: (a, b), y } = foo;

    println!("a = {}, b = {},  y = {} ", a, b, y);

    // you can destructure structs and rename the variables,
    // the order is not important

    let Foo { y: i, x: j } = foo;
    println!("i = {}, j = {}", i, j);

    // and you can also ignore some variables:
    let Foo { y, .. } = foo;
    println!("y = {}", y);

    // this will give an error: pattern does not mention field `x`
    // let Foo { y } = foo;
}
<|endoftext|>


<commit_before><commit_msg>Rename 'set' to 'put'<commit_after><|endoftext|>


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

struct A {
    x: Box<int>,
    y: int,
}

struct B {
    x: Box<int>,
    y: Box<int>,
}

struct C {
    x: Box<A>,
    y: int,
}

struct D {
    x: Box<A>,
    y: Box<int>,
}

fn copy_after_move() {
    let a = box A { x: box 0, y: 1 };
    let _x = a.x;
    let _y = a.y; //~ ERROR use of partially moved
}

fn move_after_move() {
    let a = box B { x: box 0, y: box 1 };
    let _x = a.x;
    let _y = a.y; //~ ERROR use of partially moved
}

fn borrow_after_move() {
    let a = box A { x: box 0, y: 1 };
    let _x = a.x;
    let _y = &a.y; //~ ERROR use of partially moved
}

fn move_after_borrow() {
    let a = box B { x: box 0, y: box 1 };
    let _x = &a.x;
    let _y = a.y; //~ ERROR cannot move
}

fn copy_after_mut_borrow() {
    let mut a = box A { x: box 0, y: 1 };
    let _x = &mut a.x;
    let _y = a.y; //~ ERROR cannot use
}

fn move_after_mut_borrow() {
    let mut a = box B { x: box 0, y: box 1 };
    let _x = &mut a.x;
    let _y = a.y; //~ ERROR cannot move
}

fn borrow_after_mut_borrow() {
    let mut a = box A { x: box 0, y: 1 };
    let _x = &mut a.x;
    let _y = &a.y; //~ ERROR cannot borrow
}

fn mut_borrow_after_borrow() {
    let mut a = box A { x: box 0, y: 1 };
    let _x = &a.x;
    let _y = &mut a.y; //~ ERROR cannot borrow
}

fn copy_after_move_nested() {
    let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
    let _x = a.x.x;
    let _y = a.y; //~ ERROR use of partially moved
}

fn move_after_move_nested() {
    let a = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
    let _x = a.x.x;
    let _y = a.y; //~ ERROR use of partially moved
}

fn borrow_after_move_nested() {
    let a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
    let _x = a.x.x;
    let _y = &a.y; //~ ERROR use of partially moved
}

fn move_after_borrow_nested() {
    let a = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
    let _x = &a.x.x;
    let _y = a.y; //~ ERROR cannot move
}

fn copy_after_mut_borrow_nested() {
    let mut a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
    let _x = &mut a.x.x;
    let _y = a.y; //~ ERROR cannot use
}

fn move_after_mut_borrow_nested() {
    let mut a = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
    let _x = &mut a.x.x;
    let _y = a.y; //~ ERROR cannot move
}

fn borrow_after_mut_borrow_nested() {
    let mut a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
    let _x = &mut a.x.x;
    let _y = &a.y; //~ ERROR cannot borrow
}

fn mut_borrow_after_borrow_nested() {
    let mut a = box C { x: box A { x: box 0, y: 1 }, y: 2 };
    let _x = &a.x.x;
    let _y = &mut a.y; //~ ERROR cannot borrow
}

fn main() {
    copy_after_move();
    move_after_move();
    borrow_after_move();

    move_after_borrow();

    copy_after_mut_borrow();
    move_after_mut_borrow();
    borrow_after_mut_borrow();
    mut_borrow_after_borrow();

    copy_after_move_nested();
    move_after_move_nested();
    borrow_after_move_nested();

    move_after_borrow_nested();

    copy_after_mut_borrow_nested();
    move_after_mut_borrow_nested();
    borrow_after_mut_borrow_nested();
    mut_borrow_after_borrow_nested();
}

<|endoftext|>


<commit_before><commit_msg>Add a regression test for #85921<commit_after>// check-pass

#![feature(generic_associated_types)]

trait Trait {
    type Assoc<'a>;

    fn with_assoc(f: impl FnOnce(Self::Assoc<'_>));
}

impl Trait for () {
    type Assoc<'a> = i32;

    fn with_assoc(f: impl FnOnce(Self::Assoc<'_>)) {
        f(5i32)
    }
}

fn main() {}
<|endoftext|>


<commit_before><commit_msg>Skeleton for problem 2357<commit_after>// https://leetcode.com/problems/make-array-zero-by-subtracting-equal-amounts/
pub fn minimum_operations(nums: Vec<i32>) -> i32 {
    todo!()
}

fn main() {
    println!("{}", minimum_operations(vec![1, 5, 0, 3, 5])); // 3
    println!("{}", minimum_operations(vec![0])); // 0
}
<|endoftext|>


<commit_before><commit_msg>added small example<commit_after>extern crate coremidi_sys as cm;

fn main()
{
    let src: u64 = unsafe { cm::MIDIGetNumberOfSources() };
    let dest: u64 = unsafe { cm::MIDIGetNumberOfDestinations() };

    println!("Number of MIDI sources: {}", src);
    println!("Number of MIDI destinations: {}", dest);
}
<|endoftext|>


<commit_before><commit_msg>chore: disallow input negative number<commit_after><|endoftext|>


<commit_before>use lib::llvm::ValueRef;
use common::*;
use datum::*;
use base::*;

fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.

fn trans_block(bcx: block, b: ast::blk, dest: expr::Dest) -> block {
    let _icx = bcx.insn_ctxt("trans_block");
    let mut bcx = bcx;
    do block_locals(b) |local| {
        bcx = alloc_local(bcx, local);
    };
    for vec::each(b.node.stmts) |s| {
        debuginfo::update_source_pos(bcx, b.span);
        bcx = trans_stmt(bcx, *s);
    }
    match b.node.expr {
        Some(e) => {
            debuginfo::update_source_pos(bcx, e.span);
            bcx = expr::trans_into(bcx, e, dest);
        }
        None => {
            assert dest == expr::Ignore || bcx.unreachable;
        }
    }
    return bcx;
}

fn trans_if(bcx: block,
            cond: @ast::expr,
            thn: ast::blk,
            els: Option<@ast::expr>,
            dest: expr::Dest)
    -> block
{
    debug!("trans_if(bcx=%s, cond=%s, thn=%?, dest=%s)",
           bcx.to_str(), bcx.expr_to_str(cond), thn.node.id,
           dest.to_str(bcx.ccx()));
    let _indenter = indenter();

    let _icx = bcx.insn_ctxt("trans_if");
    let Result {bcx, val: cond_val} =
        expr::trans_to_datum(bcx, cond).to_result();

    let then_bcx_in = scope_block(bcx, thn.info(), ~"then");
    let else_bcx_in = scope_block(bcx, els.info(), ~"else");
    CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);

    debug!("then_bcx_in=%s, else_bcx_in=%s",
           then_bcx_in.to_str(), else_bcx_in.to_str());

    let then_bcx_out = trans_block(then_bcx_in, thn, dest);
    let then_bcx_out = trans_block_cleanups(then_bcx_out,
                                            block_cleanups(then_bcx_in));

    // Calling trans_block directly instead of trans_expr
    // because trans_expr will create another scope block
    // context for the block, but we've already got the
    // 'else' context
    let else_bcx_out = match els {
      Some(elexpr) => {
        match elexpr.node {
          ast::expr_if(_, _, _) => {
            let elseif_blk = ast_util::block_from_expr(elexpr);
            trans_block(else_bcx_in, elseif_blk, dest)
          }
          ast::expr_block(blk) => {
            trans_block(else_bcx_in, blk, dest)
          }
          // would be nice to have a constraint on ifs
          _ => bcx.tcx().sess.bug(~"strange alternative in if")
        }
      }
      _ => else_bcx_in
    };
    let else_bcx_out = trans_block_cleanups(else_bcx_out,
                                            block_cleanups(else_bcx_in));
    return join_blocks(bcx, ~[then_bcx_out, else_bcx_out]);

}

fn join_blocks(parent_bcx: block, in_cxs: ~[block]) -> block {
    let out = sub_block(parent_bcx, ~"join");
    let mut reachable = false;
    for vec::each(in_cxs) |bcx| {
        if !bcx.unreachable {
            Br(bcx, out.llbb);
            reachable = true;
        }
    }
    if !reachable {
        Unreachable(out);
    }
    return out;
}

fn trans_while(bcx: block, cond: @ast::expr, body: ast::blk)
    -> block {
    let _icx = bcx.insn_ctxt("trans_while");
    let next_bcx = sub_block(bcx, ~"while next");

    //            bcx
    //             |
    //          loop_bcx
    //             |
    //         cond_bcx_in  <--------+
    //             |                 |
    //         cond_bcx_out          |
    //           |      |            |
    //           |    body_bcx_in    |
    //    +------+      |            |
    //    |           body_bcx_out --+
    // next_bcx

    let loop_bcx = loop_scope_block(bcx, next_bcx, ~"`while`", body.info());
    let cond_bcx_in = scope_block(loop_bcx, cond.info(), ~"while loop cond");
    let body_bcx_in = scope_block(loop_bcx, body.info(), ~"while loop body");
    Br(bcx, loop_bcx.llbb);
    Br(loop_bcx, cond_bcx_in.llbb);

    // compile the condition
    let Result {bcx: cond_bcx_out, val: cond_val} =
        expr::trans_to_datum(cond_bcx_in, cond).to_result();
    let cond_bcx_out =
        trans_block_cleanups(cond_bcx_out, block_cleanups(cond_bcx_in));
    CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, next_bcx.llbb);

    // loop body:
    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
    cleanup_and_Br(body_bcx_out, body_bcx_in, cond_bcx_in.llbb);

    return next_bcx;
}

fn trans_loop(bcx:block, body: ast::blk) -> block {
    let _icx = bcx.insn_ctxt("trans_loop");
    let next_bcx = sub_block(bcx, ~"next");
    let body_bcx_in = loop_scope_block(bcx, next_bcx, ~"`loop`", body.info());
    Br(bcx, body_bcx_in.llbb);
    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
    cleanup_and_Br(body_bcx_out, body_bcx_in, body_bcx_in.llbb);
    return next_bcx;
}

fn trans_log(log_ex: @ast::expr,
             lvl: @ast::expr,
             bcx: block,
             e: @ast::expr) -> block
{
    let _icx = bcx.insn_ctxt("trans_log");
    let ccx = bcx.ccx();
    let mut bcx = bcx;
    if ty::type_is_bot(expr_ty(bcx, lvl)) {
       return expr::trans_into(bcx, lvl, expr::Ignore);
    }

    let modpath = vec::append(
        ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name))],
        vec::filter(bcx.fcx.path, |e|
            match e { path_mod(_) => true, _ => false }
        ));
    let modname = path_str(ccx.sess, modpath);

    let global = if ccx.module_data.contains_key(modname) {
        ccx.module_data.get(modname)
    } else {
        let s = link::mangle_internal_name_by_path_and_seq(
            ccx, modpath, ~"loglevel");
        let global = str::as_c_str(s, |buf| {
            llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf)
        });
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_i32()));
        lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
        ccx.module_data.insert(modname, global);
        global
    };
    let current_level = Load(bcx, global);
    let level = unpack_result!(bcx, {
        do with_scope_result(bcx, lvl.info(), ~"level") |bcx| {
            expr::trans_to_datum(bcx, lvl).to_result()
        }
    });

    let llenabled = ICmp(bcx, lib::llvm::IntUGE, current_level, level);
    do with_cond(bcx, llenabled) |bcx| {
        do with_scope(bcx, log_ex.info(), ~"log") |bcx| {
            let mut bcx = bcx;

            // Translate the value to be logged
            let val_datum = unpack_datum!(bcx, expr::trans_to_datum(bcx, e));
            let tydesc = get_tydesc_simple(ccx, val_datum.ty);

            // Call the polymorphic log function
            let val = val_datum.to_ref_llval(bcx);
            let val = PointerCast(bcx, val, T_ptr(T_i8()));
            Call(bcx, ccx.upcalls.log_type, [tydesc, val, level]);
            bcx
        }
    }
}

fn trans_break_cont(bcx: block, to_end: bool)
    -> block {
    let _icx = bcx.insn_ctxt("trans_break_cont");
    // Locate closest loop block, outputting cleanup as we go.
    let mut unwind = bcx;
    let mut target;
    loop {
        match unwind.kind {
          block_scope({loop_break: Some(brk), _}) => {
            target = if to_end {
                brk
            } else {
                unwind
            };
            break;
          }
          _ => ()
        }
        unwind = match unwind.parent {
          Some(bcx) => bcx,
          // This is a return from a loop body block
          None => {
            Store(bcx, C_bool(!to_end), bcx.fcx.llretptr);
            cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
            Unreachable(bcx);
            return bcx;
          }
        };
    }
    cleanup_and_Br(bcx, unwind, target.llbb);
    Unreachable(bcx);
    return bcx;
}

fn trans_break(bcx: block) -> block {
    return trans_break_cont(bcx, true);
}

fn trans_cont(bcx: block) -> block {
    return trans_break_cont(bcx, false);
}

fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
    let _icx = bcx.insn_ctxt("trans_ret");
    let mut bcx = bcx;
    let retptr = match copy bcx.fcx.loop_ret {
      Some({flagptr, retptr}) => {
        // This is a loop body return. Must set continue flag (our retptr)
        // to false, return flag to true, and then store the value in the
        // parent's retptr.
        Store(bcx, C_bool(true), flagptr);
        Store(bcx, C_bool(false), bcx.fcx.llretptr);
        match e {
          Some(x) => PointerCast(bcx, retptr,
                                 T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
          None => retptr
        }
      }
      None => bcx.fcx.llretptr
    };
    match e {
      Some(x) => {
        bcx = expr::trans_into(bcx, x, expr::SaveIn(retptr));
      }
      _ => ()
    }
    cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
    Unreachable(bcx);
    return bcx;
}
fn trans_check_expr(bcx: block, chk_expr: @ast::expr,
                    pred_expr: @ast::expr, s: ~str) -> block {
    let _icx = bcx.insn_ctxt("trans_check_expr");
    let expr_str = s + ~" " + expr_to_str(pred_expr, bcx.ccx().sess.intr())
        + ~" failed";
    let Result {bcx, val} = {
        do with_scope_result(bcx, chk_expr.info(), ~"check") |bcx| {
            expr::trans_to_datum(bcx, pred_expr).to_result()
        }
    };
    do with_cond(bcx, Not(bcx, val)) |bcx| {
        trans_fail(bcx, Some(pred_expr.span), expr_str)
    }
}

fn trans_fail_expr(bcx: block,
                   sp_opt: Option<span>,
                   fail_expr: Option<@ast::expr>) -> block {
    let _icx = bcx.insn_ctxt("trans_fail_expr");
    let mut bcx = bcx;
    match fail_expr {
        Some(arg_expr) => {
            let ccx = bcx.ccx(), tcx = ccx.tcx;
            let arg_datum = unpack_datum!(
                bcx, expr::trans_to_datum(bcx, arg_expr));

            if ty::type_is_str(arg_datum.ty) {
                let (lldata, _lllen) = arg_datum.get_base_and_len(bcx);
                return trans_fail_value(bcx, sp_opt, lldata);
            } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) {
                return bcx;
            } else {
                bcx.sess().span_bug(
                    arg_expr.span, ~"fail called with unsupported type " +
                    ppaux::ty_to_str(tcx, arg_datum.ty));
            }
        }
        _ => return trans_fail(bcx, sp_opt, ~"explicit failure")
    }
}

fn trans_fail(bcx: block, sp_opt: Option<span>, fail_str: ~str)
    -> block
{
    let _icx = bcx.insn_ctxt("trans_fail");
    let V_fail_str = C_cstr(bcx.ccx(), fail_str);
    return trans_fail_value(bcx, sp_opt, V_fail_str);
}

fn trans_fail_value(bcx: block, sp_opt: Option<span>, V_fail_str: ValueRef)
    -> block
{
    let _icx = bcx.insn_ctxt("trans_fail_value");
    let ccx = bcx.ccx();
    let {V_filename, V_line} = match sp_opt {
      Some(sp) => {
        let sess = bcx.sess();
        let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
        {V_filename: C_cstr(bcx.ccx(), loc.file.name),
         V_line: loc.line as int}
      }
      None => {
        {V_filename: C_cstr(bcx.ccx(), ~"<runtime>"),
         V_line: 0}
      }
    };
    let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
    let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
    let args = ~[V_str, V_filename, C_int(ccx, V_line)];
    let bcx = callee::trans_rtcall(bcx, ~"fail", args, expr::Ignore);
    Unreachable(bcx);
    return bcx;
}
<commit_msg>rustc: Use the correct 'fail' rtcall<commit_after>use lib::llvm::ValueRef;
use common::*;
use datum::*;
use base::*;

fn macros() { include!("macros.rs"); } // FIXME(#3114): Macro import/export.

fn trans_block(bcx: block, b: ast::blk, dest: expr::Dest) -> block {
    let _icx = bcx.insn_ctxt("trans_block");
    let mut bcx = bcx;
    do block_locals(b) |local| {
        bcx = alloc_local(bcx, local);
    };
    for vec::each(b.node.stmts) |s| {
        debuginfo::update_source_pos(bcx, b.span);
        bcx = trans_stmt(bcx, *s);
    }
    match b.node.expr {
        Some(e) => {
            debuginfo::update_source_pos(bcx, e.span);
            bcx = expr::trans_into(bcx, e, dest);
        }
        None => {
            assert dest == expr::Ignore || bcx.unreachable;
        }
    }
    return bcx;
}

fn trans_if(bcx: block,
            cond: @ast::expr,
            thn: ast::blk,
            els: Option<@ast::expr>,
            dest: expr::Dest)
    -> block
{
    debug!("trans_if(bcx=%s, cond=%s, thn=%?, dest=%s)",
           bcx.to_str(), bcx.expr_to_str(cond), thn.node.id,
           dest.to_str(bcx.ccx()));
    let _indenter = indenter();

    let _icx = bcx.insn_ctxt("trans_if");
    let Result {bcx, val: cond_val} =
        expr::trans_to_datum(bcx, cond).to_result();

    let then_bcx_in = scope_block(bcx, thn.info(), ~"then");
    let else_bcx_in = scope_block(bcx, els.info(), ~"else");
    CondBr(bcx, cond_val, then_bcx_in.llbb, else_bcx_in.llbb);

    debug!("then_bcx_in=%s, else_bcx_in=%s",
           then_bcx_in.to_str(), else_bcx_in.to_str());

    let then_bcx_out = trans_block(then_bcx_in, thn, dest);
    let then_bcx_out = trans_block_cleanups(then_bcx_out,
                                            block_cleanups(then_bcx_in));

    // Calling trans_block directly instead of trans_expr
    // because trans_expr will create another scope block
    // context for the block, but we've already got the
    // 'else' context
    let else_bcx_out = match els {
      Some(elexpr) => {
        match elexpr.node {
          ast::expr_if(_, _, _) => {
            let elseif_blk = ast_util::block_from_expr(elexpr);
            trans_block(else_bcx_in, elseif_blk, dest)
          }
          ast::expr_block(blk) => {
            trans_block(else_bcx_in, blk, dest)
          }
          // would be nice to have a constraint on ifs
          _ => bcx.tcx().sess.bug(~"strange alternative in if")
        }
      }
      _ => else_bcx_in
    };
    let else_bcx_out = trans_block_cleanups(else_bcx_out,
                                            block_cleanups(else_bcx_in));
    return join_blocks(bcx, ~[then_bcx_out, else_bcx_out]);

}

fn join_blocks(parent_bcx: block, in_cxs: ~[block]) -> block {
    let out = sub_block(parent_bcx, ~"join");
    let mut reachable = false;
    for vec::each(in_cxs) |bcx| {
        if !bcx.unreachable {
            Br(bcx, out.llbb);
            reachable = true;
        }
    }
    if !reachable {
        Unreachable(out);
    }
    return out;
}

fn trans_while(bcx: block, cond: @ast::expr, body: ast::blk)
    -> block {
    let _icx = bcx.insn_ctxt("trans_while");
    let next_bcx = sub_block(bcx, ~"while next");

    //            bcx
    //             |
    //          loop_bcx
    //             |
    //         cond_bcx_in  <--------+
    //             |                 |
    //         cond_bcx_out          |
    //           |      |            |
    //           |    body_bcx_in    |
    //    +------+      |            |
    //    |           body_bcx_out --+
    // next_bcx

    let loop_bcx = loop_scope_block(bcx, next_bcx, ~"`while`", body.info());
    let cond_bcx_in = scope_block(loop_bcx, cond.info(), ~"while loop cond");
    let body_bcx_in = scope_block(loop_bcx, body.info(), ~"while loop body");
    Br(bcx, loop_bcx.llbb);
    Br(loop_bcx, cond_bcx_in.llbb);

    // compile the condition
    let Result {bcx: cond_bcx_out, val: cond_val} =
        expr::trans_to_datum(cond_bcx_in, cond).to_result();
    let cond_bcx_out =
        trans_block_cleanups(cond_bcx_out, block_cleanups(cond_bcx_in));
    CondBr(cond_bcx_out, cond_val, body_bcx_in.llbb, next_bcx.llbb);

    // loop body:
    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
    cleanup_and_Br(body_bcx_out, body_bcx_in, cond_bcx_in.llbb);

    return next_bcx;
}

fn trans_loop(bcx:block, body: ast::blk) -> block {
    let _icx = bcx.insn_ctxt("trans_loop");
    let next_bcx = sub_block(bcx, ~"next");
    let body_bcx_in = loop_scope_block(bcx, next_bcx, ~"`loop`", body.info());
    Br(bcx, body_bcx_in.llbb);
    let body_bcx_out = trans_block(body_bcx_in, body, expr::Ignore);
    cleanup_and_Br(body_bcx_out, body_bcx_in, body_bcx_in.llbb);
    return next_bcx;
}

fn trans_log(log_ex: @ast::expr,
             lvl: @ast::expr,
             bcx: block,
             e: @ast::expr) -> block
{
    let _icx = bcx.insn_ctxt("trans_log");
    let ccx = bcx.ccx();
    let mut bcx = bcx;
    if ty::type_is_bot(expr_ty(bcx, lvl)) {
       return expr::trans_into(bcx, lvl, expr::Ignore);
    }

    let modpath = vec::append(
        ~[path_mod(ccx.sess.ident_of(ccx.link_meta.name))],
        vec::filter(bcx.fcx.path, |e|
            match e { path_mod(_) => true, _ => false }
        ));
    let modname = path_str(ccx.sess, modpath);

    let global = if ccx.module_data.contains_key(modname) {
        ccx.module_data.get(modname)
    } else {
        let s = link::mangle_internal_name_by_path_and_seq(
            ccx, modpath, ~"loglevel");
        let global = str::as_c_str(s, |buf| {
            llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf)
        });
        llvm::LLVMSetGlobalConstant(global, False);
        llvm::LLVMSetInitializer(global, C_null(T_i32()));
        lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
        ccx.module_data.insert(modname, global);
        global
    };
    let current_level = Load(bcx, global);
    let level = unpack_result!(bcx, {
        do with_scope_result(bcx, lvl.info(), ~"level") |bcx| {
            expr::trans_to_datum(bcx, lvl).to_result()
        }
    });

    let llenabled = ICmp(bcx, lib::llvm::IntUGE, current_level, level);
    do with_cond(bcx, llenabled) |bcx| {
        do with_scope(bcx, log_ex.info(), ~"log") |bcx| {
            let mut bcx = bcx;

            // Translate the value to be logged
            let val_datum = unpack_datum!(bcx, expr::trans_to_datum(bcx, e));
            let tydesc = get_tydesc_simple(ccx, val_datum.ty);

            // Call the polymorphic log function
            let val = val_datum.to_ref_llval(bcx);
            let val = PointerCast(bcx, val, T_ptr(T_i8()));
            Call(bcx, ccx.upcalls.log_type, [tydesc, val, level]);
            bcx
        }
    }
}

fn trans_break_cont(bcx: block, to_end: bool)
    -> block {
    let _icx = bcx.insn_ctxt("trans_break_cont");
    // Locate closest loop block, outputting cleanup as we go.
    let mut unwind = bcx;
    let mut target;
    loop {
        match unwind.kind {
          block_scope({loop_break: Some(brk), _}) => {
            target = if to_end {
                brk
            } else {
                unwind
            };
            break;
          }
          _ => ()
        }
        unwind = match unwind.parent {
          Some(bcx) => bcx,
          // This is a return from a loop body block
          None => {
            Store(bcx, C_bool(!to_end), bcx.fcx.llretptr);
            cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
            Unreachable(bcx);
            return bcx;
          }
        };
    }
    cleanup_and_Br(bcx, unwind, target.llbb);
    Unreachable(bcx);
    return bcx;
}

fn trans_break(bcx: block) -> block {
    return trans_break_cont(bcx, true);
}

fn trans_cont(bcx: block) -> block {
    return trans_break_cont(bcx, false);
}

fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
    let _icx = bcx.insn_ctxt("trans_ret");
    let mut bcx = bcx;
    let retptr = match copy bcx.fcx.loop_ret {
      Some({flagptr, retptr}) => {
        // This is a loop body return. Must set continue flag (our retptr)
        // to false, return flag to true, and then store the value in the
        // parent's retptr.
        Store(bcx, C_bool(true), flagptr);
        Store(bcx, C_bool(false), bcx.fcx.llretptr);
        match e {
          Some(x) => PointerCast(bcx, retptr,
                                 T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))),
          None => retptr
        }
      }
      None => bcx.fcx.llretptr
    };
    match e {
      Some(x) => {
        bcx = expr::trans_into(bcx, x, expr::SaveIn(retptr));
      }
      _ => ()
    }
    cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
    Unreachable(bcx);
    return bcx;
}
fn trans_check_expr(bcx: block, chk_expr: @ast::expr,
                    pred_expr: @ast::expr, s: ~str) -> block {
    let _icx = bcx.insn_ctxt("trans_check_expr");
    let expr_str = s + ~" " + expr_to_str(pred_expr, bcx.ccx().sess.intr())
        + ~" failed";
    let Result {bcx, val} = {
        do with_scope_result(bcx, chk_expr.info(), ~"check") |bcx| {
            expr::trans_to_datum(bcx, pred_expr).to_result()
        }
    };
    do with_cond(bcx, Not(bcx, val)) |bcx| {
        trans_fail(bcx, Some(pred_expr.span), expr_str)
    }
}

fn trans_fail_expr(bcx: block,
                   sp_opt: Option<span>,
                   fail_expr: Option<@ast::expr>) -> block {
    let _icx = bcx.insn_ctxt("trans_fail_expr");
    let mut bcx = bcx;
    match fail_expr {
        Some(arg_expr) => {
            let ccx = bcx.ccx(), tcx = ccx.tcx;
            let arg_datum = unpack_datum!(
                bcx, expr::trans_to_datum(bcx, arg_expr));

            if ty::type_is_str(arg_datum.ty) {
                let (lldata, _lllen) = arg_datum.get_base_and_len(bcx);
                return trans_fail_value(bcx, sp_opt, lldata);
            } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) {
                return bcx;
            } else {
                bcx.sess().span_bug(
                    arg_expr.span, ~"fail called with unsupported type " +
                    ppaux::ty_to_str(tcx, arg_datum.ty));
            }
        }
        _ => return trans_fail(bcx, sp_opt, ~"explicit failure")
    }
}

fn trans_fail(bcx: block, sp_opt: Option<span>, fail_str: ~str)
    -> block
{
    let _icx = bcx.insn_ctxt("trans_fail");
    let V_fail_str = C_cstr(bcx.ccx(), fail_str);
    return trans_fail_value(bcx, sp_opt, V_fail_str);
}

fn trans_fail_value(bcx: block, sp_opt: Option<span>, V_fail_str: ValueRef)
    -> block
{
    let _icx = bcx.insn_ctxt("trans_fail_value");
    let ccx = bcx.ccx();
    let {V_filename, V_line} = match sp_opt {
      Some(sp) => {
        let sess = bcx.sess();
        let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
        {V_filename: C_cstr(bcx.ccx(), loc.file.name),
         V_line: loc.line as int}
      }
      None => {
        {V_filename: C_cstr(bcx.ccx(), ~"<runtime>"),
         V_line: 0}
      }
    };
    let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
    let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
    let args = ~[V_str, V_filename, C_int(ccx, V_line)];
    let bcx = callee::trans_rtcall(bcx, ~"fail_", args, expr::Ignore);
    Unreachable(bcx);
    return bcx;
}
<|endoftext|>


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

// Ensure assigning an owned or managed variable to itself works. In particular,
// that we do not glue_drop before we glue_take (#3290).

use std::rc::Rc;

pub fn main() {
   let mut x = ~3;
   x = x;
   assert!(*x == 3);

   let mut x = Rc::new(3);
   x = x;
   assert!(*x.borrow() == 3);
}
<|endoftext|>


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

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let have_cmd = |cmd: &OsStr| {
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return Some(path);
            }
        }
        return None;
    };

    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        if have_cmd(cmd).is_none() {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
        }
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // Look for the nodejs command, needed for emscripten testing
    if let Some(node) = have_cmd("node".as_ref()) {
        build.config.nodejs = Some(node);
    } else if let Some(node) = have_cmd("nodejs".as_ref()) {
        build.config.nodejs = Some(node);
    }

    if let Some(ref s) = build.config.nodejs {
        need_cmd(s.as_ref());
    }

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // The msvc hosts don't use jemalloc, turn it off globally to
    // avoid packaging the dummy liballoc_jemalloc on that platform.
    for host in build.config.host.iter() {
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.musl_root(target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the build.musl-root \
                            option or the target.$TARGET.musl-root one must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<commit_msg>rustbuild: Fix panic message when musl-root not set<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashSet;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::process::Command;

use build_helper::output;

use Build;

pub fn check(build: &mut Build) {
    let mut checked = HashSet::new();
    let path = env::var_os("PATH").unwrap_or(OsString::new());
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) {
        if path.to_string_lossy().contains("\"") {
            panic!("PATH contains invalid character '\"'");
        }
    }
    let have_cmd = |cmd: &OsStr| {
        for path in env::split_paths(&path).map(|p| p.join(cmd)) {
            if fs::metadata(&path).is_ok() ||
               fs::metadata(path.with_extension("exe")).is_ok() {
                return Some(path);
            }
        }
        return None;
    };

    let mut need_cmd = |cmd: &OsStr| {
        if !checked.insert(cmd.to_owned()) {
            return
        }
        if have_cmd(cmd).is_none() {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd);
        }
    };

    // If we've got a git directory we're gona need git to update
    // submodules and learn about various other aspects.
    if fs::metadata(build.src.join(".git")).is_ok() {
        need_cmd("git".as_ref());
    }

    // We need cmake, but only if we're actually building LLVM
    for host in build.config.host.iter() {
        if let Some(config) = build.config.target_config.get(host) {
            if config.llvm_config.is_some() {
                continue
            }
        }
        need_cmd("cmake".as_ref());
        if build.config.ninja {
            need_cmd("ninja".as_ref())
        }
        break
    }

    need_cmd("python".as_ref());

    // Look for the nodejs command, needed for emscripten testing
    if let Some(node) = have_cmd("node".as_ref()) {
        build.config.nodejs = Some(node);
    } else if let Some(node) = have_cmd("nodejs".as_ref()) {
        build.config.nodejs = Some(node);
    }

    if let Some(ref s) = build.config.nodejs {
        need_cmd(s.as_ref());
    }

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in build.config.target.iter() {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        need_cmd(build.cc(target).as_ref());
        if let Some(ar) = build.ar(target) {
            need_cmd(ar.as_ref());
        }
    }
    for host in build.config.host.iter() {
        need_cmd(build.cxx(host).as_ref());
    }

    // The msvc hosts don't use jemalloc, turn it off globally to
    // avoid packaging the dummy liballoc_jemalloc on that platform.
    for host in build.config.host.iter() {
        if host.contains("msvc") {
            build.config.use_jemalloc = false;
        }
    }

    // Externally configured LLVM requires FileCheck to exist
    let filecheck = build.llvm_filecheck(&build.config.build);
    if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
        panic!("filecheck executable {:?} does not exist", filecheck);
    }

    for target in build.config.target.iter() {
        // Can't compile for iOS unless we're on OSX
        if target.contains("apple-ios") &&
           !build.config.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on OSX");
        }

        // Make sure musl-root is valid if specified
        if target.contains("musl") && !target.contains("mips") {
            match build.musl_root(target) {
                Some(root) => {
                    if fs::metadata(root.join("lib/libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl dir: {}",
                               root.join("lib").display());
                    }
                    if fs::metadata(root.join("lib/libunwind.a")).is_err() {
                        panic!("couldn't find libunwind.a in musl dir: {}",
                               root.join("lib").display());
                    }
                }
                None => {
                    panic!("when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml")
                }
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!("
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
");
            }
        }

        if target.contains("arm-linux-android") {
            need_cmd("adb".as_ref());
        }
    }

    for host in build.flags.host.iter() {
        if !build.config.host.contains(host) {
            panic!("specified host `{}` is not in the ./configure list", host);
        }
    }
    for target in build.flags.target.iter() {
        if !build.config.target.contains(target) {
            panic!("specified target `{}` is not in the ./configure list",
                   target);
        }
    }

    let run = |cmd: &mut Command| {
        cmd.output().map(|output| {
            String::from_utf8_lossy(&output.stdout)
                   .lines().next().unwrap()
                   .to_string()
        })
    };
    build.gdb_version = run(Command::new("gdb").arg("--version")).ok();
    build.lldb_version = run(Command::new("lldb").arg("--version")).ok();
    if build.lldb_version.is_some() {
        build.lldb_python_dir = run(Command::new("lldb").arg("-P")).ok();
    }
}
<|endoftext|>


<commit_before><commit_msg>Copy cryptocurrency service and test it<commit_after>//! Tests for sample currency service almost identical to one implemented in
//! the [`cryptocurrency`] tutorial.
//!
//! [`cryptocurrency`]: https://github.com/exonum/cryptocurrency/

#[macro_use]
extern crate serde_derive;
#[macro_use]
extern crate exonum;
extern crate exonum_harness;

use exonum::crypto::{self, PublicKey, SecretKey};
use exonum::messages::Message;
use exonum_harness::{TestHarness, HarnessApi, ComparableSnapshot};

mod cryptocurrency {
    extern crate serde;
    extern crate serde_json;
    extern crate router;
    extern crate bodyparser;
    extern crate iron;

    use exonum::blockchain::{self, Blockchain, Service, Transaction, ApiContext};
    use exonum::node::{TransactionSend, ApiSender};
    use exonum::messages::{RawTransaction, FromRaw, Message};
    use exonum::storage::{Snapshot, Fork, MemoryDB, MapIndex};
    use exonum::crypto::{PublicKey, Hash, HexValue};
    use exonum::encoding;
    use exonum::api::{Api, ApiError};
    use self::iron::prelude::*;
    use self::iron::Handler;
    use self::router::Router;

    // // // // // // // // // // CONSTANTS // // // // // // // // // //

    const SERVICE_ID: u16 = 1;
    const TX_CREATE_WALLET_ID: u16 = 1;
    const TX_TRANSFER_ID: u16 = 2;

    /// Initial balance of newly created wallet.
    pub const INIT_BALANCE: u64 = 100;

    // // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

    encoding_struct! {
        struct Wallet {
            const SIZE = 48;

            field pub_key:            &PublicKey  [00 => 32]
            field name:               &str        [32 => 40]
            field balance:            u64         [40 => 48]
        }
    }

    impl Wallet {
        pub fn increase(self, amount: u64) -> Self {
            let balance = self.balance() + amount;
            Self::new(self.pub_key(), self.name(), balance)
        }

        pub fn decrease(self, amount: u64) -> Self {
            let balance = self.balance() - amount;
            Self::new(self.pub_key(), self.name(), balance)
        }
    }

    // // // // // // // // // // DATA LAYOUT // // // // // // // // // //

    pub struct CurrencySchema<S> {
        view: S,
    }

    impl<S: AsRef<Snapshot>> CurrencySchema<S> {
        pub fn new(view: S) -> Self {
            CurrencySchema { view }
        }

        pub fn wallets(&self) -> MapIndex<&Snapshot, PublicKey, Wallet> {
            let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
            MapIndex::new(prefix, self.view.as_ref())
        }

        /// Get a separate wallet from the storage.
        pub fn wallet(&self, pub_key: &PublicKey) -> Option<Wallet> {
            self.wallets().get(pub_key)
        }
    }

    impl<'a> CurrencySchema<&'a mut Fork> {
        pub fn wallets_mut(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
            let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
            MapIndex::new(prefix, self.view)
        }
    }

    // // // // // // // // // // TRANSACTIONS // // // // // // // // // //

    /// Create a new wallet.
    message! {
        struct TxCreateWallet {
            const TYPE = SERVICE_ID;
            const ID = TX_CREATE_WALLET_ID;
            const SIZE = 40;

            field pub_key:     &PublicKey  [00 => 32]
            field name:        &str        [32 => 40]
        }
    }

    /// Transfer coins between the wallets.
    message! {
        struct TxTransfer {
            const TYPE = SERVICE_ID;
            const ID = TX_TRANSFER_ID;
            const SIZE = 80;

            field from:        &PublicKey  [00 => 32]
            field to:          &PublicKey  [32 => 64]
            field amount:      u64         [64 => 72]
            field seed:        u64         [72 => 80]
        }
    }

    // // // // // // // // // // CONTRACTS // // // // // // // // // //

    impl Transaction for TxCreateWallet {
        /// Verify integrity of the transaction by checking the transaction
        /// signature.
        fn verify(&self) -> bool {
            self.verify_signature(self.pub_key())
        }

        /// Apply logic to the storage when executing the transaction.
        fn execute(&self, view: &mut Fork) {
            let mut schema = CurrencySchema { view };
            if schema.wallet(self.pub_key()).is_none() {
                let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE);
                schema.wallets_mut().put(self.pub_key(), wallet)
            }
        }

        /// Provide information about the transaction to be used in the blockchain explorer.
        fn info(&self) -> serde_json::Value {
            serde_json::to_value(&self).expect("Cannot serialize transaction to JSON")
        }
    }

    impl Transaction for TxTransfer {
        /// Check if the sender is not the receiver. Check correctness of the
        /// sender's signature.
        fn verify(&self) -> bool {
            (*self.from() != *self.to()) && self.verify_signature(self.from())
        }

        /// Retrieve two wallets to apply the transfer. Check the sender's
        /// balance and apply changes to the balances of the wallets.
        fn execute(&self, view: &mut Fork) {
            let mut schema = CurrencySchema { view };
            let sender = schema.wallet(self.from());
            let receiver = schema.wallet(self.to());
            if let (Some(sender), Some(receiver)) = (sender, receiver) {
                let amount = self.amount();
                if sender.balance() >= amount {
                    let sender = sender.decrease(amount);
                    let receiver = receiver.increase(amount);
                    let mut wallets = schema.wallets_mut();
                    wallets.put(self.from(), sender);
                    wallets.put(self.to(), receiver);
                }
            }
        }

        /// Provide information about the transaction to be used in the blockchain explorer.
        fn info(&self) -> serde_json::Value {
            serde_json::to_value(&self).expect("Cannot serialize transaction to JSON")
        }
    }

    // // // // // // // // // // REST API // // // // // // // // // //

    #[derive(Clone)]
    struct CryptocurrencyApi {
        channel: ApiSender,
        blockchain: Blockchain,
    }

    /// Shortcut to get data on wallets.
    impl CryptocurrencyApi {
        fn get_wallet(&self, pub_key: &PublicKey) -> Option<Wallet> {
            let view = self.blockchain.snapshot();
            let schema = CurrencySchema::new(view);
            schema.wallet(pub_key)
        }

        fn get_wallets(&self) -> Option<Vec<Wallet>> {
            let view = self.blockchain.snapshot();
            let schema = CurrencySchema::new(view);
            let idx = schema.wallets();
            let wallets: Vec<Wallet> = idx.values().collect();
            if wallets.is_empty() {
                None
            } else {
                Some(wallets)
            }
        }
    }

    /// Add an enum which joins transactions of both types to simplify request
    /// processing.
    #[serde(untagged)]
    #[derive(Clone, Serialize, Deserialize)]
    enum TransactionRequest {
        CreateWallet(TxCreateWallet),
        Transfer(TxTransfer),
    }

    /// Implement a trait for the enum for deserialized `TransactionRequest`s
    /// to fit into the node channel.
    impl Into<Box<Transaction>> for TransactionRequest {
        fn into(self) -> Box<Transaction> {
            match self {
                TransactionRequest::CreateWallet(trans) => Box::new(trans),
                TransactionRequest::Transfer(trans) => Box::new(trans),
            }
        }
    }

    /// The structure returned by the REST API.
    #[derive(Serialize, Deserialize)]
    pub struct TransactionResponse {
        pub tx_hash: Hash,
    }

    impl Api for CryptocurrencyApi {
        fn wire(&self, router: &mut Router) {
            let self_ = self.clone();
            let transaction = move |req: &mut Request| -> IronResult<Response> {
                match req.get::<bodyparser::Struct<TransactionRequest>>() {
                    Ok(Some(transaction)) => {
                        let transaction: Box<Transaction> = transaction.into();
                        let tx_hash = transaction.hash();
                        self_.channel.send(transaction).map_err(ApiError::from)?;
                        let json = TransactionResponse { tx_hash };
                        self_.ok_response(&serde_json::to_value(&json).unwrap())
                    }
                    Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                    Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
                }
            };

            // Gets status of all wallets.
            let self_ = self.clone();
            let wallets_info = move |_: &mut Request| -> IronResult<Response> {
                if let Some(wallets) = self_.get_wallets() {
                    self_.ok_response(&serde_json::to_value(wallets).unwrap())
                } else {
                    self_.not_found_response(
                        &serde_json::to_value("Wallets database is empty").unwrap(),
                    )
                }
            };

            // Gets status of the wallet corresponding to the public key.
            let self_ = self.clone();
            let wallet_info = move |req: &mut Request| -> IronResult<Response> {
                let path = req.url.path();
                let wallet_key = path.last().unwrap();
                let public_key = PublicKey::from_hex(wallet_key).map_err(ApiError::FromHex)?;
                if let Some(wallet) = self_.get_wallet(&public_key) {
                    self_.ok_response(&serde_json::to_value(wallet).unwrap())
                } else {
                    self_.not_found_response(&serde_json::to_value("Wallet not found").unwrap())
                }
            };

            // Bind the transaction handler to a specific route.
            router.post("/v1/wallets/transaction", transaction, "transaction");
            router.get("/v1/wallets", wallets_info, "wallets_info");
            router.get("/v1/wallet/:pub_key", wallet_info, "wallet_info");
        }
    }

    // // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

    /// Define the service.
    pub struct CurrencyService;

    /// Implement a `Service` trait for the service.
    impl Service for CurrencyService {
        fn service_name(&self) -> &'static str {
            "cryptocurrency"
        }

        fn service_id(&self) -> u16 {
            SERVICE_ID
        }

        /// Implement a method to deserialize transactions coming to the node.
        fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
            let trans: Box<Transaction> = match raw.message_type() {
                TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
                TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
                _ => {
                    return Err(encoding::Error::IncorrectMessageType {
                        message_type: raw.message_type(),
                    });
                }
            };
            Ok(trans)
        }

        /// Create a REST `Handler` to process web requests to the node.
        fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
            let mut router = Router::new();
            let api = CryptocurrencyApi {
                channel: ctx.node_channel().clone(),
                blockchain: ctx.blockchain().clone(),
            };
            api.wire(&mut router);
            Some(Box::new(router))
        }
    }

    pub fn blockchain() -> Blockchain {
        let db = MemoryDB::new();
        let services: Vec<Box<Service>> = vec![Box::new(CurrencyService)];
        Blockchain::new(Box::new(db), services)
    }
}

use cryptocurrency::{CurrencySchema, TxCreateWallet, TxTransfer, TransactionResponse, Wallet,
                     blockchain};

fn create_wallet(api: &HarnessApi, name: &str) -> (TxCreateWallet, SecretKey) {
    let (pubkey, key) = crypto::gen_keypair();
    // Create a presigned transaction
    let tx = TxCreateWallet::new(&pubkey, name, &key);

    let tx_info: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    assert_eq!(tx_info.tx_hash, tx.hash());

    (tx, key)
}

fn get_wallet(api: &HarnessApi, pubkey: &PublicKey) -> Wallet {
    api.get(
        "cryptocurrency",
        &format!("v1/wallet/{}", pubkey.to_string()),
    )
}

#[test]
fn test_create_wallet() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();
    let (tx, _) = create_wallet(&api, "Alice");

    harness.create_block();

    // Check that the user indeed is persisted by the service
    let wallet = get_wallet(&api, tx.pub_key());
    assert_eq!(wallet.pub_key(), tx.pub_key());
    assert_eq!(wallet.name(), tx.name());
    assert_eq!(wallet.balance(), 100);
}

#[test]
fn test_transfer() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, _) = create_wallet(&api, "Bob");
    // Commit creation transactions
    harness.create_block();

    // Check that the initial Alice's and Bob's balances are persisted by the service
    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    let tx_info: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    assert_eq!(tx_info.tx_hash, tx.hash());

    harness.create_block();

    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 90);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 110);
}

#[test]
fn test_snapshot_completeness() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, _) = create_wallet(&api, "Alice");
    harness.create_block();

    let (tx_bob, _) = create_wallet(&api, "Bob");
    // Check that Alice's wallet is in the snapshot
    harness
        .probe(tx_bob)
        .compare(harness.snapshot())
        .map(CurrencySchema::new)
        .map(|schema| schema.wallet(tx_alice.pub_key()))
        .assert_before("Alice's wallet is there", Option::is_some)
        .assert_after("Alice's wallet is still there", Option::is_some)
        .map(|w| w.as_ref().unwrap().balance())
        .assert_eq("Alice's balance hasn't changed");
}

#[test]
fn test_transfer_from_nonexisting_wallet() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, _) = create_wallet(&api, "Bob");
    // Do not commit Alice's transaction
    harness.create_block_with_transactions(&[tx_bob.hash()]);

    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    let tx_info: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    assert_eq!(tx_info.tx_hash, tx.hash());

    let comp = harness.probe(tx).compare(harness.snapshot());
    let comp = comp.map(CurrencySchema::new);
    comp.map(|s| s.wallet(tx_alice.pub_key()))
        .assert_before("No Alice's wallet", Option::is_none)
        .assert_after("No Alice's wallet", Option::is_none);
    comp.map(|s| s.wallet(tx_bob.pub_key()))
        .map(|w| match *w {
            Some(ref wallet) => wallet.balance(),
            None => panic!("No Bob's wallet!"),
        })
        .assert_eq("Bob's balance hasn't changed");
}

#[test]
fn test_transfer_to_nonexisting_wallet() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, _) = create_wallet(&api, "Bob");
    // Do not commit Bob's transaction
    harness.create_block_with_transactions(&[tx_alice.hash()]);

    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        10, // amount
        0, // seed
        &key_alice,
    );
    let _: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);

    let old_snapshot = harness.snapshot();
    harness.create_block_with_transactions(&[tx.hash()]);

    let comp = harness.snapshot().compare(old_snapshot);
    let comp = comp.map(CurrencySchema::new);
    comp.map(|s| s.wallet(tx_bob.pub_key()))
        .assert_before("No Bob's wallet", Option::is_none)
        .assert_after("No Bob's wallet", Option::is_none);
    comp.map(|s| s.wallet(tx_alice.pub_key()))
        .map(|w| match *w {
            Some(ref wallet) => wallet.balance(),
            None => panic!("No Alice's wallet!"),
        })
        .assert_eq("Alice's balance hasn't changed");
}

#[test]
fn test_transfer_overcharge() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, _) = create_wallet(&api, "Bob");
    harness.create_block();

    // Transfer funds
    let tx = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        110, // amount
        0, // seed
        &key_alice,
    );

    let _: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx);
    harness.create_block();

    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 100);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 100);
}

#[test]
fn test_transfers_in_single_block() {
    let mut harness = TestHarness::new(blockchain());
    let api = harness.api();

    let (tx_alice, key_alice) = create_wallet(&api, "Alice");
    let (tx_bob, key_bob) = create_wallet(&api, "Bob");
    harness.create_block();

    // Transfer funds from Alice to Bob.
    let tx_a_to_b = TxTransfer::new(
        tx_alice.pub_key(),
        tx_bob.pub_key(),
        90, // amount
        0, // seed
        &key_alice,
    );

    // Transfer funds back from Bob to Alice.
    let tx_b_to_a = TxTransfer::new(
        tx_bob.pub_key(),
        tx_alice.pub_key(),
        120, // amount
        0, // seed
        &key_bob,
    );

    {
        // See what happens if transactions are applied in an "incorrect" order.
        let comp = harness
            .probe_all(vec![
                Box::new(tx_b_to_a.clone()),
                Box::new(tx_a_to_b.clone()),
            ])
            .compare(harness.snapshot());
        let comp = comp.map(CurrencySchema::new);
        comp.map(|s| s.wallet(tx_alice.pub_key()))
            .map(|w| w.as_ref().unwrap().balance())
            .assert("Alice's balance decreases", |&old, &new| new == old - 90);
        comp.map(|s| s.wallet(tx_bob.pub_key()))
            .map(|w| w.as_ref().unwrap().balance())
            .assert("Bob's balance increases", |&old, &new| new == old + 90);
    }

    let _: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx_a_to_b);
    let _: TransactionResponse = api.post("cryptocurrency", "v1/wallets/transaction", &tx_b_to_a);
    harness.create_block_with_transactions(&[tx_a_to_b.hash(), tx_b_to_a.hash()]);

    let wallet = get_wallet(&api, tx_alice.pub_key());
    assert_eq!(wallet.balance(), 130);
    let wallet = get_wallet(&api, tx_bob.pub_key());
    assert_eq!(wallet.balance(), 70);
}
<|endoftext|>


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

//revisions: ast mir
//[mir] compile-flags: -Z borrowck=mir -Z nll

#![allow(unused_assignments)]

struct Wrap<'a> { w: &'a mut u32 }

fn foo() {
    let mut x = 22;
    let wrapper = Wrap { w: &mut x };
    x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506]
    //[mir]~^ ERROR cannot assign to `x` because it is borrowed [E0506]
    //[mir]~^^ ERROR cannot use `x` because it was mutably borrowed [E0503]
    *wrapper.w += 1;
}

fn main() { }
<commit_msg>Updated other affected tests.<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//revisions: ast mir
//[mir] compile-flags: -Z borrowck=mir -Z nll

#![allow(unused_assignments)]

struct Wrap<'a> { w: &'a mut u32 }

fn foo() {
    let mut x = 22;
    let wrapper = Wrap { w: &mut x };
    x += 1; //[ast]~ ERROR cannot assign to `x` because it is borrowed [E0506]
    //[mir]~^ ERROR cannot assign to `x` because it is borrowed [E0506]
    *wrapper.w += 1;
}

fn main() { }
<|endoftext|>


<commit_before><commit_msg>Added a fractal snowflake example<commit_after>// Source: http://www.algorithm.co.il/blogs/computer-science/fractals-in-10-minutes-no-6-turtle-snowflake/
// Modified to create a full snowflake with the fractals

extern crate turtle;

use turtle::Turtle;

fn main() {
    let mut turtle = Turtle::new();

    turtle.set_background_color("#29B6F6");
    turtle.set_pen_color("#B2EBF2");

    turtle.pen_up();
    turtle.set_speed(11);
    turtle.backward(200.0);
    turtle.right(30.0);
    turtle.pen_down();

    turtle.set_speed(10);
    fractal(&mut turtle, 350.0, 3);
    turtle.left(120.0);
    fractal(&mut turtle, 350.0, 3);
    turtle.left(120.0);
    fractal(&mut turtle, 350.0, 3);

    turtle.hide();
}

fn fractal(turtle: &mut Turtle, length: f64, depth: usize) {
    if depth == 0 {
        turtle.forward(length);
    }
    else {
        fractal(turtle, length/3.0, depth-1);
        turtle.right(60.0);
        fractal(turtle, length/3.0, depth-1);
        turtle.left(120.0);
        fractal(turtle, length/3.0, depth-1);
        turtle.right(60.0);
        fractal(turtle, length/3.0, depth-1);
    }
}
<|endoftext|>