<commit_before>use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::on_different_cards;
use gc::swiper::young::YoungGen;
use gc::swiper::Region;
use gc::swiper::CARD_SIZE;
use gc::Address;

use mem;
use object::{offset_of_array_data, Obj};

#[derive(Copy, Clone)]
pub enum VerifierPhase {
    PreMinor,
    PostMinor,
    PreFull,
    PostFull,
}

impl VerifierPhase {
    fn is_pre(self) -> bool {
        match self {
            VerifierPhase::PreMinor => true,
            VerifierPhase::PostMinor => false,
            VerifierPhase::PreFull => true,
            VerifierPhase::PostFull => false,
        }
    }
}

pub struct Verifier<'a> {
    young: &'a YoungGen,
    old: &'a OldGen,
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    rootset: &'a [IndirectObj],
    large: &'a LargeSpace,
    perm_space: &'a Space,

    refs_to_young_gen: usize,
    in_old: bool,
    in_large: bool,

    old_region: Region,
    young_region: Region,
    reserved_area: Region,

    phase: VerifierPhase,
}

impl<'a> Verifier<'a> {
    pub fn new(
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        rootset: &'a [IndirectObj],
        large: &'a LargeSpace,
        perm_space: &'a Space,
        reserved_area: Region,
        phase: VerifierPhase,
    ) -> Verifier<'a> {
        Verifier {
            young: young,
            old: old,
            card_table: card_table,
            crossing_map: crossing_map,
            rootset: rootset,
            perm_space: perm_space,
            large: large,

            refs_to_young_gen: 0,
            in_old: false,
            in_large: false,

            young_region: young.used_region(),
            old_region: old.used_region(),
            reserved_area: reserved_area,

            phase: phase,
        }
    }

    pub fn verify(&mut self) {
        self.verify_roots();
        self.verify_young();
        self.verify_old();
        self.verify_large();
    }

    fn verify_young(&mut self) {
        let region = self.young_region.clone();
        self.verify_objects(region, "young gen");
    }

    fn verify_old(&mut self) {
        let region = self.old_region.clone();
        self.in_old = true;
        self.verify_objects(region, "old gen");
        self.in_old = false;
    }

    fn verify_large(&mut self) {
        self.in_large = true;
        self.large.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };
            let region = Region::new(addr, addr.offset(object.size()));
            self.verify_objects(region, "large space");
        });
        self.in_large = false;
    }

    fn verify_roots(&mut self) {
        for root in self.rootset {
            let root_ptr = root.get();
            self.verify_reference(root_ptr, root.to_address(), Address::null(), "root set");
        }
    }

    fn verify_objects(&mut self, region: Region, name: &str) {
        let mut curr = region.start;
        self.refs_to_young_gen = 0;

        if self.in_old {
            // we should start at card start
            assert!(self.card_table.is_aligned(curr));
            self.verify_crossing(curr, curr, false);
        }

        while curr < region.end {
            let object = unsafe { &mut *curr.to_mut_ptr::<Obj>() };

            let next = if object.is_array_ref() {
                self.verify_array_ref(object, curr, name)
            } else {
                self.verify_object(object, curr, name)
            };

            curr = next;
        }

        assert!(curr == region.end, "object doesn't end at region end");

        if (self.in_old || self.in_large) && !self.card_table.is_aligned(curr) {
            self.verify_card(curr);
        }
    }

    fn verify_array_ref(&mut self, object: &mut Obj, mut curr: Address, name: &str) -> Address {
        let object_address = curr;

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if (self.in_old || self.in_large) && on_different_cards(curr, child.to_address()) {
                self.verify_card(curr);
                curr = child.to_address();
            }

            self.verify_reference(child_ptr, child.to_address(), object_address, name);
        });

        let next = object_address.offset(object.size());

        if self.in_old && on_different_cards(object_address, next) {
            self.verify_crossing(object_address, next, true);
        }

        next
    }

    fn verify_object(&mut self, object: &mut Obj, curr: Address, name: &str) -> Address {
        object.visit_reference_fields(|child| {
            let child_ptr = child.get();
            self.verify_reference(child_ptr, child.to_address(), curr, name);
        });

        let next = curr.offset(object.size());

        if (self.in_old || self.in_large) && on_different_cards(curr, next) {
            self.verify_card(curr);
            if self.in_old {
                self.verify_crossing(curr, next, false);
            }
        }

        next
    }

    fn verify_card(&mut self, curr: Address) {
        let curr_card = self.card_table.card_idx(curr);

        let card_entry = self.card_table.get(curr_card);
        let expected_card_entry = if self.refs_to_young_gen > 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        };

        // In the verify-phase before the collection the card's dirty-entry isn't
        // guaranteed to be exact. It could be `dirty` although this card doesn't
        // actually contain any references into the young generation. But it should never
        // be clean when there are actual references into the young generation.
        if self.phase.is_pre() && expected_card_entry == CardEntry::Clean {
            self.refs_to_young_gen = 0;
            return;
        }

        if card_entry != expected_card_entry {
            let card_text = match card_entry {
                CardEntry::Dirty => "dirty",
                CardEntry::Clean => "clean",
            };

            println!(
                "CARD: {} is marked {} but has {} reference(s).",
                curr_card.to_usize(),
                card_text,
                self.refs_to_young_gen
            );

            panic!("card table entry wrong.");
        }

        assert!(card_entry == expected_card_entry);

        self.refs_to_young_gen = 0;
    }

    fn verify_crossing(&mut self, old: Address, new: Address, array_ref: bool) {
        let new_card_idx = self.card_table.card_idx(new);
        let old_card_idx = self.card_table.card_idx(old);

        if new_card_idx == old_card_idx {
            return;
        }

        let new_card_start = self.card_table.to_address(new_card_idx);
        let old_card_end = self.card_table.to_address(old_card_idx).offset(CARD_SIZE);

        let offset = new.offset_from(new_card_start);
        let offset_words = (offset / mem::ptr_width_usize()) as u8;

        let crossing_middle;
        let loop_start;

        if array_ref {
            let refs_per_card = (CARD_SIZE / mem::ptr_width_usize()) as u8;

            crossing_middle = CrossingEntry::LeadingRefs(refs_per_card);

            if old.offset(offset_of_array_data() as usize) > old_card_end {
                let old_next = old_card_idx.to_usize() + 1;
                let crossing = self.crossing_map.get(old_next.into());
                let diff_words = old_card_end.offset_from(old) / mem::ptr_width_usize();
                assert!(crossing == CrossingEntry::ArrayStart(diff_words as u8));

                loop_start = old_card_idx.to_usize() + 2;
            } else {
                loop_start = old_card_idx.to_usize() + 1;
            }

            if new_card_idx.to_usize() >= loop_start {
                let crossing = self.crossing_map.get(new_card_idx);
                let expected = CrossingEntry::LeadingRefs(offset_words);
                assert!(crossing == expected, "array crossing at end not correct.");
            }
        } else {
            crossing_middle = CrossingEntry::NoRefs;
            loop_start = old_card_idx.to_usize() + 1;

            let crossing = self.crossing_map.get(new_card_idx);
            let expected = CrossingEntry::FirstObject(offset_words);
            assert!(crossing == expected, "crossing at end not correct.");
        }

        for c in loop_start..new_card_idx.to_usize() {
            assert!(
                self.crossing_map.get(c.into()) == crossing_middle,
                "middle crossing not correct."
            );
        }
    }

    fn verify_reference(
        &mut self,
        obj: *mut Obj,
        ref_addr: Address,
        obj_addr: Address,
        name: &str,
    ) {
        let addr = Address::from_ptr(obj);

        if obj.is_null() {
            return;
        }

        if self.old_region.contains(addr)
            || self.young_region.contains(addr)
            || self.perm_space.contains(addr)
            || self.large.contains(addr)
        {
            let object = unsafe { &mut *obj };

            // Verify that the address is the start of an object,
            // for this access its size.
            // To make sure this isn't optimized out by the compiler,
            // make sure that the size doesn't equal 1.
            assert!(object.size() != 1, "object size shouldn't be 1");

            if self.young_region.contains(addr) {
                self.refs_to_young_gen += 1;
            }

            return;
        }

        let perm_region = self.perm_space.used_region();

        println!(
            "PRM: {}-{}; active: {}-{}",
            self.perm_space.total().start,
            self.perm_space.total().end,
            perm_region.start,
            perm_region.end);
        println!(
            "YNG: {}-{}; active: {}-{}",
            self.young.total.start,
            self.young.total.end,
            self.young_region.start,
            self.young_region.end
        );
        println!(
            "OLD: {}-{}; active: {}-{}",
            self.old.total.start, self.old.total.end, self.old_region.start, self.old_region.end
        );
        println!(
            "LRG: {}-{}",
            self.large.total().start,
            self.large.total().end
        );
        println!(
            "TTL: {}-{}",
            self.reserved_area.start,
            self.reserved_area.end
            );
        println!(
            "found invalid reference to {} in {} (at {}, in object {}).",
            addr, name, ref_addr, obj_addr
        );

        if self.young.contains(addr) && !self.young_region.contains(addr) {
            println!("reference points into young generation but not into the active semi-space.");
        }

        panic!("reference neither pointing into young nor old generation.");
    }
}
<commit_msg>swiper: add output to verify<commit_after>use ctxt::get_ctxt;

