<commit_before>// TODO: get num cols of terminal dynamically
// TODO: care about the given print options

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing on the terminal. By `default()` everything is enabled.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

/// Pretty prints a report
///
/// **Note**: right now, the `PrintOptions` are ignored.
pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    trace!("Printing report: {:#?}", rep);
    trace!("Printing with filemap: {:#?}", src);

    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        trace!("Span is from {:?} to {:?}", start, end);

        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        trace!("Handling Remark {:?}", rem);

        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);
            trace!("Span is from {:?} to {:?}", start, end);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line_orig) = src.get_line(start.line) {
                    // replace tabs
                    let line = line_orig.replace("\t", "    ");
                    let num_tabs = line_orig[..start.col.0 as usize]
                        .chars()
                        .filter(|&c| c == '\t')
                        .count();

                    // print line (with marked span section)
                    let startcol = start.col.0 as usize + 3*num_tabs;
                    let endcol = end.col.0 as usize + 3*num_tabs;
                    println!("{:>#4} {} {}{}{}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        &line[..startcol],
                        Yellow.paint(&line[startcol..endcol]),
                        &line[endcol..],
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            startcol,
                            endcol - startcol,
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<commit_msg>Add more trace log output<commit_after>// TODO: get num cols of terminal dynamically
// TODO: care about the given print options

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing on the terminal. By `default()` everything is enabled.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

/// Pretty prints a report
///
/// **Note**: right now, the `PrintOptions` are ignored.
pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    trace!("Printing report: {:#?}", rep);
    trace!("Printing with filemap: {:#?}", src);

    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        trace!("Span is from {:?} to {:?}", start, end);

        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        trace!("Handling Remark {:?}", rem);

        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);
            trace!("Span is from {:?} to {:?}", start, end);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line_orig) = src.get_line(start.line) {
                    trace!("Printing single line span. Line: {:?}", line_orig);
                    // replace tabs
                    let line = line_orig.replace("\t", "    ");
                    let num_tabs = line_orig[..start.col.0 as usize]
                        .chars()
                        .filter(|&c| c == '\t')
                        .count();

                    // print line (with marked span section)
                    let startcol = start.col.0 as usize + 3*num_tabs;
                    let endcol = end.col.0 as usize + 3*num_tabs;
                    println!("{:>#4} {} {}{}{}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        &line[..startcol],
                        Yellow.paint(&line[startcol..endcol]),
                        &line[endcol..],
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            startcol,
                            endcol - startcol,
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<|endoftext|>


<commit_before>use std::sync::mpsc::{Receiver, Sender};
use std::rc::Rc;

use action::ExecResult;
use super::{config, Condition, Context, Message, TimerEvent};
use reactor::{self, Event, EventDemultiplexer, EventHandler, Reactor};

#[derive(Debug)]
pub enum Request {
    Event(super::Event),
    Exit
}

#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum RequestHandler {
    Event,
    Exit
}

impl reactor::Event for Request {
    type Handler = RequestHandler;
    fn handler(&self) -> Self::Handler {
        match *self {
            Request::Event(_) => RequestHandler::Event,
            Request::Exit => RequestHandler::Exit,
        }
    }
}

#[derive(Debug)]
pub enum Response {
    Event(ExecResult),
    Exit
}

pub struct Dispatcher {
    contexts: Vec<Context>,
    output_channel: Sender<Response>,
    exits_received: u32
}

impl Dispatcher {
    pub fn new(contexts: Vec<config::Context>, action_output_channel: Sender<Response>) -> Dispatcher {
        let contexts = contexts.into_iter().map(|ctx| Context::from(ctx)).collect::<Vec<Context>>();
        Dispatcher {
            contexts: contexts,
            output_channel: action_output_channel,
            exits_received: 0
        }
    }

    pub fn start_loop(&mut self, channel: Receiver<Request>) {
        for i in channel.iter() {
            match i {
                Request::Event(event) => self.dispatch(event),
                Request::Exit => {
                    if self.on_exit() {
                        break;
                    }
                }
            }
        }
    }

    fn on_exit(&mut self) -> bool {
        self.exits_received += 1;
        let _ = self.output_channel.send(Response::Exit);
        self.exits_received >= 2
    }

    pub fn dispatch(&mut self, event: super::Event) {
        match event {
            super::Event::Message(event) => {
                let event = Rc::new(event);
                self.on_message(event);
            },
            super::Event::Timer(ref event) => {
                self.on_timer(event);
            }
        };
    }

    fn on_message(&mut self, event: Rc<Message>) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_message(event.clone()) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }

    fn on_timer(&mut self, event: &TimerEvent) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_timer(event) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }
}

use std::collections::BTreeMap;

pub struct RequestReactor {
    handlers: BTreeMap<RequestHandler, Box<reactor::EventHandler<Request, Handler=RequestHandler>>>,
    demultiplexer: Demultiplexer<Request>,
    exit_condition: Condition
}

impl RequestReactor {
    fn new(demultiplexer: Demultiplexer<Request>) -> RequestReactor {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(handlers::exit::ExitHandler::new(exit_condition.clone()));
        let event_handler = Box::new(handlers::event::EventHandler::new());

        let mut reactor = RequestReactor {
            demultiplexer: demultiplexer,
            exit_condition: exit_condition,
            handlers: BTreeMap::new()
        };

        reactor.register_handler(exit_handler);
        reactor.register_handler(event_handler);
        reactor
    }
}

impl Reactor for RequestReactor {
    type Event = Request;
    type Handler = RequestHandler;
    fn handle_events(&mut self) {
        while !self.exit_condition.is_active() {
            if let Some(request) = self.demultiplexer.select() {
                let mut handler = self.handlers.get_mut(&request.handler()).unwrap();
                handler.handle_event(request);
            } else {
                break;
            }
        }
    }
    fn register_handler(&mut self, handler: Box<reactor::EventHandler<Self::Event, Handler=RequestHandler>>) {
        self.handlers.insert(handler.handler(), handler);
    }
    fn remove_handler(&mut self, handler: &reactor::EventHandler<Self::Event, Handler=RequestHandler>){}
}

struct Demultiplexer<T>(Receiver<T>);

impl reactor::EventDemultiplexer for Demultiplexer<Request> {
    type Event = Request;
    fn select(&mut self) -> Option<Self::Event> {
        self.0.recv().ok()
    }
}

mod handlers {
    pub mod exit {
        use dispatcher::{Request, RequestHandler};
        use condition::Condition;
        use reactor::EventHandler;

        pub struct ExitHandler{
            condition: Condition,
            stops: u32
        }

        impl ExitHandler {
            pub fn new(condition: Condition) -> ExitHandler {
                ExitHandler {
                    condition: condition,
                    stops: 0
                }
            }
        }

        impl EventHandler<Request> for ExitHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Exit = event {
                    self.stops += 1;

                    if self.stops >= 2 {
                        self.condition.activate();
                    }
                } else {
                    unreachable!("An ExitHandler should only receive Exit events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Exit
            }
        }
    }

    pub mod event {
        use dispatcher::{Request, RequestHandler};
        use reactor;

        pub struct EventHandler;

        impl EventHandler {
            pub fn new() -> EventHandler {
                EventHandler
            }
        }

        impl reactor::EventHandler<Request> for EventHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Event(_) = event {
                    println!("Event recvd");
                } else {
                    unreachable!("An EventHandler should only receive Event events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Event
            }
        }
    }

    mod linear {
        use dispatcher::{Request, RequestHandler};
        use EventHandler;
        use Event;
        use reactor;

        pub struct LinearHandler<C, H> {
            contexts: Vec<C>,
            handler: H
        }

        impl<C, H> LinearHandler<C, H> {
            pub fn new(handler: H) -> LinearHandler<C, H> {
                LinearHandler {
                    contexts: Vec::new(),
                    handler: handler
                }
            }
        }

        /*impl<C, H, E> reactor::EventHandler<E> for LinearHandler<C, H> {
            type Handler = H;
            fn handle_event(&mut self, event: E) {

            }
            fn handler(&self) -> Self::Handler {
                self.handler
            }
        }*/
    }
}
<commit_msg>dispatcher: finish  LinearHandler<commit_after>use std::sync::mpsc::{Receiver, Sender};
use std::rc::Rc;

use action::ExecResult;
use super::{config, Condition, Context, Message, TimerEvent};
use reactor::{self, Event, EventDemultiplexer, EventHandler, Reactor};

#[derive(Debug)]
pub enum Request {
    Event(super::Event),
    Exit
}

#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum RequestHandler {
    Event,
    Exit
}

impl reactor::Event for Request {
    type Handler = RequestHandler;
    fn handler(&self) -> Self::Handler {
        match *self {
            Request::Event(_) => RequestHandler::Event,
            Request::Exit => RequestHandler::Exit,
        }
    }
}

#[derive(Debug)]
pub enum Response {
    Event(ExecResult),
    Exit
}

pub struct Dispatcher {
    contexts: Vec<Context>,
    output_channel: Sender<Response>,
    exits_received: u32
}

impl Dispatcher {
    pub fn new(contexts: Vec<config::Context>, action_output_channel: Sender<Response>) -> Dispatcher {
        let contexts = contexts.into_iter().map(|ctx| Context::from(ctx)).collect::<Vec<Context>>();
        Dispatcher {
            contexts: contexts,
            output_channel: action_output_channel,
            exits_received: 0
        }
    }

    pub fn start_loop(&mut self, channel: Receiver<Request>) {
        for i in channel.iter() {
            match i {
                Request::Event(event) => self.dispatch(event),
                Request::Exit => {
                    if self.on_exit() {
                        break;
                    }
                }
            }
        }
    }

    fn on_exit(&mut self) -> bool {
        self.exits_received += 1;
        let _ = self.output_channel.send(Response::Exit);
        self.exits_received >= 2
    }

    pub fn dispatch(&mut self, event: super::Event) {
        match event {
            super::Event::Message(event) => {
                let event = Rc::new(event);
                self.on_message(event);
            },
            super::Event::Timer(ref event) => {
                self.on_timer(event);
            }
        };
    }

    fn on_message(&mut self, event: Rc<Message>) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_message(event.clone()) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }

    fn on_timer(&mut self, event: &TimerEvent) {
        for context in self.contexts.iter_mut() {
            if let Some(result) = context.on_timer(event) {
                for i in result.into_iter() {
                    let _ = self.output_channel.send(i.into());
                }
            }
        }
    }
}

use std::collections::BTreeMap;

pub struct RequestReactor {
    handlers: BTreeMap<RequestHandler, Box<reactor::EventHandler<Request, Handler=RequestHandler>>>,
    demultiplexer: Demultiplexer<Request>,
    exit_condition: Condition
}

impl RequestReactor {
    fn new(demultiplexer: Demultiplexer<Request>) -> RequestReactor {
        let exit_condition = Condition::new(false);
        let exit_handler = Box::new(handlers::exit::ExitHandler::new(exit_condition.clone()));
        let event_handler = Box::new(handlers::event::EventHandler::new());

        let mut reactor = RequestReactor {
            demultiplexer: demultiplexer,
            exit_condition: exit_condition,
            handlers: BTreeMap::new()
        };

        reactor.register_handler(exit_handler);
        reactor.register_handler(event_handler);
        reactor
    }
}

impl Reactor for RequestReactor {
    type Event = Request;
    type Handler = RequestHandler;
    fn handle_events(&mut self) {
        while !self.exit_condition.is_active() {
            if let Some(request) = self.demultiplexer.select() {
                let mut handler = self.handlers.get_mut(&request.handler()).unwrap();
                handler.handle_event(request);
            } else {
                break;
            }
        }
    }
    fn register_handler(&mut self, handler: Box<reactor::EventHandler<Self::Event, Handler=RequestHandler>>) {
        self.handlers.insert(handler.handler(), handler);
    }
    fn remove_handler(&mut self, handler: &reactor::EventHandler<Self::Event, Handler=RequestHandler>){}
}

struct Demultiplexer<T>(Receiver<T>);

impl reactor::EventDemultiplexer for Demultiplexer<Request> {
    type Event = Request;
    fn select(&mut self) -> Option<Self::Event> {
        self.0.recv().ok()
    }
}

mod handlers {
    pub mod exit {
        use dispatcher::{Request, RequestHandler};
        use condition::Condition;
        use reactor::EventHandler;

        pub struct ExitHandler{
            condition: Condition,
            stops: u32
        }

        impl ExitHandler {
            pub fn new(condition: Condition) -> ExitHandler {
                ExitHandler {
                    condition: condition,
                    stops: 0
                }
            }
        }

        impl EventHandler<Request> for ExitHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Exit = event {
                    self.stops += 1;

                    if self.stops >= 2 {
                        self.condition.activate();
                    }
                } else {
                    unreachable!("An ExitHandler should only receive Exit events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Exit
            }
        }
    }

    pub mod event {
        use dispatcher::{Request, RequestHandler};
        use reactor;

        pub struct EventHandler;

        impl EventHandler {
            pub fn new() -> EventHandler {
                EventHandler
            }
        }

        impl reactor::EventHandler<Request> for EventHandler {
            type Handler = RequestHandler;
            fn handle_event(&mut self, event: Request) {
                if let Request::Event(_) = event {
                    println!("Event recvd");
                } else {
                    unreachable!("An EventHandler should only receive Event events");
                }
            }
            fn handler(&self) -> Self::Handler {
                RequestHandler::Event
            }
        }
    }

    mod linear {
        use context::Context;
        use dispatcher::{Request, RequestHandler};
        use EventHandler;
        use Event;
        use reactor;

        pub struct LinearHandler {
            contexts: Vec<Context>
        }

        impl LinearHandler {
            pub fn new() -> LinearHandler {
                LinearHandler {
                    contexts: Vec::new()
                }
            }
        }

        impl reactor::EventHandler<Event> for LinearHandler {
            type Handler = EventHandler;
            fn handle_event(&mut self, event: Event) {
                println!("timer event");
            }
            fn handler(&self) -> Self::Handler {
                EventHandler::Timer
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Platform-specific types, as defined by C.
//!
//! Code that interacts via FFI will almost certainly be using the
//! base types provided by C, which aren't nearly as nicely defined
//! as Rust's primitive types. This module provides types which will
//! match those defined by C, so that code that interacts with C will
//! refer to the correct types.

#![stable(feature = "raw_os", since = "1.1.0")]

#[cfg(test)]
mod tests;

use core::num::*;

macro_rules! type_alias_no_nz {
    {
      $Docfile:tt, $Alias:ident = $Real:ty;
      $( $Cfg:tt )*
    } => {
        #[doc = include_str!($Docfile)]
        $( $Cfg )*
        #[stable(feature = "raw_os", since = "1.1.0")]
        pub type $Alias = $Real;
    }
}

// To verify that the NonZero types in this file's macro invocations correspond
//
//  perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
//
// NB this does not check that the main c_* types are right.

macro_rules! type_alias {
    {
      $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
      $( $Cfg:tt )*
    } => {
        type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }

        #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
        #[unstable(feature = "raw_os_nonzero", issue = "82363")]
        $( $Cfg )*
        pub type $NZAlias = $NZReal;
    }
}

type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
#[cfg(any(
    all(
        target_os = "linux",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "hexagon",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "s390x",
            target_arch = "riscv64",
            target_arch = "riscv32"
        )
    ),
    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
    all(target_os = "l4re", target_arch = "x86_64"),
    all(
        target_os = "freebsd",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc",
            target_arch = "powerpc64"
        )
    ),
    all(
        target_os = "netbsd",
        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
    ),
    all(target_os = "openbsd", target_arch = "aarch64"),
    all(
        target_os = "vxworks",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc64",
            target_arch = "powerpc"
        )
    ),
    all(target_os = "fuchsia", target_arch = "aarch64")
))]}
type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
#[cfg(not(any(
    all(
        target_os = "linux",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "hexagon",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "s390x",
            target_arch = "riscv64",
            target_arch = "riscv32"
        )
    ),
    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
    all(target_os = "l4re", target_arch = "x86_64"),
    all(
        target_os = "freebsd",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc",
            target_arch = "powerpc64"
        )
    ),
    all(
        target_os = "netbsd",
        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
    ),
    all(target_os = "openbsd", target_arch = "aarch64"),
    all(
        target_os = "vxworks",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc64",
            target_arch = "powerpc"
        )
    ),
    all(target_os = "fuchsia", target_arch = "aarch64")
)))]}
type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32;
#[cfg(any(target_pointer_width = "32", windows))] }
type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
#[cfg(any(target_pointer_width = "32", windows))] }
type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64;
#[cfg(all(target_pointer_width = "64", not(windows)))] }
type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
#[cfg(all(target_pointer_width = "64", not(windows)))] }
type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
type_alias_no_nz! { "float.md", c_float = f32; }
type_alias_no_nz! { "double.md", c_double = f64; }

#[stable(feature = "raw_os", since = "1.1.0")]
#[doc(no_inline)]
pub use core::ffi::c_void;
<commit_msg>Rollup merge of #88340 - thomcc:c_size_t, r=joshtriplett<commit_after>//! Platform-specific types, as defined by C.
//!
//! Code that interacts via FFI will almost certainly be using the
//! base types provided by C, which aren't nearly as nicely defined
//! as Rust's primitive types. This module provides types which will
//! match those defined by C, so that code that interacts with C will
//! refer to the correct types.

#![stable(feature = "raw_os", since = "1.1.0")]

#[cfg(test)]
mod tests;

use core::num::*;

macro_rules! type_alias_no_nz {
    {
      $Docfile:tt, $Alias:ident = $Real:ty;
      $( $Cfg:tt )*
    } => {
        #[doc = include_str!($Docfile)]
        $( $Cfg )*
        #[stable(feature = "raw_os", since = "1.1.0")]
        pub type $Alias = $Real;
    }
}