use gc::root::IndirectObj;
use gc::space::Space;
use gc::swiper::card::{CardEntry, CardTable};
use gc::swiper::crossing::{CrossingEntry, CrossingMap};
use gc::swiper::large::LargeSpace;
use gc::swiper::old::OldGen;
use gc::swiper::on_different_cards;
use gc::swiper::young::YoungGen;
use gc::swiper::Region;
use gc::swiper::CARD_SIZE;
use gc::Address;

use mem;
use object::{offset_of_array_data, Obj};

#[derive(Copy, Clone)]
pub enum VerifierPhase {
    PreMinor,
    PostMinor,
    PreFull,
    PostFull,
}

impl VerifierPhase {
    fn is_pre(self) -> bool {
        match self {
            VerifierPhase::PreMinor => true,
            VerifierPhase::PostMinor => false,
            VerifierPhase::PreFull => true,
            VerifierPhase::PostFull => false,
        }
    }
}

pub struct Verifier<'a> {
    young: &'a YoungGen,
    old: &'a OldGen,
    card_table: &'a CardTable,
    crossing_map: &'a CrossingMap,
    rootset: &'a [IndirectObj],
    large: &'a LargeSpace,
    perm_space: &'a Space,

    refs_to_young_gen: usize,
    in_old: bool,
    in_large: bool,

    old_region: Region,
    young_region: Region,
    reserved_area: Region,

    phase: VerifierPhase,
}

impl<'a> Verifier<'a> {
    pub fn new(
        young: &'a YoungGen,
        old: &'a OldGen,
        card_table: &'a CardTable,
        crossing_map: &'a CrossingMap,
        rootset: &'a [IndirectObj],
        large: &'a LargeSpace,
        perm_space: &'a Space,
        reserved_area: Region,
        phase: VerifierPhase,
    ) -> Verifier<'a> {
        Verifier {
            young: young,
            old: old,
            card_table: card_table,
            crossing_map: crossing_map,
            rootset: rootset,
            perm_space: perm_space,
            large: large,

            refs_to_young_gen: 0,
            in_old: false,
            in_large: false,

            young_region: young.used_region(),
            old_region: old.used_region(),
            reserved_area: reserved_area,

            phase: phase,
        }
    }

    pub fn verify(&mut self) {
        self.verify_roots();
        self.verify_young();
        self.verify_old();
        self.verify_large();
    }

    fn verify_young(&mut self) {
        let region = self.young_region.clone();
        self.verify_objects(region, "young gen");
    }

    fn verify_old(&mut self) {
        let region = self.old_region.clone();
        self.in_old = true;
        self.verify_objects(region, "old gen");
        self.in_old = false;
    }

    fn verify_large(&mut self) {
        self.in_large = true;
        self.large.visit_objects(|addr| {
            let object = unsafe { &mut *addr.to_mut_ptr::<Obj>() };
            let region = Region::new(addr, addr.offset(object.size()));
            self.verify_objects(region, "large space");
        });
        self.in_large = false;
    }

    fn verify_roots(&mut self) {
        for root in self.rootset {
            let root_ptr = root.get();
            self.verify_reference(root_ptr, root.to_address(), Address::null(), "root set");
        }
    }

    fn verify_objects(&mut self, region: Region, name: &str) {
        let mut curr = region.start;
        self.refs_to_young_gen = 0;

        if self.in_old {
            // we should start at card start
            assert!(self.card_table.is_aligned(curr));
            self.verify_crossing(curr, curr, false);
        }

        while curr < region.end {
            let object = unsafe { &mut *curr.to_mut_ptr::<Obj>() };

            let next = if object.is_array_ref() {
                self.verify_array_ref(object, curr, name)
            } else {
                self.verify_object(object, curr, name)
            };

            curr = next;
        }

        assert!(curr == region.end, "object doesn't end at region end");

        if (self.in_old || self.in_large) && !self.card_table.is_aligned(curr) {
            self.verify_card(curr);
        }
    }

    fn verify_array_ref(&mut self, object: &mut Obj, mut curr: Address, name: &str) -> Address {
        let object_address = curr;

        object.visit_reference_fields(|child| {
            let child_ptr = child.get();

            if (self.in_old || self.in_large) && on_different_cards(curr, child.to_address()) {
                self.verify_card(curr);
                curr = child.to_address();
            }

            self.verify_reference(child_ptr, child.to_address(), object_address, name);
        });

        let next = object_address.offset(object.size());

        if self.in_old && on_different_cards(object_address, next) {
            self.verify_crossing(object_address, next, true);
        }

        next
    }

    fn verify_object(&mut self, object: &mut Obj, curr: Address, name: &str) -> Address {
        object.visit_reference_fields(|child| {
            let child_ptr = child.get();
            self.verify_reference(child_ptr, child.to_address(), curr, name);
        });

        let next = curr.offset(object.size());

        if (self.in_old || self.in_large) && on_different_cards(curr, next) {
            self.verify_card(curr);
            if self.in_old {
                self.verify_crossing(curr, next, false);
            }
        }

        next
    }

    fn verify_card(&mut self, curr: Address) {
        let curr_card = self.card_table.card_idx(curr);

        let card_entry = self.card_table.get(curr_card);
        let expected_card_entry = if self.refs_to_young_gen > 0 {
            CardEntry::Dirty
        } else {
            CardEntry::Clean
        };

        // In the verify-phase before the collection the card's dirty-entry isn't
        // guaranteed to be exact. It could be `dirty` although this card doesn't
        // actually contain any references into the young generation. But it should never
        // be clean when there are actual references into the young generation.
        if self.phase.is_pre() && expected_card_entry == CardEntry::Clean {
            self.refs_to_young_gen = 0;
            return;
        }

        if card_entry != expected_card_entry {
            let card_text = match card_entry {
                CardEntry::Dirty => "dirty",
                CardEntry::Clean => "clean",
            };

            println!(
                "CARD: {} is marked {} but has {} reference(s).",
                curr_card.to_usize(),
                card_text,
                self.refs_to_young_gen
            );

            panic!("card table entry wrong.");
        }

        assert!(card_entry == expected_card_entry);

        self.refs_to_young_gen = 0;
    }

    fn verify_crossing(&mut self, old: Address, new: Address, array_ref: bool) {
        let new_card_idx = self.card_table.card_idx(new);
        let old_card_idx = self.card_table.card_idx(old);

        if new_card_idx == old_card_idx {
            return;
        }

        let new_card_start = self.card_table.to_address(new_card_idx);
        let old_card_end = self.card_table.to_address(old_card_idx).offset(CARD_SIZE);

        let offset = new.offset_from(new_card_start);
        let offset_words = (offset / mem::ptr_width_usize()) as u8;

        let crossing_middle;
        let loop_start;

        if array_ref {
            let refs_per_card = (CARD_SIZE / mem::ptr_width_usize()) as u8;

            crossing_middle = CrossingEntry::LeadingRefs(refs_per_card);

            if old.offset(offset_of_array_data() as usize) > old_card_end {
                let old_next = old_card_idx.to_usize() + 1;
                let crossing = self.crossing_map.get(old_next.into());
                let diff_words = old_card_end.offset_from(old) / mem::ptr_width_usize();
                assert!(crossing == CrossingEntry::ArrayStart(diff_words as u8));

                loop_start = old_card_idx.to_usize() + 2;
            } else {
                loop_start = old_card_idx.to_usize() + 1;
            }

            if new_card_idx.to_usize() >= loop_start {
                let crossing = self.crossing_map.get(new_card_idx);
                let expected = CrossingEntry::LeadingRefs(offset_words);
                assert!(crossing == expected, "array crossing at end not correct.");
            }
        } else {
            crossing_middle = CrossingEntry::NoRefs;
            loop_start = old_card_idx.to_usize() + 1;

            let crossing = self.crossing_map.get(new_card_idx);
            let expected = CrossingEntry::FirstObject(offset_words);
            assert!(crossing == expected, "crossing at end not correct.");
        }

        for c in loop_start..new_card_idx.to_usize() {
            assert!(
                self.crossing_map.get(c.into()) == crossing_middle,
                "middle crossing not correct."
            );
        }
    }

    fn verify_reference(
        &mut self,
        obj: *mut Obj,
        ref_addr: Address,
        obj_addr: Address,
        name: &str,
    ) {
        let addr = Address::from_ptr(obj);

        if obj.is_null() {
            return;
        }

        if self.old_region.contains(addr)
            || self.young_region.contains(addr)
            || self.perm_space.contains(addr)
            || self.large.contains(addr)
        {
            let object = unsafe { &mut *obj };

            // Verify that the address is the start of an object,
            // for this access its size.
            // To make sure this isn't optimized out by the compiler,
            // make sure that the size doesn't equal 1.
            assert!(object.size() != 1, "object size shouldn't be 1");

            if self.young_region.contains(addr) {
                self.refs_to_young_gen += 1;
            }

            return;
        }

        let perm_region = self.perm_space.used_region();

        println!(
            "PRM: {}-{}; active: {}-{}",
            self.perm_space.total().start,
            self.perm_space.total().end,
            perm_region.start,
            perm_region.end);
        println!(
            "YNG: {}-{}; active: {}-{}",
            self.young.total.start,
            self.young.total.end,
            self.young_region.start,
            self.young_region.end
        );
        println!(
            "OLD: {}-{}; active: {}-{}",
            self.old.total.start, self.old.total.end, self.old_region.start, self.old_region.end
        );
        println!(
            "LRG: {}-{}",
            self.large.total().start,
            self.large.total().end
        );
        println!(
            "TTL: {}-{}",
            self.reserved_area.start,
            self.reserved_area.end
            );
        println!(
            "found invalid reference to {} in {} (at {}, in object {}).",
            addr, name, ref_addr, obj_addr
        );

        if self.young.contains(addr) && !self.young_region.contains(addr) {
            println!("reference points into young generation but not into the active semi-space.");
        }

        println!("try print object size and class:");

        let object = unsafe { &mut *obj };
        println!("\tsize {}", object.size());
        let cls = object.header().vtbl().class();
        println!("\tclass {}", cls.name(get_ctxt()));

        panic!("reference neither pointing into young nor old generation.");
    }
}
<|endoftext|>