// To verify that the NonZero types in this file's macro invocations correspond
//
//  perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
//
// NB this does not check that the main c_* types are right.

macro_rules! type_alias {
    {
      $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
      $( $Cfg:tt )*
    } => {
        type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }

        #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
        #[unstable(feature = "raw_os_nonzero", issue = "82363")]
        $( $Cfg )*
        pub type $NZAlias = $NZReal;
    }
}

type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
#[cfg(any(
    all(
        target_os = "linux",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "hexagon",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "s390x",
            target_arch = "riscv64",
            target_arch = "riscv32"
        )
    ),
    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
    all(target_os = "l4re", target_arch = "x86_64"),
    all(
        target_os = "freebsd",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc",
            target_arch = "powerpc64"
        )
    ),
    all(
        target_os = "netbsd",
        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
    ),
    all(target_os = "openbsd", target_arch = "aarch64"),
    all(
        target_os = "vxworks",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc64",
            target_arch = "powerpc"
        )
    ),
    all(target_os = "fuchsia", target_arch = "aarch64")
))]}
type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
#[cfg(not(any(
    all(
        target_os = "linux",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "hexagon",
            target_arch = "powerpc",
            target_arch = "powerpc64",
            target_arch = "s390x",
            target_arch = "riscv64",
            target_arch = "riscv32"
        )
    ),
    all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")),
    all(target_os = "l4re", target_arch = "x86_64"),
    all(
        target_os = "freebsd",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc",
            target_arch = "powerpc64"
        )
    ),
    all(
        target_os = "netbsd",
        any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc")
    ),
    all(target_os = "openbsd", target_arch = "aarch64"),
    all(
        target_os = "vxworks",
        any(
            target_arch = "aarch64",
            target_arch = "arm",
            target_arch = "powerpc64",
            target_arch = "powerpc"
        )
    ),
    all(target_os = "fuchsia", target_arch = "aarch64")
)))]}
type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32;
#[cfg(any(target_pointer_width = "32", windows))] }
type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
#[cfg(any(target_pointer_width = "32", windows))] }
type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64;
#[cfg(all(target_pointer_width = "64", not(windows)))] }
type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
#[cfg(all(target_pointer_width = "64", not(windows)))] }
type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
type_alias_no_nz! { "float.md", c_float = f32; }
type_alias_no_nz! { "double.md", c_double = f64; }

#[stable(feature = "raw_os", since = "1.1.0")]
#[doc(no_inline)]
pub use core::ffi::c_void;

/// Equivalent to C's `size_t` type, from `stddef.h` (or `cstddef` for C++).
///
/// This type is currently always [`usize`], however in the future there may be
/// platforms where this is not the case.
#[unstable(feature = "c_size_t", issue = "88345")]
pub type c_size_t = usize;

/// Equivalent to C's `ssize_t` type, from `stddef.h` (or `cstddef` for C++).
///
/// This type is currently always [`isize`], however in the future there may be
/// platforms where this is not the case.
#[unstable(feature = "c_size_t", issue = "88345")]
pub type c_ssize_t = isize;
<|endoftext|>


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

//! Format attributes and meta items.

use config::lists::*;
use syntax::ast;
use syntax::codemap::Span;

use comment::{combine_strs_with_missing_comments, contains_comment, rewrite_doc_comment};
use expr::rewrite_literal;
use lists::{itemize_list, write_list, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{count_newlines, mk_sp};

use std::cmp;

/// Returns attributes on the given statement.
pub fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
    match stmt.node {
        ast::StmtKind::Local(ref local) => &local.attrs,
        ast::StmtKind::Item(ref item) => &item.attrs,
        ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => &expr.attrs,
        ast::StmtKind::Mac(ref mac) => &mac.2,
    }
}

/// Returns attributes that are within `outer_span`.
pub fn filter_inline_attrs(attrs: &[ast::Attribute], outer_span: Span) -> Vec<ast::Attribute> {
    attrs
        .iter()
        .filter(|a| outer_span.lo() <= a.span.lo() && a.span.hi() <= outer_span.hi())
        .cloned()
        .collect()
}

fn is_derive(attr: &ast::Attribute) -> bool {
    attr.check_name("derive")
}

/// Returns the arguments of `#[derive(...)]`.
fn get_derive_args<'a>(context: &'a RewriteContext, attr: &ast::Attribute) -> Option<Vec<&'a str>> {
    attr.meta_item_list().map(|meta_item_list| {
        meta_item_list
            .iter()
            .map(|nested_meta_item| context.snippet(nested_meta_item.span))
            .collect()
    })
}

// Format `#[derive(..)]`, using visual indent & mixed style when we need to go multiline.
fn format_derive(context: &RewriteContext, derive_args: &[&str], shape: Shape) -> Option<String> {
    let mut result = String::with_capacity(128);
    result.push_str("#[derive(");
    // 11 = `#[derive()]`
    let initial_budget = shape.width.checked_sub(11)?;
    let mut budget = initial_budget;
    let num = derive_args.len();
    for (i, a) in derive_args.iter().enumerate() {
        // 2 = `, ` or `)]`
        let width = a.len() + 2;
        if width > budget {
            if i > 0 {
                // Remove trailing whitespace.
                result.pop();
            }
            result.push('\n');
            // 9 = `#[derive(`
            result.push_str(&(shape.indent + 9).to_string(context.config));
            budget = initial_budget;
        } else {
            budget = budget.checked_sub(width).unwrap_or(0);
        }
        result.push_str(a);
        if i != num - 1 {
            result.push_str(", ")
        }
    }
    result.push_str(")]");
    Some(result)
}

/// Returns the first group of attributes that fills the given predicate.
/// We consider two doc comments are in different group if they are separated by normal comments.
fn take_while_with_pred<'a, P>(
    context: &RewriteContext,
    attrs: &'a [ast::Attribute],
    pred: P,
) -> &'a [ast::Attribute]
where
    P: Fn(&ast::Attribute) -> bool,
{
    let mut last_index = 0;
    let mut iter = attrs.iter().enumerate().peekable();
    while let Some((i, attr)) = iter.next() {
        if !pred(attr) {
            break;
        }
        if let Some(&(_, next_attr)) = iter.peek() {
            // Extract comments between two attributes.
            let span_between_attr = mk_sp(attr.span.hi(), next_attr.span.lo());
            let snippet = context.snippet(span_between_attr);
            if count_newlines(snippet) >= 2 || snippet.contains('/') {
                break;
            }
        }
        last_index = i;
    }
    if last_index == 0 {
        &[]
    } else {
        &attrs[..last_index + 1]
    }
}

fn rewrite_first_group_attrs(
    context: &RewriteContext,
    attrs: &[ast::Attribute],
    shape: Shape,
) -> Option<(usize, String)> {
    if attrs.is_empty() {
        return Some((0, String::new()));
    }
    // Rewrite doc comments
    let sugared_docs = take_while_with_pred(context, attrs, |a| a.is_sugared_doc);
    if !sugared_docs.is_empty() {
        let snippet = sugared_docs
            .iter()
            .map(|a| context.snippet(a.span))
            .collect::<Vec<_>>()
            .join("\n");
        return Some((
            sugared_docs.len(),
            rewrite_doc_comment(&snippet, shape, context.config)?,
        ));
    }
    // Rewrite `#[derive(..)]`s.
    if context.config.merge_derives() {
        let derives = take_while_with_pred(context, attrs, is_derive);
        if !derives.is_empty() {
            let mut derive_args = vec![];
            for derive in derives {
                derive_args.append(&mut get_derive_args(context, derive)?);
            }
            return Some((derives.len(), format_derive(context, &derive_args, shape)?));
        }
    }
    // Rewrite the first attribute.
    Some((1, attrs[0].rewrite(context, shape)?))
}

impl Rewrite for ast::NestedMetaItem {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match self.node {
            ast::NestedMetaItemKind::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
            ast::NestedMetaItemKind::Literal(ref l) => rewrite_literal(context, l, shape),
        }
    }
}

fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
    // Look at before and after comment and see if there are any empty lines.
    let comment_begin = comment.chars().position(|c| c == '/');
    let len = comment_begin.unwrap_or_else(|| comment.len());
    let mlb = count_newlines(&comment[..len]) > 1;
    let mla = if comment_begin.is_none() {
        mlb
    } else {
        let comment_end = comment.chars().rev().position(|c| !c.is_whitespace());
        let len = comment_end.unwrap();
        comment
            .chars()
            .rev()
            .take(len)
            .filter(|c| *c == '\n')
            .count() > 1
    };
    (if mlb { "\n" } else { "" }, if mla { "\n" } else { "" })
}