<commit_before>#![feature(no_std,lang_items,core)]
#![no_std]

#![crate_type = "staticlib"]
#![crate_name = "rustcode"]

#[macro_use]
extern crate core;
extern crate rlibc;

use core::fmt;

#[no_mangle]
pub fn kernel_main() {

}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
//    use core::fmt::Write;
//    log!("\r\nPanic at {}:{}: ", file, line);
//    let _ = console::Console.write_fmt(args);
    loop {};
}
<commit_msg>Painting screen<commit_after>#![feature(no_std,lang_items,core)]
#![no_std]

#![crate_type = "staticlib"]
#![crate_name = "rustcode"]

#![allow(dead_code)]

#[macro_use]
extern crate core;
extern crate rlibc;

use core::prelude::*;
use core::fmt;

enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

fn clear_screen(background: u16) {
    for i in 0..(80 * 25) {
        unsafe {
            *((0xb8000 + i * 2) as *mut u16) = background << 12;
        }
    }
}

/**
 * This is the entry point to the kernel. It is the first rust code that runs.
 */
#[no_mangle]
pub fn kernel_main() {
    let color = Color::LightGreen as u16;
    clear_screen(color);
}

// For bare-bones rust
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
pub extern fn rust_begin_unwind(args: fmt::Arguments,
                                file: &'static str, line: u32) -> ! {
//    use core::fmt::Write;
//    log!("\r\nPanic at {}:{}: ", file, line);
//    let _ = console::Console.write_fmt(args);
    loop {};
}
<|endoftext|>


<commit_before>use crate::ptr::NullPtr;
use crate::{CppBox, CppDeletable, MutPtr, MutRef, Ptr, Ref, StaticUpcast};
use std::ffi::CStr;
use std::os::raw::c_char;

/// Used to do value-to-value conversions while consuming the input value.
pub trait CastFrom<T>: Sized {
    /// Performs the conversion.
    unsafe fn cast_from(_: T) -> Self;
}

pub trait CastInto<T>: Sized {
    unsafe fn cast_into(self) -> T;
}

impl<T, U: CastFrom<T>> CastInto<U> for T {
    unsafe fn cast_into(self) -> U {
        U::cast_from(self)
    }
}

impl<T, U> CastFrom<MutPtr<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutPtr<U>) -> Self {
        <U as StaticUpcast<T>>::static_upcast_mut(value).as_ptr()
    }
}

impl<T, U> CastFrom<MutRef<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
    }
}

impl<T, U> CastFrom<Ref<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ref<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<T, U> CastFrom<MutRef<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T, U> CastFrom<MutRef<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a CppBox<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a CppBox<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a mut CppBox<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a mut CppBox<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a CppBox<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a CppBox<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on CppBox input")
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a mut CppBox<U>> for MutRef<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a mut CppBox<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
            .as_mut_ref()
            .expect("StaticUpcast returned null on CppBox input")
    }
}

impl<T, U> CastFrom<Ptr<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ptr<U>) -> Self {
        StaticUpcast::static_upcast(value)
    }
}

impl<T, U> CastFrom<MutPtr<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutPtr<U>) -> Self {
        StaticUpcast::static_upcast_mut(value)
    }
}

impl<T, U> CastFrom<Ref<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ref<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T, U> CastFrom<MutRef<U>> for MutRef<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
            .as_mut_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T> CastFrom<NullPtr> for Ptr<T> {
    unsafe fn cast_from(_value: NullPtr) -> Self {
        Self::null()
    }
}

impl<T> CastFrom<NullPtr> for MutPtr<T> {
    unsafe fn cast_from(_value: NullPtr) -> Self {
        Self::null()
    }
}

impl<'a> CastFrom<&'a CStr> for MutPtr<c_char> {
    unsafe fn cast_from(value: &'a CStr) -> Self {
        MutPtr::from_c_str(value)
    }
}

impl<'a> CastFrom<&'a CStr> for Ptr<c_char> {
    unsafe fn cast_from(value: &'a CStr) -> Self {
        Ptr::from_c_str(value)
    }
}
<commit_msg>convert raw pointers to Ptr/MutPtr<commit_after>use crate::ptr::NullPtr;
use crate::{CppBox, CppDeletable, MutPtr, MutRef, Ptr, Ref, StaticUpcast};
use std::ffi::CStr;
use std::os::raw::c_char;

/// Used to do value-to-value conversions while consuming the input value.
pub trait CastFrom<T>: Sized {
    /// Performs the conversion.
    unsafe fn cast_from(_: T) -> Self;
}

pub trait CastInto<T>: Sized {
    unsafe fn cast_into(self) -> T;
}

impl<T, U: CastFrom<T>> CastInto<U> for T {
    unsafe fn cast_into(self) -> U {
        U::cast_from(self)
    }
}

impl<T, U> CastFrom<MutPtr<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutPtr<U>) -> Self {
        <U as StaticUpcast<T>>::static_upcast_mut(value).as_ptr()
    }
}

impl<T, U> CastFrom<MutRef<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
    }
}

impl<T, U> CastFrom<Ref<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ref<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<T, U> CastFrom<MutRef<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T, U> CastFrom<MutRef<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a CppBox<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a CppBox<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a mut CppBox<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a mut CppBox<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a CppBox<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a CppBox<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on CppBox input")
    }
}

impl<'a, T, U: CppDeletable> CastFrom<&'a mut CppBox<U>> for MutRef<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: &'a mut CppBox<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
            .as_mut_ref()
            .expect("StaticUpcast returned null on CppBox input")
    }
}

impl<T, U> CastFrom<Ptr<U>> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ptr<U>) -> Self {
        StaticUpcast::static_upcast(value)
    }
}

impl<T, U> CastFrom<MutPtr<U>> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutPtr<U>) -> Self {
        StaticUpcast::static_upcast_mut(value)
    }
}

impl<T, U> CastFrom<Ref<U>> for Ref<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: Ref<U>) -> Self {
        StaticUpcast::static_upcast(value.as_ptr())
            .as_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T, U> CastFrom<MutRef<U>> for MutRef<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: MutRef<U>) -> Self {
        StaticUpcast::static_upcast_mut(value.as_mut_ptr())
            .as_mut_ref()
            .expect("StaticUpcast returned null on Ref input")
    }
}

impl<T> CastFrom<NullPtr> for Ptr<T> {
    unsafe fn cast_from(_value: NullPtr) -> Self {
        Self::null()
    }
}

impl<T> CastFrom<NullPtr> for MutPtr<T> {
    unsafe fn cast_from(_value: NullPtr) -> Self {
        Self::null()
    }
}

impl<'a> CastFrom<&'a CStr> for MutPtr<c_char> {
    unsafe fn cast_from(value: &'a CStr) -> Self {
        MutPtr::from_c_str(value)
    }
}

impl<'a> CastFrom<&'a CStr> for Ptr<c_char> {
    unsafe fn cast_from(value: &'a CStr) -> Self {
        Ptr::from_c_str(value)
    }
}

impl<T, U> CastFrom<*const U> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: *const U) -> Self {
        Self::cast_from(Ptr::from_raw(value))
    }
}

impl<T, U> CastFrom<*mut U> for Ptr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: *mut U) -> Self {
        Self::cast_from(Ptr::from_raw(value as *const U))
    }
}

impl<T, U> CastFrom<*mut U> for MutPtr<T>
where
    U: StaticUpcast<T>,
{
    unsafe fn cast_from(value: *mut U) -> Self {
        Self::cast_from(MutPtr::from_raw(value))
    }
}
<|endoftext|>


<commit_before>//! This module handles auto-magic editing actions applied together with users
//! edits. For example, if the user typed
//!
//! ```text
//!     foo
//!         .bar()
//!         .baz()
//!     |   // <- cursor is here
//! ```
//!
//! and types `.` next, we want to indent the dot.
//!
//! Language server executes such typing assists synchronously. That is, they
//! block user's typing and should be pretty fast for this reason!

mod on_enter;