impl Rewrite for ast::MetaItem {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        Some(match self.node {
            ast::MetaItemKind::Word => String::from(&*self.name.as_str()),
            ast::MetaItemKind::List(ref list) => {
                let name = self.name.as_str();
                // 1 = `(`, 2 = `]` and `)`
                let item_shape = shape
                    .visual_indent(0)
                    .shrink_left(name.len() + 1)
                    .and_then(|s| s.sub_width(2))?;
                let items = itemize_list(
                    context.snippet_provider,
                    list.iter(),
                    ")",
                    ",",
                    |nested_meta_item| nested_meta_item.span.lo(),
                    |nested_meta_item| nested_meta_item.span.hi(),
                    |nested_meta_item| nested_meta_item.rewrite(context, item_shape),
                    self.span.lo(),
                    self.span.hi(),
                    false,
                );
                let item_vec = items.collect::<Vec<_>>();
                let fmt = ListFormatting {
                    tactic: DefinitiveListTactic::Mixed,
                    separator: ",",
                    trailing_separator: SeparatorTactic::Never,
                    separator_place: SeparatorPlace::Back,
                    shape: item_shape,
                    ends_with_newline: false,
                    preserve_newline: false,
                    config: context.config,
                };
                format!("{}({})", name, write_list(&item_vec, &fmt)?)
            }
            ast::MetaItemKind::NameValue(ref literal) => {
                let name = self.name.as_str();
                // 3 = ` = `
                let lit_shape = shape.shrink_left(name.len() + 3)?;
                let value = rewrite_literal(context, literal, lit_shape)?;
                format!("{} = {}", name, value)
            }
        })
    }
}

impl Rewrite for ast::Attribute {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        let prefix = match self.style {
            ast::AttrStyle::Inner => "#!",
            ast::AttrStyle::Outer => "#",
        };
        let snippet = context.snippet(self.span);
        if self.is_sugared_doc {
            let doc_shape = Shape {
                width: cmp::min(shape.width, context.config.comment_width())
                    .checked_sub(shape.indent.width())
                    .unwrap_or(0),
                ..shape
            };
            rewrite_doc_comment(snippet, doc_shape, context.config)
        } else {
            if contains_comment(snippet) {
                return Some(snippet.to_owned());
            }
            // 1 = `[`
            let shape = shape.offset_left(prefix.len() + 1)?;
            Some(
                self.meta()
                    .and_then(|meta| meta.rewrite(context, shape))
                    .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
            )
        }
    }
}

impl<'a> Rewrite for [ast::Attribute] {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        if self.is_empty() {
            return Some(String::new());
        }
        let (first_group_len, first_group_str) = rewrite_first_group_attrs(context, self, shape)?;
        if self.len() == 1 || first_group_len == self.len() {
            Some(first_group_str)
        } else {
            let rest_str = self[first_group_len..].rewrite(context, shape)?;
            let missing_span = mk_sp(
                self[first_group_len - 1].span.hi(),
                self[first_group_len].span.lo(),
            );
            // Preserve an empty line before/after doc comments.
            if self[0].is_sugared_doc || self[first_group_len].is_sugared_doc {
                let snippet = context.snippet(missing_span);
                let (mla, mlb) = has_newlines_before_after_comment(snippet);
                let comment = ::comment::recover_missing_comment_in_span(
                    missing_span,
                    shape.with_max_width(context.config),
                    context,
                    0,
                )?;
                let comment = if comment.is_empty() {
                    format!("\n{}", mlb)
                } else {
                    format!("{}{}\n{}", mla, comment, mlb)
                };
                Some(format!(
                    "{}{}{}{}",
                    first_group_str,
                    comment,
                    shape.indent.to_string(context.config),
                    rest_str
                ))
            } else {
                combine_strs_with_missing_comments(
                    context,
                    &first_group_str,
                    &rest_str,
                    missing_span,
                    shape,
                    false,
                )
            }
        }
    }
}
<commit_msg>Add doc comment to rewrite_first_group_attrs<commit_after>// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Format attributes and meta items.

use config::lists::*;
use syntax::ast;
use syntax::codemap::Span;

use comment::{combine_strs_with_missing_comments, contains_comment, rewrite_doc_comment};
use expr::rewrite_literal;
use lists::{itemize_list, write_list, ListFormatting};
use rewrite::{Rewrite, RewriteContext};
use shape::Shape;
use utils::{count_newlines, mk_sp};

use std::cmp;

/// Returns attributes on the given statement.
pub fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
    match stmt.node {
        ast::StmtKind::Local(ref local) => &local.attrs,
        ast::StmtKind::Item(ref item) => &item.attrs,
        ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => &expr.attrs,
        ast::StmtKind::Mac(ref mac) => &mac.2,
    }
}

/// Returns attributes that are within `outer_span`.
pub fn filter_inline_attrs(attrs: &[ast::Attribute], outer_span: Span) -> Vec<ast::Attribute> {
    attrs
        .iter()
        .filter(|a| outer_span.lo() <= a.span.lo() && a.span.hi() <= outer_span.hi())
        .cloned()
        .collect()
}

fn is_derive(attr: &ast::Attribute) -> bool {
    attr.check_name("derive")
}

/// Returns the arguments of `#[derive(...)]`.
fn get_derive_args<'a>(context: &'a RewriteContext, attr: &ast::Attribute) -> Option<Vec<&'a str>> {
    attr.meta_item_list().map(|meta_item_list| {
        meta_item_list
            .iter()
            .map(|nested_meta_item| context.snippet(nested_meta_item.span))
            .collect()
    })
}

// Format `#[derive(..)]`, using visual indent & mixed style when we need to go multiline.
fn format_derive(context: &RewriteContext, derive_args: &[&str], shape: Shape) -> Option<String> {
    let mut result = String::with_capacity(128);
    result.push_str("#[derive(");
    // 11 = `#[derive()]`
    let initial_budget = shape.width.checked_sub(11)?;
    let mut budget = initial_budget;
    let num = derive_args.len();
    for (i, a) in derive_args.iter().enumerate() {
        // 2 = `, ` or `)]`
        let width = a.len() + 2;
        if width > budget {
            if i > 0 {
                // Remove trailing whitespace.
                result.pop();
            }
            result.push('\n');
            // 9 = `#[derive(`
            result.push_str(&(shape.indent + 9).to_string(context.config));
            budget = initial_budget;
        } else {
            budget = budget.checked_sub(width).unwrap_or(0);
        }
        result.push_str(a);
        if i != num - 1 {
            result.push_str(", ")
        }
    }
    result.push_str(")]");
    Some(result)
}

/// Returns the first group of attributes that fills the given predicate.
/// We consider two doc comments are in different group if they are separated by normal comments.
fn take_while_with_pred<'a, P>(
    context: &RewriteContext,
    attrs: &'a [ast::Attribute],
    pred: P,
) -> &'a [ast::Attribute]
where
    P: Fn(&ast::Attribute) -> bool,
{
    let mut last_index = 0;
    let mut iter = attrs.iter().enumerate().peekable();
    while let Some((i, attr)) = iter.next() {
        if !pred(attr) {
            break;
        }
        if let Some(&(_, next_attr)) = iter.peek() {
            // Extract comments between two attributes.
            let span_between_attr = mk_sp(attr.span.hi(), next_attr.span.lo());
            let snippet = context.snippet(span_between_attr);
            if count_newlines(snippet) >= 2 || snippet.contains('/') {
                break;
            }
        }
        last_index = i;
    }
    if last_index == 0 {
        &[]
    } else {
        &attrs[..last_index + 1]
    }
}

/// Rewrite the same kind of attributes at the same time. This includes doc
/// comments and derives.
fn rewrite_first_group_attrs(
    context: &RewriteContext,
    attrs: &[ast::Attribute],
    shape: Shape,
) -> Option<(usize, String)> {
    if attrs.is_empty() {
        return Some((0, String::new()));
    }
    // Rewrite doc comments
    let sugared_docs = take_while_with_pred(context, attrs, |a| a.is_sugared_doc);
    if !sugared_docs.is_empty() {
        let snippet = sugared_docs
            .iter()
            .map(|a| context.snippet(a.span))
            .collect::<Vec<_>>()
            .join("\n");
        return Some((
            sugared_docs.len(),
            rewrite_doc_comment(&snippet, shape, context.config)?,
        ));
    }
    // Rewrite `#[derive(..)]`s.
    if context.config.merge_derives() {
        let derives = take_while_with_pred(context, attrs, is_derive);
        if !derives.is_empty() {
            let mut derive_args = vec![];
            for derive in derives {
                derive_args.append(&mut get_derive_args(context, derive)?);
            }
            return Some((derives.len(), format_derive(context, &derive_args, shape)?));
        }
    }
    // Rewrite the first attribute.
    Some((1, attrs[0].rewrite(context, shape)?))
}

impl Rewrite for ast::NestedMetaItem {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        match self.node {
            ast::NestedMetaItemKind::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
            ast::NestedMetaItemKind::Literal(ref l) => rewrite_literal(context, l, shape),
        }
    }
}

fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
    // Look at before and after comment and see if there are any empty lines.
    let comment_begin = comment.chars().position(|c| c == '/');
    let len = comment_begin.unwrap_or_else(|| comment.len());
    let mlb = count_newlines(&comment[..len]) > 1;
    let mla = if comment_begin.is_none() {
        mlb
    } else {
        let comment_end = comment.chars().rev().position(|c| !c.is_whitespace());
        let len = comment_end.unwrap();
        comment
            .chars()
            .rev()
            .take(len)
            .filter(|c| *c == '\n')
            .count() > 1
    };
    (if mlb { "\n" } else { "" }, if mla { "\n" } else { "" })
}

impl Rewrite for ast::MetaItem {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        Some(match self.node {
            ast::MetaItemKind::Word => String::from(&*self.name.as_str()),
            ast::MetaItemKind::List(ref list) => {
                let name = self.name.as_str();
                // 1 = `(`, 2 = `]` and `)`
                let item_shape = shape
                    .visual_indent(0)
                    .shrink_left(name.len() + 1)
                    .and_then(|s| s.sub_width(2))?;
                let items = itemize_list(
                    context.snippet_provider,
                    list.iter(),
                    ")",
                    ",",
                    |nested_meta_item| nested_meta_item.span.lo(),
                    |nested_meta_item| nested_meta_item.span.hi(),
                    |nested_meta_item| nested_meta_item.rewrite(context, item_shape),
                    self.span.lo(),
                    self.span.hi(),
                    false,
                );
                let item_vec = items.collect::<Vec<_>>();
                let fmt = ListFormatting {
                    tactic: DefinitiveListTactic::Mixed,
                    separator: ",",
                    trailing_separator: SeparatorTactic::Never,
                    separator_place: SeparatorPlace::Back,
                    shape: item_shape,
                    ends_with_newline: false,
                    preserve_newline: false,
                    config: context.config,
                };
                format!("{}({})", name, write_list(&item_vec, &fmt)?)
            }
            ast::MetaItemKind::NameValue(ref literal) => {
                let name = self.name.as_str();
                // 3 = ` = `
                let lit_shape = shape.shrink_left(name.len() + 3)?;
                let value = rewrite_literal(context, literal, lit_shape)?;
                format!("{} = {}", name, value)
            }
        })
    }
}

impl Rewrite for ast::Attribute {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        let prefix = match self.style {
            ast::AttrStyle::Inner => "#!",
            ast::AttrStyle::Outer => "#",
        };
        let snippet = context.snippet(self.span);
        if self.is_sugared_doc {
            let doc_shape = Shape {
                width: cmp::min(shape.width, context.config.comment_width())
                    .checked_sub(shape.indent.width())
                    .unwrap_or(0),
                ..shape
            };
            rewrite_doc_comment(snippet, doc_shape, context.config)
        } else {
            if contains_comment(snippet) {
                return Some(snippet.to_owned());
            }
            // 1 = `[`
            let shape = shape.offset_left(prefix.len() + 1)?;
            Some(
                self.meta()
                    .and_then(|meta| meta.rewrite(context, shape))
                    .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
            )
        }
    }
}

impl<'a> Rewrite for [ast::Attribute] {
    fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
        if self.is_empty() {
            return Some(String::new());
        }
        let (first_group_len, first_group_str) = rewrite_first_group_attrs(context, self, shape)?;
        if self.len() == 1 || first_group_len == self.len() {
            Some(first_group_str)
        } else {
            let rest_str = self[first_group_len..].rewrite(context, shape)?;
            let missing_span = mk_sp(
                self[first_group_len - 1].span.hi(),
                self[first_group_len].span.lo(),
            );
            // Preserve an empty line before/after doc comments.
            if self[0].is_sugared_doc || self[first_group_len].is_sugared_doc {
                let snippet = context.snippet(missing_span);
                let (mla, mlb) = has_newlines_before_after_comment(snippet);
                let comment = ::comment::recover_missing_comment_in_span(
                    missing_span,
                    shape.with_max_width(context.config),
                    context,
                    0,
                )?;
                let comment = if comment.is_empty() {
                    format!("\n{}", mlb)
                } else {
                    format!("{}{}\n{}", mla, comment, mlb)
                };
                Some(format!(
                    "{}{}{}{}",
                    first_group_str,
                    comment,
                    shape.indent.to_string(context.config),
                    rest_str
                ))
            } else {
                combine_strs_with_missing_comments(
                    context,
                    &first_group_str,
                    &rest_str,
                    missing_span,
                    shape,
                    false,
                )
            }
        }
    }
}
<|endoftext|>


<commit_before>//! See [`patch_json_for_outdated_configs`]
use serde_json::{json, Value};

/// This function patches the json config to the new expected keys.
/// That is we try to load old known config keys here and convert them to the new ones.
/// See https://github.com/rust-lang/rust-analyzer/pull/12010
pub(super) fn patch_json_for_outdated_configs(json: &mut Value) {
    let copy = json.clone();

    macro_rules! patch {
        ($(
            $($src:ident).+ -> $($dst:ident).+ ;
        )+) => { $(
            match copy.pointer(concat!($("/", stringify!($src)),+)).cloned() {
                Some(Value::Object(_)) | None => (),
                Some(it) => {
                    let mut last = it;
                    for segment in [$(stringify!($dst)),+].into_iter().rev() {
                        last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_string(), last))));
                    }

                    merge(json, last);
                },
            }
        )+ };
    }

    patch! {
        assist.allowMergingIntoGlobImports -> imports.merge.glob;
        assist.exprFillDefault -> assist.expressionFillDefault;
        assist.importEnforceGranularity -> imports.granularity.enforce;
        assist.importGranularity -> imports.granularity.group;
        assist.importMergeBehavior -> imports.granularity.group;
        assist.importMergeBehaviour -> imports.granularity.group;
        assist.importGroup -> imports.group.enable;
        assist.importPrefix -> imports.prefix;
        primeCaches.enable -> cachePriming.enable;
        cache.warmup -> cachePriming.enable;
        cargo.loadOutDirsFromCheck -> cargo.buildScripts.enable;
        cargo.runBuildScripts -> cargo.buildScripts.enable;
        cargo.runBuildScriptsCommand -> cargo.buildScripts.overrideCommand;
        cargo.useRustcWrapperForBuildScripts -> cargo.buildScripts.useRustcWrapper;
        diagnostics.enableExperimental -> diagnostics.experimental.enable;
        experimental.procAttrMacros -> procMacro.attributes.enable;
        highlighting.strings -> semanticHighlighting.strings.enable;
        highlightRelated.breakPoints -> semanticHighlighting.breakPoints.enable;
        highlightRelated.exitPoints -> semanticHighlighting.exitPoints.enable;
        highlightRelated.yieldPoints -> semanticHighlighting.yieldPoints.enable;
        highlightRelated.references -> semanticHighlighting.references.enable;
        hover.documentation -> hover.documentation.enable;
        hover.linksInHover -> hover.links.enable;
        hoverActions.linksInHover -> hover.links.enable;
        hoverActions.debug -> hover.actions.debug.enable;
        hoverActions.enable -> hover.actions.enable;
        hoverActions.gotoTypeDef -> hover.actions.gotoTypeDef.enable;
        hoverActions.implementations -> hover.actions.implementations.enable;
        hoverActions.references -> hover.actions.references.enable;
        hoverActions.run -> hover.actions.run.enable;
        inlayHints.chainingHints -> inlayHints.chainingHints.enable;
        inlayHints.closureReturnTypeHints -> inlayHints.closureReturnTypeHints.enable;
        inlayHints.hideNamedConstructorHints -> inlayHints.typeHints.hideNamedConstructorHints;
        inlayHints.parameterHints -> inlayHints.parameterHints.enable;
        inlayHints.reborrowHints -> inlayHints.reborrowHints.enable;
        inlayHints.typeHints -> inlayHints.typeHints.enable;
        lruCapacity -> lru.capacity;
        runnables.cargoExtraArgs -> runnables.extraArgs ;
        runnables.overrideCargo -> runnables.command ;
        rustcSource -> rustc.source;
        rustfmt.enableRangeFormatting -> rustfmt.rangeFormatting.enable;
    }

    // completion.snippets -> completion.snippets.custom;
    if let Some(Value::Object(obj)) = copy.pointer("/completion/snippets").cloned() {
        if obj.len() != 1 || obj.get("custom").is_none() {
            merge(
                json,
                json! {{
                    "completion": {
                        "snippets": {
                            "custom": obj
                        },
                    },
                }},
            );
        }
    }

    // callInfo_full -> signatureInfo_detail, signatureInfo_documentation_enable
    if let Some(Value::Bool(b)) = copy.pointer("/callInfo/full") {
        let sig_info = match b {
            true => json!({ "signatureInfo": {
                "documentation": {"enable": true}},
                "detail": "full"
            }),
            false => json!({ "signatureInfo": {
                "documentation": {"enable": false}},
                "detail": "parameters"
            }),
        };
        merge(json, sig_info);
    }

    // cargo_allFeatures, cargo_features -> cargo_features
    if let Some(Value::Bool(true)) = copy.pointer("/cargo/allFeatures") {
        merge(json, json!({ "cargo": { "features": "all" } }));
    }

    // checkOnSave_allFeatures, checkOnSave_features -> checkOnSave_features
    if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") {
        merge(json, json!({ "checkOnSave": { "features": "all" } }));
    }

    // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets
    let res = match (
        copy.pointer("/completion/addCallArgumentSnippets"),
        copy.pointer("/completion/addCallParenthesis"),
    ) {
        (Some(Value::Bool(true)), Some(Value::Bool(true))) => json!("fill_arguments"),
        (Some(Value::Bool(true)), _) => json!("add_parentheses"),
        (Some(Value::Bool(false)), Some(Value::Bool(false))) => json!("add_parentheses"),
        (_, _) => return,
    };
    merge(json, json!({ "completion": { "callable": {"snippets": res }} }));
}