use ide_db::{
    base_db::{FilePosition, SourceDatabase},
    RootDatabase,
};
use syntax::{
    algo::find_node_at_offset,
    ast::{self, edit::IndentLevel, AstToken},
    AstNode, Parse, SourceFile,
    SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
    TextRange, TextSize,
};

use text_edit::{Indel, TextEdit};

use crate::SourceChange;

pub(crate) use on_enter::on_enter;

// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
pub(crate) const TRIGGER_CHARS: &str = ".=>{";

// Feature: On Typing Assists
//
// Some features trigger on typing certain characters:
//
// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
// - typing `.` in a chain method call auto-indents
//
// VS Code::
//
// Add the following to `settings.json`:
// [source,json]
// ----
// "editor.formatOnType": true,
// ----
//
// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[]
// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[]
pub(crate) fn on_char_typed(
    db: &RootDatabase,
    position: FilePosition,
    char_typed: char,
) -> Option<SourceChange> {
    assert!(TRIGGER_CHARS.contains(char_typed));
    let file = &db.parse(position.file_id);
    assert_eq!(file.tree().syntax().text().char_at(position.offset), Some(char_typed));
    let edit = on_char_typed_inner(file, position.offset, char_typed)?;
    Some(SourceChange::from_text_edit(position.file_id, edit))
}

fn on_char_typed_inner(
    file: &Parse<SourceFile>,
    offset: TextSize,
    char_typed: char,
) -> Option<TextEdit> {
    assert!(TRIGGER_CHARS.contains(char_typed));
    match char_typed {
        '.' => on_dot_typed(&file.tree(), offset),
        '=' => on_eq_typed(&file.tree(), offset),
        '>' => on_arrow_typed(&file.tree(), offset),
        '{' => on_opening_brace_typed(file, offset),
        _ => unreachable!(),
    }
}

/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
/// block.
fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
    stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{'));

    let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;

    // Remove the `{` to get a better parse tree, and reparse
    let file = file.reparse(&Indel::delete(brace_token.text_range()));

    let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
    if expr.syntax().text_range().start() != offset {
        return None;
    }

    // Enclose the outermost expression starting at `offset`
    while let Some(parent) = expr.syntax().parent() {
        if parent.text_range().start() != expr.syntax().text_range().start() {
            break;
        }

        match ast::Expr::cast(parent) {
            Some(parent) => expr = parent,
            None => break,
        }
    }

    // If it's a statement in a block, we don't know how many statements should be included
    if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
        return None;
    }

    // Insert `}` right after the expression.
    Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
}

/// Returns an edit which should be applied after `=` was typed. Primarily,
/// this works when adding `let =`.
// FIXME: use a snippet completion instead of this hack here.
fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    stdx::always!(file.syntax().text().char_at(offset) == Some('='));
    let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
    if let_stmt.semicolon_token().is_some() {
        return None;
    }
    if let Some(expr) = let_stmt.initializer() {
        let expr_range = expr.syntax().text_range();
        if expr_range.contains(offset) && offset != expr_range.start() {
            return None;
        }
        if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') {
            return None;
        }
    } else {
        return None;
    }
    let offset = let_stmt.syntax().text_range().end();
    Some(TextEdit::insert(offset, ";".to_string()))
}

/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    stdx::always!(file.syntax().text().char_at(offset) == Some('.'));
    let whitespace =
        file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;

    let current_indent = {
        let text = whitespace.text();
        let newline = text.rfind('\n')?;
        &text[newline + 1..]
    };
    let current_indent_len = TextSize::of(current_indent);

    let parent = whitespace.syntax().parent()?;
    // Make sure dot is a part of call chain
    if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) {
        return None;
    }
    let prev_indent = IndentLevel::from_node(&parent);
    let target_indent = format!("    {}", prev_indent);
    let target_indent_len = TextSize::of(&target_indent);
    if current_indent_len == target_indent_len {
        return None;
    }

    Some(TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent))
}

/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    let file_text = file.syntax().text();
    stdx::always!(file_text.char_at(offset) == Some('>'));
    let after_arrow = offset + TextSize::of('>');
    if file_text.char_at(after_arrow) != Some('{') {
        return None;
    }
    if find_node_at_offset::<ast::RetType>(file.syntax(), offset).is_none() {
        return None;
    }

    Some(TextEdit::insert(after_arrow, " ".to_string()))
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_offset};

    use super::*;

    fn do_type_char(char_typed: char, before: &str) -> Option<String> {
        let (offset, mut before) = extract_offset(before);
        let edit = TextEdit::insert(offset, char_typed.to_string());
        edit.apply(&mut before);
        let parse = SourceFile::parse(&before);
        on_char_typed_inner(&parse, offset, char_typed).map(|it| {
            it.apply(&mut before);
            before.to_string()
        })
    }

    fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) {
        let actual = do_type_char(char_typed, ra_fixture_before)
            .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed));

        assert_eq_text!(ra_fixture_after, &actual);
    }

    fn type_char_noop(char_typed: char, before: &str) {
        let file_change = do_type_char(char_typed, before);
        assert!(file_change.is_none())
    }

    #[test]
    fn test_on_eq_typed() {
        //     do_check(r"
        // fn foo() {
        //     let foo =$0
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        // }
        // ");
        type_char(
            '=',
            r"
fn foo() {
    let foo $0 1 + 1
}
",
            r"
fn foo() {
    let foo = 1 + 1;
}
",
        );
        //     do_check(r"
        // fn foo() {
        //     let foo =$0
        //     let bar = 1;
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        //     let bar = 1;
        // }
        // ");
    }

    #[test]
    fn indents_new_chain_call() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                $0
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    $0
            }
            ",
        )
    }

    #[test]
    fn indents_new_chain_call_with_semi() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                $0;
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .;
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    $0;
            }
            ",
        )
    }

    #[test]
    fn indents_new_chain_call_with_let() {
        type_char(
            '.',
            r#"
fn main() {
    let _ = foo
    $0
    bar()
}
"#,
            r#"
fn main() {
    let _ = foo
        .
    bar()
}
"#,
        );
    }

    #[test]
    fn indents_continued_chain_call() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                    .first()
                $0
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .first()
                    .
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    .first()
                    $0
            }
            ",
        );
    }

    #[test]
    fn indents_middle_of_chain_call() {
        type_char(
            '.',
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                $0
                    .nth(92)
                    .unwrap();
            }
            ",
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                    .
                    .nth(92)
                    .unwrap();
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                    $0
                    .nth(92)
                    .unwrap();
            }
            ",
        );
    }

    #[test]
    fn dont_indent_freestanding_dot() {
        type_char_noop(
            '.',
            r"
            fn main() {
                $0
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
            $0
            }
            ",
        );
    }

    #[test]
    fn adds_space_after_return_type() {
        type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
    }

    #[test]
    fn adds_closing_brace() {
        type_char(
            '{',
            r#"
fn f() { match () { _ => $0() } }
            "#,
            r#"
fn f() { match () { _ => {()} } }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { $0() }
            "#,
            r#"
fn f() { {()} }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { let x = $0(); }
            "#,
            r#"
fn f() { let x = {()}; }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { let x = $0a.b(); }
            "#,
            r#"
fn f() { let x = {a.b()}; }
            "#,
        );
        type_char(
            '{',
            r#"
const S: () = $0();
fn f() {}
            "#,
            r#"
const S: () = {()};
fn f() {}
            "#,
        );
        type_char(
            '{',
            r#"
const S: () = $0a.b();
fn f() {}
            "#,
            r#"
const S: () = {a.b()};
fn f() {}
            "#,
        );
        type_char(
            '{',
            r#"
fn f() {
    match x {
        0 => $0(),
        1 => (),
    }
}
            "#,
            r#"
fn f() {
    match x {
        0 => {()},
        1 => (),
    }
}
            "#,
        );
    }
}
<commit_msg>Make better use of `stdx::always`<commit_after>//! This module handles auto-magic editing actions applied together with users
//! edits. For example, if the user typed
//!
//! ```text
//!     foo
//!         .bar()
//!         .baz()
//!     |   // <- cursor is here
//! ```
//!
//! and types `.` next, we want to indent the dot.
//!
//! Language server executes such typing assists synchronously. That is, they
//! block user's typing and should be pretty fast for this reason!

mod on_enter;

use ide_db::{
    base_db::{FilePosition, SourceDatabase},
    RootDatabase,
};
use syntax::{
    algo::find_node_at_offset,
    ast::{self, edit::IndentLevel, AstToken},
    AstNode, Parse, SourceFile,
    SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
    TextRange, TextSize,
};

use text_edit::{Indel, TextEdit};

use crate::SourceChange;

pub(crate) use on_enter::on_enter;

// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
pub(crate) const TRIGGER_CHARS: &str = ".=>{";

// Feature: On Typing Assists
//
// Some features trigger on typing certain characters:
//
// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
// - typing `.` in a chain method call auto-indents
//
// VS Code::
//
// Add the following to `settings.json`:
// [source,json]
// ----
// "editor.formatOnType": true,
// ----
//
// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[]
// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[]
pub(crate) fn on_char_typed(
    db: &RootDatabase,
    position: FilePosition,
    char_typed: char,
) -> Option<SourceChange> {
    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
        return None;
    }
    let file = &db.parse(position.file_id);
    if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) {
        return None;
    }
    let edit = on_char_typed_inner(file, position.offset, char_typed)?;
    Some(SourceChange::from_text_edit(position.file_id, edit))
}