fn merge(dst: &mut Value, src: Value) {
    match (dst, src) {
        (Value::Object(dst), Value::Object(src)) => {
            for (k, v) in src {
                merge(dst.entry(k).or_insert(v.clone()), v)
            }
        }
        (dst, src) => *dst = src,
    }
}
<commit_msg>fix: Fix config patching for callable snippets<commit_after>//! See [`patch_json_for_outdated_configs`]
use serde_json::{json, Value};

/// This function patches the json config to the new expected keys.
/// That is we try to load old known config keys here and convert them to the new ones.
/// See https://github.com/rust-lang/rust-analyzer/pull/12010
pub(super) fn patch_json_for_outdated_configs(json: &mut Value) {
    let copy = json.clone();

    macro_rules! patch {
        ($(
            $($src:ident).+ -> $($dst:ident).+ ;
        )+) => { $(
            match copy.pointer(concat!($("/", stringify!($src)),+)).cloned() {
                Some(Value::Object(_)) | None => (),
                Some(it) => {
                    let mut last = it;
                    for segment in [$(stringify!($dst)),+].into_iter().rev() {
                        last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_string(), last))));
                    }

                    merge(json, last);
                },
            }
        )+ };
    }

    patch! {
        assist.allowMergingIntoGlobImports -> imports.merge.glob;
        assist.exprFillDefault -> assist.expressionFillDefault;
        assist.importEnforceGranularity -> imports.granularity.enforce;
        assist.importGranularity -> imports.granularity.group;
        assist.importMergeBehavior -> imports.granularity.group;
        assist.importMergeBehaviour -> imports.granularity.group;
        assist.importGroup -> imports.group.enable;
        assist.importPrefix -> imports.prefix;
        primeCaches.enable -> cachePriming.enable;
        cache.warmup -> cachePriming.enable;
        cargo.loadOutDirsFromCheck -> cargo.buildScripts.enable;
        cargo.runBuildScripts -> cargo.buildScripts.enable;
        cargo.runBuildScriptsCommand -> cargo.buildScripts.overrideCommand;
        cargo.useRustcWrapperForBuildScripts -> cargo.buildScripts.useRustcWrapper;
        diagnostics.enableExperimental -> diagnostics.experimental.enable;
        experimental.procAttrMacros -> procMacro.attributes.enable;
        highlighting.strings -> semanticHighlighting.strings.enable;
        highlightRelated.breakPoints -> semanticHighlighting.breakPoints.enable;
        highlightRelated.exitPoints -> semanticHighlighting.exitPoints.enable;
        highlightRelated.yieldPoints -> semanticHighlighting.yieldPoints.enable;
        highlightRelated.references -> semanticHighlighting.references.enable;
        hover.documentation -> hover.documentation.enable;
        hover.linksInHover -> hover.links.enable;
        hoverActions.linksInHover -> hover.links.enable;
        hoverActions.debug -> hover.actions.debug.enable;
        hoverActions.enable -> hover.actions.enable;
        hoverActions.gotoTypeDef -> hover.actions.gotoTypeDef.enable;
        hoverActions.implementations -> hover.actions.implementations.enable;
        hoverActions.references -> hover.actions.references.enable;
        hoverActions.run -> hover.actions.run.enable;
        inlayHints.chainingHints -> inlayHints.chainingHints.enable;
        inlayHints.closureReturnTypeHints -> inlayHints.closureReturnTypeHints.enable;
        inlayHints.hideNamedConstructorHints -> inlayHints.typeHints.hideNamedConstructorHints;
        inlayHints.parameterHints -> inlayHints.parameterHints.enable;
        inlayHints.reborrowHints -> inlayHints.reborrowHints.enable;
        inlayHints.typeHints -> inlayHints.typeHints.enable;
        lruCapacity -> lru.capacity;
        runnables.cargoExtraArgs -> runnables.extraArgs ;
        runnables.overrideCargo -> runnables.command ;
        rustcSource -> rustc.source;
        rustfmt.enableRangeFormatting -> rustfmt.rangeFormatting.enable;
    }

    // completion.snippets -> completion.snippets.custom;
    if let Some(Value::Object(obj)) = copy.pointer("/completion/snippets").cloned() {
        if obj.len() != 1 || obj.get("custom").is_none() {
            merge(
                json,
                json! {{
                    "completion": {
                        "snippets": {
                            "custom": obj
                        },
                    },
                }},
            );
        }
    }

    // callInfo_full -> signatureInfo_detail, signatureInfo_documentation_enable
    if let Some(Value::Bool(b)) = copy.pointer("/callInfo/full") {
        let sig_info = match b {
            true => json!({ "signatureInfo": {
                "documentation": {"enable": true}},
                "detail": "full"
            }),
            false => json!({ "signatureInfo": {
                "documentation": {"enable": false}},
                "detail": "parameters"
            }),
        };
        merge(json, sig_info);
    }

    // cargo_allFeatures, cargo_features -> cargo_features
    if let Some(Value::Bool(true)) = copy.pointer("/cargo/allFeatures") {
        merge(json, json!({ "cargo": { "features": "all" } }));
    }

    // checkOnSave_allFeatures, checkOnSave_features -> checkOnSave_features
    if let Some(Value::Bool(true)) = copy.pointer("/checkOnSave/allFeatures") {
        merge(json, json!({ "checkOnSave": { "features": "all" } }));
    }

    // completion_addCallArgumentSnippets completion_addCallParenthesis -> completion_callable_snippets
    let res = match (
        copy.pointer("/completion/addCallArgumentSnippets"),
        copy.pointer("/completion/addCallParenthesis"),
    ) {
        (Some(Value::Bool(true)), Some(Value::Bool(true))) => json!("fill_arguments"),
        (Some(Value::Bool(true)), _) => json!("add_parentheses"),
        (Some(Value::Bool(false)), Some(Value::Bool(false))) => json!("none"),
        (_, _) => return,
    };
    merge(json, json!({ "completion": { "callable": {"snippets": res }} }));
}

fn merge(dst: &mut Value, src: Value) {
    match (dst, src) {
        (Value::Object(dst), Value::Object(src)) => {
            for (k, v) in src {
                merge(dst.entry(k).or_insert(v.clone()), v)
            }
        }
        (dst, src) => *dst = src,
    }
}
<|endoftext|>


<commit_before>use std::convert::TryFrom;
use gc::Gc;

use value::{Program, Proc, Value, ValueRef};
use bytecode::*;

#[derive(Debug)]
pub enum VMError {
    OutOfInstrs,
    Uninitialized,
    Type
}

impl<'a> TryFrom<&'a Value> for isize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<isize, VMError> {
        if let &Value::Int(i) = v {
            Ok(i)
        } else {
            Err(VMError::Type)
        }
    }
}

impl<'a> TryFrom<&'a Value> for usize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<usize, VMError> {
        if let &Value::Int(i) = v {
            Ok(i as usize)
        } else {
            Err(VMError::Type)
        }
    }
}

#[derive(Debug)]
pub struct VM {
    regs: Vec<ValueRef>,
    procs: Vec<Gc<Proc>>,
    curr_proc: Gc<Proc>,
    pc: usize
}

impl VM {
    pub fn new(program: &Program) -> VM {
        let procs = program.procs.clone();
        let curr_proc = program.procs[program.entry].clone();
        VM {
            regs: vec![Gc::new(Value::Null); program.register_demand],
            procs: procs,
            curr_proc: curr_proc,
            pc: 0
        }
    }

    fn consts(&self) -> &[ValueRef] { self.curr_proc.consts.as_slice() }

    fn instrs(&self) -> &[Instr] { self.curr_proc.instrs.as_slice() }

    fn atom(&self, ai: Atom) -> &ValueRef {
        match ai {
            Atom::Reg(ri) => &self.regs[ri],
            Atom::Const(ci) => &self.consts()[ci]
        }
    }

    pub fn run(&mut self) -> Result<ValueRef, VMError> {
        while self.pc < self.instrs().len() {
            let instr = self.instrs()[self.pc];
            self.pc += 1;
            match instr.op() {
                MOV => {
                    let di = instr.byte_arg(0);
                    let v = self.atom(instr.atom_arg(1)).clone();
                    self.regs[di] = v;
                },

                IEQ => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Bool(a == b));
                },
                IADD => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a + b));
                },
                ISUB => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a - b));
                },
                IMUL => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a * b));
                },

                BOX_NEW => {
                    let di = instr.byte_arg(0);
                    self.regs[di] = Gc::new(Value::new_box());
                },
                BOX_INIT => {
                    let b = &self.regs[instr.byte_arg(0)];
                    let v = self.atom(instr.atom_arg(1));
                    if let &Value::Box(ref cell) = &**b {
                        *cell.borrow_mut() = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                BOX_GET => {
                    let di = instr.byte_arg(0);
                    let b = self.atom(instr.atom_arg(1)).clone();
                    if let &Value::Box(ref cell) = &*b {
                        self.regs[di] = cell.borrow().clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                TUPLE_NEW => {
                    let di = instr.byte_arg(0);
                    let len = isize::try_from(&**self.atom(instr.atom_arg(1)))? as usize;
                    self.regs[di] = Gc::new(Value::new_tuple(len));
                },
                TUPLE_INIT => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let v = self.atom(instr.atom_arg(2));
                    if let &Value::Tuple(ref fields_cell) = &**f {
                        fields_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                TUPLE_LEN => {
                    let di = instr.byte_arg(0);
                    let t = self.atom(instr.atom_arg(1)).clone();
                    if let &Value::Tuple(ref fields_cell) = &*t {
                        self.regs[di] = Gc::new(Value::Int(fields_cell.borrow().len() as isize));
                    } else {
                        return Err(VMError::Type);
                    }
                },
                TUPLE_GET => {
                    let di = instr.byte_arg(0);
                    let t = self.atom(instr.atom_arg(1)).clone();
                    let i = usize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    if let &Value::Tuple(ref fields_cell) = &*t {
                        self.regs[di] = fields_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                FN_NEW => {
                    let di = instr.byte_arg(0);
                    let len = usize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    self.regs[di] = Gc::new(Value::new_fn(len));
                },
                FN_INIT_CODE => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let cob = &self.procs[instr.short_arg()];
                    if let &Value::Fn(ref proc_cell, _) = &**f {
                        *proc_cell.borrow_mut() = Some(cob.clone());
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_INIT => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let v = self.atom(instr.atom_arg(2));
                    if let &Value::Fn(_, ref env_cell) = &**f {
                        env_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_CODE => {
                    let di = instr.byte_arg(0);
                    let f = self.atom(instr.atom_arg(1)).clone();
                    if let &Value::Fn(ref proc_cell, _) = &*f {
                        if let &Some(ref cob) = &*proc_cell.borrow() {
                            self.regs[di] = Gc::new(Value::CodePtr(cob.clone(), 0));
                        } else {
                            return Err(VMError::Uninitialized);
                        }
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_GET => {
                    let di = instr.byte_arg(0);
                    let f = self.regs[instr.byte_arg(1)].clone();
                    let i = usize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    if let &Value::Fn(_, ref env_cell) = &*f {
                        self.regs[di] = env_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                CONT_NEW => {
                    let di = instr.byte_arg(0);
                    let len = usize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    self.regs[di] = Gc::new(Value::new_cont(len));
                },
                CONT_INIT_CODE => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let offset = instr.short_arg() as isize;
                    if let &Value::Cont(ref code_cell, _) = &**f {
                        let cont_pc = (self.pc as isize + offset) as usize;
                        let code = Gc::new(Value::CodePtr(self.curr_proc.clone(), cont_pc));
                        *code_cell.borrow_mut() = code;
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_INIT => {
                    let k = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.atom(instr.atom_arg(1)))?;
                    let v = self.atom(instr.atom_arg(2));
                    if let &Value::Cont(_, ref env_cell) = &**k {
                        env_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_CODE => {
                    let di = instr.byte_arg(0);
                    let k = self.atom(instr.atom_arg(1)).clone();
                    if let &Value::Cont(ref code_cell, _) = &*k {
                        if let &Value::CodePtr(ref cob, ref pc) = &**code_cell.borrow() {
                            self.regs[di] = Gc::new(Value::CodePtr(cob.clone(), *pc));
                        } else {
                            return Err(VMError::Uninitialized);
                        }
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_GET => {
                    let di = instr.byte_arg(0);
                    let k = self.regs[instr.byte_arg(1)].clone();
                    let i = usize::try_from(&**self.atom(instr.atom_arg(2)))?;
                    if let &Value::Cont(_, ref env_cell) = &*k {
                        self.regs[di] = env_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                DENV_NEW => {
                    let di = instr.byte_arg(0);
                    self.regs[di] = Gc::new(Value::new_denv());
                },

                BRF => {
                    let cond = self.atom(instr.atom_arg(0)).clone();
                    match &*cond {
                        &Value::Bool(true) => {},
                        &Value::Bool(false) => {
                            let offset = instr.short_arg() as isize;
                            self.pc = (self.pc as isize + offset) as usize;
                        },
                        _ => return Err(VMError::Type)
                    }
                }

                IJMP => {
                    let code = &self.regs[instr.byte_arg(0)];
                    if let &Value::CodePtr(ref cob, ref pc) = &**code {
                        self.curr_proc = cob.clone();
                        self.pc = *pc;
                    } else {
                        return Err(VMError::Type);
                    }
                },

                HALT => return Ok(self.atom(instr.atom_arg(0)).clone()),

                op => panic!("unimplemented op {:?}", op)
            }
        }
        Err(VMError::OutOfInstrs)
    }
}
<commit_msg>Rethink VM convenience methods and loop structure.<commit_after>use std::convert::TryFrom;
use gc::Gc;

use value::{Program, Proc, Value, ValueRef};
use bytecode::*;

#[derive(Debug)]
pub enum VMError {
    OutOfInstrs,
    Uninitialized,
    Type
}

impl<'a> TryFrom<&'a Value> for isize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<isize, VMError> {
        if let &Value::Int(i) = v {
            Ok(i)
        } else {
            Err(VMError::Type)
        }
    }
}

impl<'a> TryFrom<&'a Value> for usize {
    type Error = VMError;

    fn try_from(v: &Value) -> Result<usize, VMError> {
        if let &Value::Int(i) = v {
            Ok(i as usize)
        } else {
            Err(VMError::Type)
        }
    }
}

#[derive(Debug)]
pub struct VM {
    regs: Vec<ValueRef>,
    procs: Vec<Gc<Proc>>,
    curr_proc: Gc<Proc>,
    pc: usize
}

impl VM {
    pub fn new(program: &Program) -> VM {
        let procs = program.procs.clone();
        let curr_proc = program.procs[program.entry].clone();
        VM {
            regs: vec![Gc::new(Value::Null); program.register_demand],
            procs: procs,
            curr_proc: curr_proc,
            pc: 0
        }
    }

    fn fetch(&mut self) -> Result<Instr, VMError> {
        if let Some(&instr) = self.curr_proc.instrs.get(self.pc) {
            self.pc += 1;
            Ok(instr)
        } else {
            Err(VMError::OutOfInstrs)
        }
    }

    fn load_atom(&self, ai: Atom) -> &ValueRef {
        match ai {
            Atom::Reg(ri) => &self.regs[ri],
            Atom::Const(ci) => &self.curr_proc.consts[ci]
        }
    }

    pub fn run(&mut self) -> Result<ValueRef, VMError> {
        loop {
            let instr = self.fetch()?;
            match instr.op() {
                MOV => {
                    let di = instr.byte_arg(0);
                    let v = self.load_atom(instr.atom_arg(1)).clone();
                    self.regs[di] = v;
                },

                IEQ => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Bool(a == b));
                },
                IADD => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a + b));
                },
                ISUB => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a - b));
                },
                IMUL => {
                    let di = instr.byte_arg(0);
                    let a = isize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let b = isize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    self.regs[di] = Gc::new(Value::Int(a * b));
                },

                BOX_NEW => {
                    let di = instr.byte_arg(0);
                    self.regs[di] = Gc::new(Value::new_box());
                },
                BOX_INIT => {
                    let b = &self.regs[instr.byte_arg(0)];
                    let v = self.load_atom(instr.atom_arg(1));
                    if let &Value::Box(ref cell) = &**b {
                        *cell.borrow_mut() = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                BOX_GET => {
                    let di = instr.byte_arg(0);
                    let b = self.load_atom(instr.atom_arg(1)).clone();
                    if let &Value::Box(ref cell) = &*b {
                        self.regs[di] = cell.borrow().clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                TUPLE_NEW => {
                    let di = instr.byte_arg(0);
                    let len = isize::try_from(&**self.load_atom(instr.atom_arg(1)))? as usize;
                    self.regs[di] = Gc::new(Value::new_tuple(len));
                },
                TUPLE_INIT => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let v = self.load_atom(instr.atom_arg(2));
                    if let &Value::Tuple(ref fields_cell) = &**f {
                        fields_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                TUPLE_LEN => {
                    let di = instr.byte_arg(0);
                    let t = self.load_atom(instr.atom_arg(1)).clone();
                    if let &Value::Tuple(ref fields_cell) = &*t {
                        self.regs[di] = Gc::new(Value::Int(fields_cell.borrow().len() as isize));
                    } else {
                        return Err(VMError::Type);
                    }
                },
                TUPLE_GET => {
                    let di = instr.byte_arg(0);
                    let t = self.load_atom(instr.atom_arg(1)).clone();
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    if let &Value::Tuple(ref fields_cell) = &*t {
                        self.regs[di] = fields_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                FN_NEW => {
                    let di = instr.byte_arg(0);
                    let len = usize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    self.regs[di] = Gc::new(Value::new_fn(len));
                },
                FN_INIT_CODE => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let cob = &self.procs[instr.short_arg()];
                    if let &Value::Fn(ref proc_cell, _) = &**f {
                        *proc_cell.borrow_mut() = Some(cob.clone());
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_INIT => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let v = self.load_atom(instr.atom_arg(2));
                    if let &Value::Fn(_, ref env_cell) = &**f {
                        env_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_CODE => {
                    let di = instr.byte_arg(0);
                    let f = self.load_atom(instr.atom_arg(1)).clone();
                    if let &Value::Fn(ref proc_cell, _) = &*f {
                        if let &Some(ref cob) = &*proc_cell.borrow() {
                            self.regs[di] = Gc::new(Value::CodePtr(cob.clone(), 0));
                        } else {
                            return Err(VMError::Uninitialized);
                        }
                    } else {
                        return Err(VMError::Type);
                    }
                },
                FN_GET => {
                    let di = instr.byte_arg(0);
                    let f = self.regs[instr.byte_arg(1)].clone();
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    if let &Value::Fn(_, ref env_cell) = &*f {
                        self.regs[di] = env_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                CONT_NEW => {
                    let di = instr.byte_arg(0);
                    let len = usize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    self.regs[di] = Gc::new(Value::new_cont(len));
                },
                CONT_INIT_CODE => {
                    let f = &self.regs[instr.byte_arg(0)];
                    let offset = instr.short_arg() as isize;
                    if let &Value::Cont(ref code_cell, _) = &**f {
                        let cont_pc = (self.pc as isize + offset) as usize;
                        let code = Gc::new(Value::CodePtr(self.curr_proc.clone(), cont_pc));
                        *code_cell.borrow_mut() = code;
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_INIT => {
                    let k = &self.regs[instr.byte_arg(0)];
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(1)))?;
                    let v = self.load_atom(instr.atom_arg(2));
                    if let &Value::Cont(_, ref env_cell) = &**k {
                        env_cell.borrow_mut()[i] = v.clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_CODE => {
                    let di = instr.byte_arg(0);
                    let k = self.load_atom(instr.atom_arg(1)).clone();
                    if let &Value::Cont(ref code_cell, _) = &*k {
                        if let &Value::CodePtr(ref cob, ref pc) = &**code_cell.borrow() {
                            self.regs[di] = Gc::new(Value::CodePtr(cob.clone(), *pc));
                        } else {
                            return Err(VMError::Uninitialized);
                        }
                    } else {
                        return Err(VMError::Type);
                    }
                },
                CONT_GET => {
                    let di = instr.byte_arg(0);
                    let k = self.regs[instr.byte_arg(1)].clone();
                    let i = usize::try_from(&**self.load_atom(instr.atom_arg(2)))?;
                    if let &Value::Cont(_, ref env_cell) = &*k {
                        self.regs[di] = env_cell.borrow()[i].clone();
                    } else {
                        return Err(VMError::Type);
                    }
                },

                DENV_NEW => {
                    let di = instr.byte_arg(0);
                    self.regs[di] = Gc::new(Value::new_denv());
                },

                BRF => {
                    let cond = self.load_atom(instr.atom_arg(0)).clone();
                    match &*cond {
                        &Value::Bool(true) => {},
                        &Value::Bool(false) => {
                            let offset = instr.short_arg() as isize;
                            self.pc = (self.pc as isize + offset) as usize;
                        },
                        _ => return Err(VMError::Type)
                    }
                }

                IJMP => {
                    let code = &self.regs[instr.byte_arg(0)];
                    if let &Value::CodePtr(ref cob, ref pc) = &**code {
                        self.curr_proc = cob.clone();
                        self.pc = *pc;
                    } else {
                        return Err(VMError::Type);
                    }
                },

                HALT => return Ok(self.load_atom(instr.atom_arg(0)).clone()),

                op => panic!("unimplemented op {:?}", op)
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::env::args;

struct Diff {
    a: String,
    b: String,
    m: usize,
    n: usize,
}

fn build_diff(a: String, b: String) -> Diff {
    if a.len() > b.len() {
        return Diff {
            a: b.to_string(),
            b: a.to_string(),
            m: b.len(),
            n: a.len(),
        };
    }
    return Diff {
        a: a.to_string(),
        b: b.to_string(),
        m: a.len(),
        n: b.len(),
    };
}

impl Diff {
    fn snake(&self, mut x: usize, mut y: usize) -> usize {
        while x < self.m
            && y < self.n
            && self.a.chars().nth(x).unwrap() == self.b.chars().nth(y).unwrap()
        {
            x = x + 1;
            y = y + 1;
        }

        return y;
    }

    fn ed(&self) -> usize {
        let offset: usize = self.m + 1;
        let delta: usize = self.n - self.m;
        let size = self.m + self.n + 3;
        let mut fp: Vec<usize> = vec![0; size];

        let mut p: usize = 0;
        loop {
            let mut k = offset - p;
            while k <= delta + offset - 1 {
                let y = max(fp[k - 1] + 1, fp[k + 1]);
                if offset < k {
                    fp[k] = self.snake(y - (k - offset), y);
                } else {
                    fp[k] = self.snake(y + (offset - k), y);
                }
                k = k + 1;
            }
            let mut l = delta + p;
            while l >= delta + 1 {
                let y = max(fp[l + offset - 1] + 1, fp[l + 1 + offset]);
                fp[l + offset] = self.snake(y - l, y);
                l = l - 1;
            }

            let y = max(fp[delta + offset - 1] + 1, fp[delta + 1 + offset]);
            fp[delta + offset] = self.snake(y - delta, y);

            if fp[delta + offset] >= self.n {
                break;
            }
            p = p + 1;
        }
        return delta + 2 * p;
    }
}

fn main() {
    let args: Vec<String> = args().collect();

    if args.len() < 3 {
        println!("few arguments");
        std::process::exit(1);
    }

    let a = &args[1];
    let b = &args[2];

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

    let d = build_diff(a.to_string(), b.to_string());

    println!("ed: {}", d.ed());
}
<commit_msg>minor changed<commit_after>use std::cmp::max;
use std::env::args;

struct Diff {
    a: String,
    b: String,
    m: usize,
    n: usize,
}

fn build_diff(a: String, b: String) -> Diff {
    if a.len() > b.len() {
        return Diff {
            a: b.to_string(),
            b: a.to_string(),
            m: b.len(),
            n: a.len(),
        };
    }
    return Diff {
        a: a.to_string(),
        b: b.to_string(),
        m: a.len(),
        n: b.len(),
    };
}

impl Diff {
    fn snake(&self, mut x: usize, mut y: usize) -> usize {
        while x < self.m
            && y < self.n
            && self.a.chars().nth(x).unwrap() == self.b.chars().nth(y).unwrap()
        {
            x = x + 1;
            y = y + 1;
        }

        return y;
    }

    fn ed(&self) -> usize {
        let offset: usize = self.m + 1;
        let delta: usize = self.n - self.m;
        let size = self.m + self.n + 3;
        let mut fp: Vec<usize> = vec![0; size];

        let mut p: usize = 0;
        loop {
            let mut k = offset - p;
            while k <= delta + offset - 1 {
                let y = max(fp[k - 1] + 1, fp[k + 1]);
                if offset < k {
                    fp[k] = self.snake(y - (k - offset), y);
                } else {
                    fp[k] = self.snake(y + (offset - k), y);
                }
                k = k + 1;
            }
            let mut l = delta + p;
            while l >= delta + 1 {
                let y = max(fp[l + offset - 1] + 1, fp[l + 1 + offset]);
                fp[l + offset] = self.snake(y - l, y);
                l = l - 1;
            }

            let y = max(fp[delta + offset - 1] + 1, fp[delta + 1 + offset]);
            fp[delta + offset] = self.snake(y - delta, y);

            if fp[delta + offset] >= self.n {
                break;
            }
            p = p + 1;
        }
        return delta + 2 * p;
    }
}

fn main() {
    let args: Vec<String> = args().collect();

    if args.len() < 3 {
        println!("few arguments");
        std::process::exit(1);
    }

    let a = &args[1];
    let b = &args[2];

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

    let d = build_diff(a.to_string(), b.to_string());

    println!("editdistance: {}", d.ed());
}
<|endoftext|>