fn on_char_typed_inner(
    file: &Parse<SourceFile>,
    offset: TextSize,
    char_typed: char,
) -> Option<TextEdit> {
    if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
        return None;
    }
    match char_typed {
        '.' => on_dot_typed(&file.tree(), offset),
        '=' => on_eq_typed(&file.tree(), offset),
        '>' => on_arrow_typed(&file.tree(), offset),
        '{' => on_opening_brace_typed(file, offset),
        _ => unreachable!(),
    }
}

/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
/// block.
fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
    if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
        return None;
    }

    let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;

    // Remove the `{` to get a better parse tree, and reparse
    let file = file.reparse(&Indel::delete(brace_token.text_range()));

    let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
    if expr.syntax().text_range().start() != offset {
        return None;
    }

    // Enclose the outermost expression starting at `offset`
    while let Some(parent) = expr.syntax().parent() {
        if parent.text_range().start() != expr.syntax().text_range().start() {
            break;
        }

        match ast::Expr::cast(parent) {
            Some(parent) => expr = parent,
            None => break,
        }
    }

    // If it's a statement in a block, we don't know how many statements should be included
    if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
        return None;
    }

    // Insert `}` right after the expression.
    Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
}

/// Returns an edit which should be applied after `=` was typed. Primarily,
/// this works when adding `let =`.
// FIXME: use a snippet completion instead of this hack here.
fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
        return None;
    }
    let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
    if let_stmt.semicolon_token().is_some() {
        return None;
    }
    if let Some(expr) = let_stmt.initializer() {
        let expr_range = expr.syntax().text_range();
        if expr_range.contains(offset) && offset != expr_range.start() {
            return None;
        }
        if file.syntax().text().slice(offset..expr_range.start()).contains_char('\n') {
            return None;
        }
    } else {
        return None;
    }
    let offset = let_stmt.syntax().text_range().end();
    Some(TextEdit::insert(offset, ";".to_string()))
}

/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
        return None;
    }
    let whitespace =
        file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;

    let current_indent = {
        let text = whitespace.text();
        let newline = text.rfind('\n')?;
        &text[newline + 1..]
    };
    let current_indent_len = TextSize::of(current_indent);

    let parent = whitespace.syntax().parent()?;
    // Make sure dot is a part of call chain
    if !matches!(parent.kind(), FIELD_EXPR | METHOD_CALL_EXPR) {
        return None;
    }
    let prev_indent = IndentLevel::from_node(&parent);
    let target_indent = format!("    {}", prev_indent);
    let target_indent_len = TextSize::of(&target_indent);
    if current_indent_len == target_indent_len {
        return None;
    }

    Some(TextEdit::replace(TextRange::new(offset - current_indent_len, offset), target_indent))
}

/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
    let file_text = file.syntax().text();
    if !stdx::always!(file_text.char_at(offset) == Some('>')) {
        return None;
    }
    let after_arrow = offset + TextSize::of('>');
    if file_text.char_at(after_arrow) != Some('{') {
        return None;
    }
    if find_node_at_offset::<ast::RetType>(file.syntax(), offset).is_none() {
        return None;
    }

    Some(TextEdit::insert(after_arrow, " ".to_string()))
}

#[cfg(test)]
mod tests {
    use test_utils::{assert_eq_text, extract_offset};

    use super::*;

    fn do_type_char(char_typed: char, before: &str) -> Option<String> {
        let (offset, mut before) = extract_offset(before);
        let edit = TextEdit::insert(offset, char_typed.to_string());
        edit.apply(&mut before);
        let parse = SourceFile::parse(&before);
        on_char_typed_inner(&parse, offset, char_typed).map(|it| {
            it.apply(&mut before);
            before.to_string()
        })
    }

    fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) {
        let actual = do_type_char(char_typed, ra_fixture_before)
            .unwrap_or_else(|| panic!("typing `{}` did nothing", char_typed));

        assert_eq_text!(ra_fixture_after, &actual);
    }

    fn type_char_noop(char_typed: char, before: &str) {
        let file_change = do_type_char(char_typed, before);
        assert!(file_change.is_none())
    }

    #[test]
    fn test_on_eq_typed() {
        //     do_check(r"
        // fn foo() {
        //     let foo =$0
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        // }
        // ");
        type_char(
            '=',
            r"
fn foo() {
    let foo $0 1 + 1
}
",
            r"
fn foo() {
    let foo = 1 + 1;
}
",
        );
        //     do_check(r"
        // fn foo() {
        //     let foo =$0
        //     let bar = 1;
        // }
        // ", r"
        // fn foo() {
        //     let foo =;
        //     let bar = 1;
        // }
        // ");
    }

    #[test]
    fn indents_new_chain_call() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                $0
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    $0
            }
            ",
        )
    }

    #[test]
    fn indents_new_chain_call_with_semi() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                $0;
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .;
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    $0;
            }
            ",
        )
    }

    #[test]
    fn indents_new_chain_call_with_let() {
        type_char(
            '.',
            r#"
fn main() {
    let _ = foo
    $0
    bar()
}
"#,
            r#"
fn main() {
    let _ = foo
        .
    bar()
}
"#,
        );
    }

    #[test]
    fn indents_continued_chain_call() {
        type_char(
            '.',
            r"
            fn main() {
                xs.foo()
                    .first()
                $0
            }
            ",
            r"
            fn main() {
                xs.foo()
                    .first()
                    .
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
                xs.foo()
                    .first()
                    $0
            }
            ",
        );
    }

    #[test]
    fn indents_middle_of_chain_call() {
        type_char(
            '.',
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                $0
                    .nth(92)
                    .unwrap();
            }
            ",
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                    .
                    .nth(92)
                    .unwrap();
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn source_impl() {
                let var = enum_defvariant_list().unwrap()
                    $0
                    .nth(92)
                    .unwrap();
            }
            ",
        );
    }

    #[test]
    fn dont_indent_freestanding_dot() {
        type_char_noop(
            '.',
            r"
            fn main() {
                $0
            }
            ",
        );
        type_char_noop(
            '.',
            r"
            fn main() {
            $0
            }
            ",
        );
    }

    #[test]
    fn adds_space_after_return_type() {
        type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }")
    }

    #[test]
    fn adds_closing_brace() {
        type_char(
            '{',
            r#"
fn f() { match () { _ => $0() } }
            "#,
            r#"
fn f() { match () { _ => {()} } }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { $0() }
            "#,
            r#"
fn f() { {()} }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { let x = $0(); }
            "#,
            r#"
fn f() { let x = {()}; }
            "#,
        );
        type_char(
            '{',
            r#"
fn f() { let x = $0a.b(); }
            "#,
            r#"
fn f() { let x = {a.b()}; }
            "#,
        );
        type_char(
            '{',
            r#"
const S: () = $0();
fn f() {}
            "#,
            r#"
const S: () = {()};
fn f() {}
            "#,
        );
        type_char(
            '{',
            r#"
const S: () = $0a.b();
fn f() {}
            "#,
            r#"
const S: () = {a.b()};
fn f() {}
            "#,
        );
        type_char(
            '{',
            r#"
fn f() {
    match x {
        0 => $0(),
        1 => (),
    }
}
            "#,
            r#"
fn f() {
    match x {
        0 => {()},
        1 => (),
    }
}
            "#,
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Fixed closure syntax<commit_after><|endoftext|>


<commit_before><commit_msg>New struct `Factory` with empty `new` impl<commit_after><|endoftext|>


<commit_before><commit_msg>Bring parameters into range for fuzz_encode_decode<commit_after><|endoftext|>


<commit_before><commit_msg>Added serve_listings check<commit_after><|endoftext|>


<commit_before><commit_msg>Move buf generation out of the loop in write_metadata<commit_after><|endoftext|>


<commit_before>use crate::ToTokens;
use proc_macro2::{Span, TokenStream};

pub trait Spanned {
    fn span(&self) -> Span;
}

impl Spanned for Span {
    fn span(&self) -> Span {
        *self
    }
}

impl<T: ToTokens> Spanned for T {
    fn span(&self) -> Span {
        join_spans(self.into_token_stream())
    }
}

fn join_spans(tokens: TokenStream) -> Span {
    let mut iter = tokens.into_iter().filter_map(|tt| {
        // FIXME: This shouldn't be required, since optimally spans should
        // never be invalid. This filter_map can probably be removed when
        // https://github.com/rust-lang/rust/issues/43081 is resolved.
        let span = tt.span();
        let debug = format!("{:?}", span);
        if debug.ends_with("bytes(0..0)") {
            None
        } else {
            Some(span)
        }
    });

    let first = match iter.next() {
        Some(span) => span,
        None => return Span::call_site(),
    };

    #[cfg(procmacro2_semver_exempt)]
    return iter
        .fold(None, |_prev, next| Some(next))
        .and_then(|last| first.join(last))
        .unwrap_or(first);

    // We can't join spans without procmacro2_semver_exempt so just grab the
    // first one.
    #[cfg(not(procmacro2_semver_exempt))]
    return first;
}
<commit_msg>Rename method of Spanned to avoid conflict with syn Spanned<commit_after>use crate::ToTokens;
use proc_macro2::{Span, TokenStream};

pub trait Spanned {
    fn __span(&self) -> Span;
}

impl Spanned for Span {
    fn __span(&self) -> Span {
        *self
    }
}

impl<T: ToTokens> Spanned for T {
    fn __span(&self) -> Span {
        join_spans(self.into_token_stream())
    }
}

fn join_spans(tokens: TokenStream) -> Span {
    let mut iter = tokens.into_iter().filter_map(|tt| {
        // FIXME: This shouldn't be required, since optimally spans should
        // never be invalid. This filter_map can probably be removed when
        // https://github.com/rust-lang/rust/issues/43081 is resolved.
        let span = tt.span();
        let debug = format!("{:?}", span);
        if debug.ends_with("bytes(0..0)") {
            None
        } else {
            Some(span)
        }
    });

    let first = match iter.next() {
        Some(span) => span,
        None => return Span::call_site(),
    };

    #[cfg(procmacro2_semver_exempt)]
    return iter
        .fold(None, |_prev, next| Some(next))
        .and_then(|last| first.join(last))
        .unwrap_or(first);

    // We can't join spans without procmacro2_semver_exempt so just grab the
    // first one.
    #[cfg(not(procmacro2_semver_exempt))]
    return first;
}
<|endoftext|>


<commit_before>use rutorch::*;
use std::ops::{Index, IndexMut};
//use std::convert::From;
use std::slice;

pub trait Storage {
    fn new() -> Self;
    fn with_capacity(len: isize) -> Self;
}

pub struct FloatStorage {
    pub t: *mut THFloatStorage,
}

impl Storage for FloatStorage {
    fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    fn with_capacity(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
}
// XXX annotate with lifetime for safety's sake
impl FloatStorage {
    fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;

    fn index(&self, idx: isize) -> &f32 {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}

impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut f32 {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;
<commit_msg>add LongStorage<commit_after>use rutorch::*;
use std::ops::{Index, IndexMut};
use std::slice;

pub struct FloatStorage {
    pub t: *mut THFloatStorage,
}
impl Drop for FloatStorage {
    fn drop(&mut self) {
        unsafe {THFloatStorage_free(self.t) }
    }
}
impl FloatStorage {
    pub fn new() -> Self {
        unsafe { FloatStorage { t: THFloatStorage_new() } }
    }
    pub fn with_capacity(size: isize) -> Self {
        unsafe { FloatStorage { t: THFloatStorage_newWithSize(size) } }
    }
    pub fn into_slice(&self) -> &[f32] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    pub fn into_slice_mut(&mut self) -> &mut [f32] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<f32> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<f32> {
        self.into_slice_mut().iter_mut()
    }
}

pub struct LongStorage {
    pub t: *mut THLongStorage,
}
impl Drop for LongStorage {
    fn drop(&mut self) {
        unsafe {THLongStorage_free(self.t) }
    }
}
impl LongStorage {
    pub fn new() -> Self {
        unsafe { LongStorage { t: THLongStorage_new() } }
    }
    pub fn with_capacity(size: isize) -> Self {
        unsafe { LongStorage { t: THLongStorage_newWithSize(size) } }
    }
    pub fn into_slice(&self) -> &[i64] {
        unsafe { slice::from_raw_parts((*self.t).data, (*self.t).size as usize) }
    }
    pub fn into_slice_mut(&mut self) -> &mut [i64] {
        unsafe { slice::from_raw_parts_mut((*self.t).data, (*self.t).size as usize) }
    }
    pub fn iter(&self) -> slice::Iter<i64> {
        self.into_slice().iter()
    }
    pub fn iter_mut(&mut self) -> slice::IterMut<i64> {
        self.into_slice_mut().iter_mut()
    }
}

impl Index<isize> for FloatStorage {
    type Output = f32;
    fn index(&self, idx: isize) -> &Self::Output {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}
impl IndexMut<isize> for FloatStorage {
    fn index_mut(&mut self, idx: isize) -> &mut Self::Output {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

impl Index<isize> for LongStorage {
    type Output = i64;
    fn index(&self, idx: isize) -> &Self::Output {
        unsafe { &*(*self.t).data.offset(idx) }
    }
}
impl IndexMut<isize> for LongStorage {
    fn index_mut(&mut self, idx: isize) -> &mut Self::Output {
        unsafe { &mut *(*self.t).data.offset(idx) }
    }
}

//fn from(args: &ArgsArray<T>) -> Self;
<|endoftext|>


<commit_before>import stb_image::*;
import stb_image::bindgen::*;
import libc::types::os::arch::c95::c_int;
import ptr::{addr_of, is_null};
import str::as_c_str;
import vec::unsafe::from_buf;

class image {
    let width: uint;
    let height: uint;
    let depth: uint;
    let data: ~[u8];

    new(width: uint, height: uint, depth: uint, -data: ~[u8]) {
        self.width = width;
        self.height = height;
        self.depth = depth;
        self.data = data;
    }
}

fn load(path: str) -> image unsafe {
    let mut width = 0 as c_int;
    let mut height = 0 as c_int;
    let mut depth = 0 as c_int;
    let buffer = as_c_str(path, |bytes| {
        stbi_load(bytes, addr_of(width), addr_of(height), addr_of(depth), 0 as c_int)
    });
    if is_null(buffer) {
        fail "failed to load image";
    }

    // FIXME: Shouldn't copy; instead we should use a sendable resource. They
    // aren't particularly safe yet though.
    let data = from_buf(buffer, (width * height * depth) as uint);
    ret image(width as uint, height as uint, depth as uint, data);
}

<commit_msg>fixed deprecated string syntax<commit_after>import stb_image::*;
import stb_image::bindgen::*;
import libc::types::os::arch::c95::c_int;
import ptr::{addr_of, is_null};
import str::as_c_str;
import vec::unsafe::from_buf;

class image {
    let width: uint;
    let height: uint;
    let depth: uint;
    let data: ~[u8];

    new(width: uint, height: uint, depth: uint, -data: ~[u8]) {
        self.width = width;
        self.height = height;
        self.depth = depth;
        self.data = data;
    }
}

fn load(path: ~str) -> image unsafe {
    let mut width = 0 as c_int;
    let mut height = 0 as c_int;
    let mut depth = 0 as c_int;
    let buffer = as_c_str(path, |bytes| {
        stbi_load(bytes, addr_of(width), addr_of(height), addr_of(depth), 0 as c_int)
    });
    if is_null(buffer) {
        fail ~"failed to load image";
    }

    // FIXME: Shouldn't copy; instead we should use a sendable resource. They
    // aren't particularly safe yet though.
    let data = from_buf(buffer, (width * height * depth) as uint);
    ret image(width as uint, height as uint, depth as uint, data);
}

<|endoftext|>


<commit_before>use serde::{
    de::DeserializeOwned,
    Serialize,
    Deserialize,
};

use std::{
    cmp::Ordering::{
        Equal,
        Greater,
        Less,
    },
    path::Path,
};

use anyhow::{
    anyhow,
    Result,
};
use itertools::Itertools;

use rnc_core::psql::JsonlIterator;

pub trait HasIndex {
    fn index(&self) -> usize;
}

pub enum Criteria {
    AnyNumber,
    AtleastOne,
    ExactlyOne,
    ZeroOrOne,
}

#[derive(Serialize, Deserialize)]
pub enum Grouped<T>
{
    Multiple {
        id: usize,
        data: Vec<T>,
    },
    Optional {
        id: usize,
        data: Option<T>,
    },
    Required {
        id: usize,
        data: T,
    },
}

impl<T> Grouped<T>
where
    T: Serialize + DeserializeOwned,
{
    fn empty(criteria: &Criteria, id: usize) -> Result<Grouped<T>> {
        match criteria {
            Criteria::AnyNumber => Ok(Self::Multiple {
                id,
                data: Vec::new(),
            }),
            Criteria::AtleastOne => Err(anyhow!("Missing data for id: {}", id)),
            Criteria::ExactlyOne => Err(anyhow!("Missing data for id: {}", id)),
            Criteria::ZeroOrOne => Ok(Self::Optional {
                id,
                data: None,
            }),
        }
    }

    fn build(criteria: &Criteria, id: usize, items: Vec<T>) -> Result<Grouped<T>> {
        match (criteria, items.len()) {
            (Criteria::AnyNumber, 0) => Ok(Self::Multiple {
                id,
                data: Vec::new(),
            }),
            (Criteria::AnyNumber, _) => Ok(Self::Multiple {
                id,
                data: items,
            }),
            (Criteria::AtleastOne, 0) => Err(anyhow!("Missing at least one item for {}", id)),
            (Criteria::AtleastOne, _) => Ok(Self::Multiple {
                id,
                data: items,
            }),
            (Criteria::ExactlyOne, 0) => Err(anyhow!("Missing required items for {}", id)),
            (Criteria::ExactlyOne, 1) => Ok(Self::Required {
                id,
                data: items.into_iter().next().unwrap(),
            }),
            (Criteria::ExactlyOne, l) => {
                Err(anyhow!("Too many items ({}) for id: {}, expected 1", l, id))
            },
            (Criteria::ZeroOrOne, 0) => Ok(Self::Optional {
                id,
                data: None,
            }),
            (Criteria::ZeroOrOne, 1) => Ok(Self::Optional {
                id,
                data: items.into_iter().next(),
            }),
            (Criteria::ZeroOrOne, l) => {
                Err(anyhow!("Too many items ({}) for {}, expected 0 or 1", l, id))
            },
        }
    }
}

pub fn group<T>(criteria: Criteria, path: &Path, max: usize, output: &Path) -> Result<()>
where
    T: DeserializeOwned + HasIndex + Serialize,
{
    let reader = rnc_utils::buf_reader(path)?;
    let mut writer = rnc_utils::buf_writer(output)?;

    let data = JsonlIterator::from_read(reader);
    let data = data.group_by(T::index);

    let mut expected = 1;
    for (id, entries) in &data {
        match (&expected).cmp(&id) {
            Less => {
                while expected < id {
                    let empty: Grouped<T> = Grouped::empty(&criteria, expected)?;
                    serde_json::to_writer(&mut writer, &empty)?;
                    writeln!(&mut writer)?;
                    expected += 1;
                }
                assert!(expected == id);
                let group = Grouped::build(&criteria, expected, entries.collect())?;
                serde_json::to_writer(&mut writer, &group)?;
                writeln!(&mut writer)?;
                expected += 1;
            },
            Equal => {
                let data: Vec<T> = entries.collect();
                let grouped = Grouped::build(&criteria, id, data)?;
                serde_json::to_writer(&mut writer, &grouped)?;
                writeln!(&mut writer)?;
                expected += 1;
            },
            Greater => {
                return Err(anyhow!("Somehow got too small index {}", id));
            },
        }

        if expected != id + 1 {
            return Err(anyhow!("Current out of sync with expected {} {}", expected, id));
        }
    }

    match expected.cmp(&max) {
        Less => {
            while expected <= max {
                let empty: Grouped<T> = Grouped::empty(&criteria, expected)?;
                serde_json::to_writer(&mut writer, &empty)?;
                writeln!(&mut writer)?;
                expected += 1;
            }
        },
        Equal => (),
        Greater => {
            return Err(anyhow!("Got more items {} than expected {}", &expected, &max));
        },
    }

    assert!(expected == max);

    Ok(())
}
<commit_msg>Improve adding trailing empty items<commit_after>use serde::{
    de::DeserializeOwned,
    Serialize,
    Deserialize,
};

use std::{
    cmp::Ordering::{
        Equal,
        Greater,
        Less,
    },
    path::Path,
};

use anyhow::{
    anyhow,
    Result,
};
use itertools::Itertools;

use rnc_core::psql::JsonlIterator;

pub trait HasIndex {
    fn index(&self) -> usize;
}

pub enum Criteria {
    AnyNumber,
    AtleastOne,
    ExactlyOne,
    ZeroOrOne,
}

#[derive(Serialize, Deserialize)]
pub enum Grouped<T>
{
    Multiple {
        id: usize,
        data: Vec<T>,
    },
    Optional {
        id: usize,
        data: Option<T>,
    },
    Required {
        id: usize,
        data: T,
    },
}

impl<T> Grouped<T>
where
    T: Serialize + DeserializeOwned,
{
    fn empty(criteria: &Criteria, id: usize) -> Result<Grouped<T>> {
        match criteria {
            Criteria::AnyNumber => Ok(Self::Multiple {
                id,
                data: Vec::new(),
            }),
            Criteria::AtleastOne => Err(anyhow!("Missing data for id: {}", id)),
            Criteria::ExactlyOne => Err(anyhow!("Missing data for id: {}", id)),
            Criteria::ZeroOrOne => Ok(Self::Optional {
                id,
                data: None,
            }),
        }
    }

    fn build(criteria: &Criteria, id: usize, items: Vec<T>) -> Result<Grouped<T>> {
        match (criteria, items.len()) {
            (Criteria::AnyNumber, 0) => Ok(Self::Multiple {
                id,
                data: Vec::new(),
            }),
            (Criteria::AnyNumber, _) => Ok(Self::Multiple {
                id,
                data: items,
            }),
            (Criteria::AtleastOne, 0) => Err(anyhow!("Missing at least one item for {}", id)),
            (Criteria::AtleastOne, _) => Ok(Self::Multiple {
                id,
                data: items,
            }),
            (Criteria::ExactlyOne, 0) => Err(anyhow!("Missing required items for {}", id)),
            (Criteria::ExactlyOne, 1) => Ok(Self::Required {
                id,
                data: items.into_iter().next().unwrap(),
            }),
            (Criteria::ExactlyOne, l) => {
                Err(anyhow!("Too many items ({}) for id: {}, expected 1", l, id))
            },
            (Criteria::ZeroOrOne, 0) => Ok(Self::Optional {
                id,
                data: None,
            }),
            (Criteria::ZeroOrOne, 1) => Ok(Self::Optional {
                id,
                data: items.into_iter().next(),
            }),
            (Criteria::ZeroOrOne, l) => {
                Err(anyhow!("Too many items ({}) for {}, expected 0 or 1", l, id))
            },
        }
    }
}

pub fn group<T>(criteria: Criteria, path: &Path, max: usize, output: &Path) -> Result<()>
where
    T: DeserializeOwned + HasIndex + Serialize,
{
    let reader = rnc_utils::buf_reader(path)?;
    let mut writer = rnc_utils::buf_writer(output)?;

    let data = JsonlIterator::from_read(reader);
    let data = data.group_by(T::index);

    let mut expected = 1;
    for (id, entries) in &data {
        match (&expected).cmp(&id) {
            Less => {
                while expected < id {
                    let empty: Grouped<T> = Grouped::empty(&criteria, expected)?;
                    serde_json::to_writer(&mut writer, &empty)?;
                    writeln!(&mut writer)?;
                    expected += 1;
                }
                assert!(expected == id);
                let group = Grouped::build(&criteria, expected, entries.collect())?;
                serde_json::to_writer(&mut writer, &group)?;
                writeln!(&mut writer)?;
                expected += 1;
            },
            Equal => {
                let data: Vec<T> = entries.collect();
                let grouped = Grouped::build(&criteria, id, data)?;
                serde_json::to_writer(&mut writer, &grouped)?;
                writeln!(&mut writer)?;
                expected += 1;
            },
            Greater => {
                return Err(anyhow!("Somehow got too small index {}", id));
            },
        }

        if expected != id + 1 {
            return Err(anyhow!("Current out of sync with expected {} {}", expected, id));
        }
    }

    match expected.cmp(&max) {
        Less => {
            while expected < max {
                let empty: Grouped<T> = Grouped::empty(&criteria, expected)?;
                serde_json::to_writer(&mut writer, &empty)?;
                writeln!(&mut writer)?;
                expected += 1;
            }
            let empty: Grouped<T> = Grouped::empty(&criteria, expected)?;
            serde_json::to_writer(&mut writer, &empty)?;
            writeln!(&mut writer)?;
        },
        Equal => (),
        Greater => {
            return Err(anyhow!("Got more items {} than expected {}", &expected, &max));
        },
    }

    assert!(expected == max, "Did not reach {}, at {}", &max, &expected);

    Ok(())
}
<|endoftext|>


<commit_before>//! Tools for parsing [Cargo configuration](https://doc.rust-lang.org/cargo/reference/config.html) files

use std::collections::BTreeMap;
use std::fs;
use std::path::Path;
use std::str::FromStr;

use anyhow::Result;
use serde::{Deserialize, Serialize};

/// The [`[registry]`](https://doc.rust-lang.org/cargo/reference/config.html#registry)
/// table controls the default registry used when one is not specified.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Registry {
    /// name of the default registry
    pub default: String,

    /// authentication token for crates.io
    pub token: Option<String>,
}

/// The [`[source]`](https://doc.rust-lang.org/cargo/reference/config.html#source)
/// table defines the registry sources available.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Source {
    /// replace this source with the given named source
    #[serde(rename = "replace-with")]
    pub replace_with: Option<String>,

    /// URL to a registry source
    #[serde(default = "default_registry_url")]
    pub registry: String,
}

/// This is the default registry url per what's defined by Cargo.
fn default_registry_url() -> String {
    "https://github.com/rust-lang/crates.io-index".to_owned()
}

#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
/// registries other than crates.io
pub struct AdditionalRegistry {
    /// URL of the registry index
    pub index: String,

    /// authentication token for the registry
    pub token: Option<String>,
}

/// A subset of a Cargo configuration file. The schema here is only what
/// is required for parsing registry information.
/// See [cargo docs](https://doc.rust-lang.org/cargo/reference/config.html#configuration-format)
/// for more details.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct CargoConfig {
    /// registries other than crates.io
    #[serde(default = "default_registries")]
    pub registries: BTreeMap<String, AdditionalRegistry>,

    #[serde(default = "default_registry")]
    pub registry: Registry,

    /// source definition and replacement
    #[serde(default = "BTreeMap::new")]
    pub source: BTreeMap<String, Source>,
}

/// Each Cargo config is expected to have a default `crates-io` registry.
fn default_registries() -> BTreeMap<String, AdditionalRegistry> {
    let mut registries = BTreeMap::new();
    registries.insert(
        "crates-io".to_owned(),
        AdditionalRegistry {
            index: default_registry_url(),
            token: None,
        },
    );
    registries
}

/// Each Cargo config has a default registry for `crates.io`.
fn default_registry() -> Registry {
    Registry {
        default: "crates-io".to_owned(),
        token: None,
    }
}

impl Default for CargoConfig {
    fn default() -> Self {
        let registries = default_registries();
        let registry = default_registry();
        let source = Default::default();

        Self {
            registries,
            registry,
            source,
        }
    }
}

impl FromStr for CargoConfig {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let incoming: CargoConfig = toml::from_str(s)?;
        let mut config = Self::default();
        config.registries.extend(incoming.registries);
        config.source.extend(incoming.source);
        config.registry = incoming.registry;
        Ok(config)
    }
}

impl CargoConfig {
    /// Load a Cargo conig from a path to a file on disk.
    pub fn try_from_path(path: &Path) -> Result<Self> {
        let content = fs::read_to_string(path)?;
        Self::from_str(&content)
    }

    /// Look up a reigstry [Source] by it's url.
    pub fn get_source_from_url(&self, url: &str) -> Option<&Source> {
        self.source.values().find(|v| v.registry == url)
    }

    pub fn get_registry_index_url_by_name(&self, name: &str) -> Option<&str> {
        if let Some(registry) = self.registries.get(name) {
            Some(&registry.index)
        } else if let Some(source) = self.source.get(name) {
            Some(&source.registry)
        } else {
            None
        }
    }
}

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

    use std::fs;

    #[test]
    fn registry_settings() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                # Makes artifactory the default registry and saves passing --registry parameter
                [registry]
                default = "art-crates-remote"

                [registries]
                # Remote repository proxy in Artifactory (read-only)
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                # Optional, use with --registry to publish to crates.io
                crates-io = { index = "https://github.com/rust-lang/crates.io-index" }

                [net]
                git-fetch-with-cli = true
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config,
            CargoConfig {
                registries: BTreeMap::from([
                    (
                        "art-crates-remote".to_owned(),
                        AdditionalRegistry {
                            index: "https://artprod.mycompany/artifactory/git/cargo-remote.git"
                                .to_owned(),
                            token: None,
                        },
                    ),
                    (
                        "crates-io".to_owned(),
                        AdditionalRegistry {
                            index: "https://github.com/rust-lang/crates.io-index".to_owned(),
                            token: None,
                        },
                    ),
                ]),
                registry: Registry {
                    default: "art-crates-remote".to_owned(),
                    token: None,
                },
                source: BTreeMap::new(),
            },
        )
    }

    #[test]
    fn registry_settings_get_index_url_by_name_from_source() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                [registries]
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                [source.crates-io]
                replace-with = "some-mirror"

                [source.some-mirror]
                registry = "https://artmirror.mycompany/artifactory/cargo-mirror.git"
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config.get_registry_index_url_by_name("some-mirror"),
            Some("https://artmirror.mycompany/artifactory/cargo-mirror.git"),
        );
    }

    #[test]
    fn registry_settings_get_index_url_by_name_from_registry() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                [registries]
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                [source.crates-io]
                replace-with = "art-crates-remote"
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config.get_registry_index_url_by_name("art-crates-remote"),
            Some("https://artprod.mycompany/artifactory/git/cargo-remote.git"),
        );
    }
}
<commit_msg>[docs] Fixing typos in CargoConfig doc strings (#1638)<commit_after>//! Tools for parsing [Cargo configuration](https://doc.rust-lang.org/cargo/reference/config.html) files

use std::collections::BTreeMap;
use std::fs;
use std::path::Path;
use std::str::FromStr;

use anyhow::Result;
use serde::{Deserialize, Serialize};

/// The [`[registry]`](https://doc.rust-lang.org/cargo/reference/config.html#registry)
/// table controls the default registry used when one is not specified.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Registry {
    /// name of the default registry
    pub default: String,

    /// authentication token for crates.io
    pub token: Option<String>,
}

/// The [`[source]`](https://doc.rust-lang.org/cargo/reference/config.html#source)
/// table defines the registry sources available.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct Source {
    /// replace this source with the given named source
    #[serde(rename = "replace-with")]
    pub replace_with: Option<String>,

    /// URL to a registry source
    #[serde(default = "default_registry_url")]
    pub registry: String,
}

/// This is the default registry url per what's defined by Cargo.
fn default_registry_url() -> String {
    "https://github.com/rust-lang/crates.io-index".to_owned()
}

#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
/// registries other than crates.io
pub struct AdditionalRegistry {
    /// URL of the registry index
    pub index: String,

    /// authentication token for the registry
    pub token: Option<String>,
}

/// A subset of a Cargo configuration file. The schema here is only what
/// is required for parsing registry information.
/// See [cargo docs](https://doc.rust-lang.org/cargo/reference/config.html#configuration-format)
/// for more details.
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct CargoConfig {
    /// registries other than crates.io
    #[serde(default = "default_registries")]
    pub registries: BTreeMap<String, AdditionalRegistry>,

    #[serde(default = "default_registry")]
    pub registry: Registry,

    /// source definition and replacement
    #[serde(default = "BTreeMap::new")]
    pub source: BTreeMap<String, Source>,
}

/// Each Cargo config is expected to have a default `crates-io` registry.
fn default_registries() -> BTreeMap<String, AdditionalRegistry> {
    let mut registries = BTreeMap::new();
    registries.insert(
        "crates-io".to_owned(),
        AdditionalRegistry {
            index: default_registry_url(),
            token: None,
        },
    );
    registries
}

/// Each Cargo config has a default registry for `crates.io`.
fn default_registry() -> Registry {
    Registry {
        default: "crates-io".to_owned(),
        token: None,
    }
}

impl Default for CargoConfig {
    fn default() -> Self {
        let registries = default_registries();
        let registry = default_registry();
        let source = Default::default();

        Self {
            registries,
            registry,
            source,
        }
    }
}

impl FromStr for CargoConfig {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let incoming: CargoConfig = toml::from_str(s)?;
        let mut config = Self::default();
        config.registries.extend(incoming.registries);
        config.source.extend(incoming.source);
        config.registry = incoming.registry;
        Ok(config)
    }
}

impl CargoConfig {
    /// Load a Cargo config from a path to a file on disk.
    pub fn try_from_path(path: &Path) -> Result<Self> {
        let content = fs::read_to_string(path)?;
        Self::from_str(&content)
    }

    /// Look up a registry [Source] by its url.
    pub fn get_source_from_url(&self, url: &str) -> Option<&Source> {
        self.source.values().find(|v| v.registry == url)
    }

    pub fn get_registry_index_url_by_name(&self, name: &str) -> Option<&str> {
        if let Some(registry) = self.registries.get(name) {
            Some(&registry.index)
        } else if let Some(source) = self.source.get(name) {
            Some(&source.registry)
        } else {
            None
        }
    }
}

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

    use std::fs;

    #[test]
    fn registry_settings() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                # Makes artifactory the default registry and saves passing --registry parameter
                [registry]
                default = "art-crates-remote"

                [registries]
                # Remote repository proxy in Artifactory (read-only)
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                # Optional, use with --registry to publish to crates.io
                crates-io = { index = "https://github.com/rust-lang/crates.io-index" }

                [net]
                git-fetch-with-cli = true
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config,
            CargoConfig {
                registries: BTreeMap::from([
                    (
                        "art-crates-remote".to_owned(),
                        AdditionalRegistry {
                            index: "https://artprod.mycompany/artifactory/git/cargo-remote.git"
                                .to_owned(),
                            token: None,
                        },
                    ),
                    (
                        "crates-io".to_owned(),
                        AdditionalRegistry {
                            index: "https://github.com/rust-lang/crates.io-index".to_owned(),
                            token: None,
                        },
                    ),
                ]),
                registry: Registry {
                    default: "art-crates-remote".to_owned(),
                    token: None,
                },
                source: BTreeMap::new(),
            },
        )
    }

    #[test]
    fn registry_settings_get_index_url_by_name_from_source() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                [registries]
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                [source.crates-io]
                replace-with = "some-mirror"

                [source.some-mirror]
                registry = "https://artmirror.mycompany/artifactory/cargo-mirror.git"
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config.get_registry_index_url_by_name("some-mirror"),
            Some("https://artmirror.mycompany/artifactory/cargo-mirror.git"),
        );
    }

    #[test]
    fn registry_settings_get_index_url_by_name_from_registry() {
        let temp_dir = tempfile::tempdir().unwrap();
        let config = temp_dir.as_ref().join("config.toml");

        fs::write(&config, textwrap::dedent(
            r##"
                [registries]
                art-crates-remote = { index = "https://artprod.mycompany/artifactory/git/cargo-remote.git" }

                [source.crates-io]
                replace-with = "art-crates-remote"
            "##,
        )).unwrap();

        let config = CargoConfig::try_from_path(&config).unwrap();
        assert_eq!(
            config.get_registry_index_url_by_name("art-crates-remote"),
            Some("https://artprod.mycompany/artifactory/git/cargo-remote.git"),
        );
    }
}
<|endoftext|>