<commit_before>extern crate hyper;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate http_event_store as hes;

#[macro_use]
mod support;

use support::task_domain::*;

use hes::write::Event;
use hes::client::Client;
use hes::expected_version::ExpectedVersion;
use hes::error::ApiError::*;

#[test]
fn should_append_events_in_right_order() {
    let created_id = uuid::Uuid::new_v4();
    let updated_id = uuid::Uuid::new_v4();
    let events: Vec<Event> = vec![
        TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: created_id }.into(),
        TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: updated_id }.into()
    ];

    let client = Client::default();
    let stream_name = test_stream_name();
    client.append_to_stream(&stream_name, ExpectedVersion::NoStream, events).unwrap();
    let stream = client.read_stream_events_forward(&stream_name, 0, 2, true).unwrap();

    assert_eq!("task-renamed", stream.entries[0].event_type);
    assert_eq!("task-created", stream.entries[1].event_type);
    assert_eq!(updated_id, stream.entries[0].event_id);
    assert_eq!(created_id, stream.entries[1].event_id);
}

#[test]
fn should_require_expected_version_to_be_correct() {
    let client = Client::default();
    let stream_name = test_stream_name();

    let mut version = ExpectedVersion::NoStream;
    client.append_to_stream(&stream_name, version, vec![task_created_event().into()]).unwrap();
    assert_eq!(1, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());

    version = ExpectedVersion::Number(0);
    client.append_to_stream(&stream_name, version, vec![task_renamed_event().into()]).unwrap();
    assert_eq!(2, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());

    version = ExpectedVersion::Number(1);
    client.append_to_stream(&stream_name, version, vec![task_renamed_event().into()]).unwrap();
    assert_eq!(3, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());
}

#[test]
fn should_return_wrong_expected_event_number_error_if_expected_version_is_wrong() {
    let client = Client::default();
    let stream_name = test_stream_name();

    let version = ExpectedVersion::Number(1);
    let result = client.append_to_stream(&stream_name, version, vec![task_created_event().into()]);

    assert_error!(WrongExpectedEventNumber(..), result.unwrap_err());
}

#[test]
fn should_fail_appending_with_any_expected_version_to_deleted_stream() {
    let client = Client::default();
    let stream_name = test_stream_name();

    client.append_to_stream(&stream_name, ExpectedVersion::NoStream, vec![task_created_event().into()]).unwrap();
    client.hard_delete_stream(&stream_name, ExpectedVersion::Any).unwrap();

    let result = client.append_to_stream(&stream_name, ExpectedVersion::Any, vec![task_renamed_event().into()]);

    assert_error!(StreamDeleted(..), result.unwrap_err());
}

#[test]
fn should_cope_with_empty_event_collection() {}

fn test_stream_name() -> String {
    format!("task-{}", uuid::Uuid::new_v4().simple())
}

fn task_created_event() -> TaskCreated {
    TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: uuid::Uuid::new_v4() }
}
fn task_renamed_event() -> TaskRenamed {
    TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: uuid::Uuid::new_v4() }
}
<commit_msg>Enhnace a test<commit_after>extern crate hyper;
extern crate serde;
extern crate serde_json;
extern crate time;
extern crate uuid;
extern crate http_event_store as hes;

#[macro_use]
mod support;

use support::task_domain::*;

use hes::write::Event;
use hes::client::Client;
use hes::expected_version::ExpectedVersion;
use hes::error::ApiError::*;

#[test]
fn should_append_events_in_right_order() {
    let created_id = uuid::Uuid::new_v4();
    let updated_id = uuid::Uuid::new_v4();
    let events: Vec<Event> = vec![
        TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: created_id }.into(),
        TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: updated_id }.into()
    ];

    let client = Client::default();
    let stream_name = test_stream_name();
    client.append_to_stream(&stream_name, ExpectedVersion::NoStream, events).unwrap();
    let stream = client.read_stream_events_forward(&stream_name, 0, 2, true).unwrap();

    assert_eq!("task-renamed", stream.entries[0].event_type);
    assert_eq!("task-created", stream.entries[1].event_type);
    assert_eq!(updated_id, stream.entries[0].event_id);
    assert_eq!(created_id, stream.entries[1].event_id);
    assert_eq!(1, stream.entries[0].event_number);
    assert_eq!(0, stream.entries[1].event_number);
}

#[test]
fn should_require_expected_version_to_be_correct() {
    let client = Client::default();
    let stream_name = test_stream_name();

    let mut version = ExpectedVersion::NoStream;
    client.append_to_stream(&stream_name, version, vec![task_created_event().into()]).unwrap();
    assert_eq!(1, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());

    version = ExpectedVersion::Number(0);
    client.append_to_stream(&stream_name, version, vec![task_renamed_event().into()]).unwrap();
    assert_eq!(2, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());

    version = ExpectedVersion::Number(1);
    client.append_to_stream(&stream_name, version, vec![task_renamed_event().into()]).unwrap();
    assert_eq!(3, client.read_stream_events_forward(&stream_name, 0, 3, true).unwrap().entries.len());
}

#[test]
fn should_return_wrong_expected_event_number_error_if_expected_version_is_wrong() {
    let client = Client::default();
    let stream_name = test_stream_name();

    let version = ExpectedVersion::Number(1);
    let result = client.append_to_stream(&stream_name, version, vec![task_created_event().into()]);

    assert_error!(WrongExpectedEventNumber(..), result.unwrap_err());
}

#[test]
fn should_fail_appending_with_any_expected_version_to_deleted_stream() {
    let client = Client::default();
    let stream_name = test_stream_name();

    client.append_to_stream(&stream_name, ExpectedVersion::NoStream, vec![task_created_event().into()]).unwrap();
    client.hard_delete_stream(&stream_name, ExpectedVersion::Any).unwrap();

    let result = client.append_to_stream(&stream_name, ExpectedVersion::Any, vec![task_renamed_event().into()]);

    assert_error!(StreamDeleted(..), result.unwrap_err());
}

#[test]
fn should_cope_with_empty_event_collection() {}

fn test_stream_name() -> String {
    format!("task-{}", uuid::Uuid::new_v4().simple())
}

fn task_created_event() -> TaskCreated {
    TaskCreated { name: format!("Created {:?}", time::get_time()), event_id: uuid::Uuid::new_v4() }
}
fn task_renamed_event() -> TaskRenamed {
    TaskRenamed { name: format!("Renamed {:?}", time::get_time()), event_id: uuid::Uuid::new_v4() }
}
<|endoftext|>


<commit_before>use std::fmt;

#[derive(Debug, PartialEq)]
pub enum ControlCommand {
    EvalStart,
    EvalOutput,
    EvalEnd,
    Duplicate,
    PopEvaluatedValue,
    PopFunction,
    PopTunnel,
    BeginString,
    EndString,
    NoOp,
    ChoiceCount,
    TurnsSince,
    ReadCount,
    Random,
    SeedRandom,
    VisitIndex,
    SequenceShuffleIndex,
    StartThread,
    Done,
    End,
    ListFromInt,
    ListRange
}

impl fmt::Display for ControlCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ControlCommand::EvalStart => write!(f, "ev"),
            ControlCommand::EvalOutput => write!(f, "out"),
            ControlCommand::EvalEnd => write!(f, "/ev"),
            ControlCommand::Duplicate => write!(f, "du"),
            ControlCommand::PopEvaluatedValue => write!(f, "pop"),
            ControlCommand::PopFunction => write!(f, "~ret"),
            ControlCommand::PopTunnel => write!(f, "->->"),
            ControlCommand::BeginString => write!(f, "str"),
            ControlCommand::EndString => write!(f, "/str"),
            ControlCommand::NoOp => write!(f, "nop"),
            ControlCommand::ChoiceCount => write!(f, "choiceCnt"),
            ControlCommand::TurnsSince => write!(f, "turns"),
            ControlCommand::ReadCount => write!(f, "readc"),
            ControlCommand::Random => write!(f, "rnd"),
            ControlCommand::SeedRandom => write!(f, "srnd"),
            ControlCommand::VisitIndex => write!(f, "visit"),
            ControlCommand::SequenceShuffleIndex => write!(f, "seq"),
            ControlCommand::StartThread => write!(f, "thread"),
            ControlCommand::Done => write!(f, "done"),
            ControlCommand::End => write!(f, "end"),
            ControlCommand::ListFromInt => write!(f, "listInt"),
            ControlCommand::ListRange => write!(f, "range"),
        }
    }
}<commit_msg>Add description of the control commands<commit_after>use std::fmt;

#[derive(Debug, PartialEq)]
pub enum ControlCommand {
    /// Begin logical evaluation mode. In evaluation mode, objects that are encounted are
    /// added to an evaluation stack, rather than simply echoed into the main text output stream.
    /// As they're pushed onto the stack, they may be processed by other commands, functions, etc.
    EvalStart,

    /// The topmost object on the evaluation stack is popped and appended to the output stream
    /// (main story output).
    EvalOutput,

    /// End logical evaluation mode. Future objects will be appended to the output stream rather
    /// than to the evaluation stack.
    EvalEnd,

    /// Duplicate the topmost object on the evaluation stack. Useful since some commands consume
    /// objects on the evaluation stack.
    Duplicate,

    /// Pops a value from the evaluation stack, without appending to the output stream.
    PopEvaluatedValue,

    /// pop the callstack - used for returning from a tunnel or function respectively. They are
    /// specified independently for error checking, since the callstack is aware of whether each
    /// element was pushed as a tunnel or function in the first place.
    PopFunction,
    PopTunnel,

    /// Begin string evaluation mode. Adds a marker to the output stream, and goes into content
    /// mode (from evaluation mode). Must have already been in evaluation mode when this is
    /// encounted.
    BeginString,

    /// End string evaluation mode. All content after the previous Begin marker is concatenated
    /// together, removed from the output stream, and appended as a string value to the evaluation
    /// stack. Re-enters evaluation mode immediately afterwards.
    EndString,

    /// No-operation. Does nothing, but is useful as an addressable piece of content to divert to.
    NoOp,

    /// Pushes an integer with the current number of choices to the evaluation stack.
    ChoiceCount,

    /// Pops from the evaluation stack, expecting to see a divert target for a knot, stitch,
    /// gather or choice. Pushes an integer with the number of turns since that target was last
    /// visited by the story engine.
    TurnsSince,

    ReadCount,
    Random,
    SeedRandom,
    VisitIndex,

    /// Pops an integer, expected to be the number of elements in a sequence that's being entered.
    /// In return, it pushes an integer with the next sequence shuffle index to the evaluation
    /// stack. This shuffle index is derived from the number of elements in the sequence, the
    /// number of elements in it, and the story's random seed from when it was first begun.
    SequenceShuffleIndex,

    /// Clones/starts a new thread, as used with the <- knot syntax in ink. This essentially
    /// clones the entire callstack, branching it.
    StartThread,

    /// Tries to close/pop the active thread, otherwise marks the story flow safe to exit without
    /// a loose end warning.
    Done,

    /// Ends the story flow immediately, closes all active threads, unwinds the callstack, and
    /// removes any choices that were previously created.
    End,

    ListFromInt,
    ListRange
}

impl fmt::Display for ControlCommand {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ControlCommand::EvalStart => write!(f, "ev"),
            ControlCommand::EvalOutput => write!(f, "out"),
            ControlCommand::EvalEnd => write!(f, "/ev"),
            ControlCommand::Duplicate => write!(f, "du"),
            ControlCommand::PopEvaluatedValue => write!(f, "pop"),
            ControlCommand::PopFunction => write!(f, "~ret"),
            ControlCommand::PopTunnel => write!(f, "->->"),
            ControlCommand::BeginString => write!(f, "str"),
            ControlCommand::EndString => write!(f, "/str"),
            ControlCommand::NoOp => write!(f, "nop"),
            ControlCommand::ChoiceCount => write!(f, "choiceCnt"),
            ControlCommand::TurnsSince => write!(f, "turns"),
            ControlCommand::ReadCount => write!(f, "readc"),
            ControlCommand::Random => write!(f, "rnd"),
            ControlCommand::SeedRandom => write!(f, "srnd"),
            ControlCommand::VisitIndex => write!(f, "visit"),
            ControlCommand::SequenceShuffleIndex => write!(f, "seq"),
            ControlCommand::StartThread => write!(f, "thread"),
            ControlCommand::Done => write!(f, "done"),
            ControlCommand::End => write!(f, "end"),
            ControlCommand::ListFromInt => write!(f, "listInt"),
            ControlCommand::ListRange => write!(f, "range"),
        }
    }
}<|endoftext|>


<commit_before>use doc::ItemUtils;
use io::ReaderUtil;

export WriteInstr;
export Writer;
export WriterFactory;
export WriterUtils;
export make_writer_factory;
export future_writer_factory;
export make_filename;

enum WriteInstr {
    Write(~str),
    Done
}

type Writer = fn~(+v: WriteInstr);
type WriterFactory = fn~(page: doc::Page) -> Writer;

trait WriterUtils {
    fn write_str(str: ~str);
    fn write_line(str: ~str);
    fn write_done();
}

impl Writer: WriterUtils {
    fn write_str(str: ~str) {
        self(Write(str));
    }

    fn write_line(str: ~str) {
        self.write_str(str + ~"\n");
    }

    fn write_done() {
        self(Done)
    }
}

fn make_writer_factory(config: config::Config) -> WriterFactory {
    match config.output_format {
      config::Markdown => {
        markdown_writer_factory(config)
      }
      config::PandocHtml => {
        pandoc_writer_factory(config)
      }
    }
}

fn markdown_writer_factory(config: config::Config) -> WriterFactory {
    fn~(page: doc::Page) -> Writer {
        markdown_writer(config, page)
    }
}

fn pandoc_writer_factory(config: config::Config) -> WriterFactory {
    fn~(page: doc::Page) -> Writer {
        pandoc_writer(config, page)
    }
}

fn markdown_writer(
    config: config::Config,
    page: doc::Page
) -> Writer {
    let filename = make_local_filename(config, page);
    do generic_writer |markdown| {
        write_file(&filename, markdown);
    }
}

fn pandoc_writer(
    config: config::Config,
    page: doc::Page
) -> Writer {
    assert config.pandoc_cmd.is_some();
    let pandoc_cmd = config.pandoc_cmd.get();
    let filename = make_local_filename(config, page);

    let pandoc_args = ~[
        ~"--standalone",
        ~"--section-divs",
        ~"--from=markdown",
        ~"--to=html",
        ~"--css=rust.css",
        ~"--output=" + filename.to_str()
    ];

    do generic_writer |markdown| {
        use io::WriterUtil;

        debug!("pandoc cmd: %s", pandoc_cmd);
        debug!("pandoc args: %s", str::connect(pandoc_args, ~" "));

        let pipe_in = os::pipe();
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let pid = run::spawn_process(
            pandoc_cmd, pandoc_args, &None, &None,
            pipe_in.in, pipe_out.out, pipe_err.out);

        let writer = io::fd_writer(pipe_in.out, false);
        writer.write_str(markdown);

        os::close(pipe_in.in);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        os::close(pipe_in.out);

        let stdout_po = comm::Port();
        let stdout_ch = comm::Chan(&stdout_po);
        do task::spawn_sched(task::SingleThreaded) {
            comm::send(stdout_ch, readclose(pipe_out.in));
        }
        let stdout = comm::recv(stdout_po);

        let stderr_po = comm::Port();
        let stderr_ch = comm::Chan(&stderr_po);
        do task::spawn_sched(task::SingleThreaded) {
            comm::send(stderr_ch, readclose(pipe_err.in));
        }
        let stderr = comm::recv(stderr_po);

        let status = run::waitpid(pid);
        debug!("pandoc result: %i", status);
        if status != 0 {
            error!("pandoc-out: %s", stdout);
            error!("pandoc-err: %s", stderr);
            fail ~"pandoc failed";
        }
    }
}

fn readclose(fd: libc::c_int) -> ~str {
    // Copied from run::program_output
    let file = os::fdopen(fd);
    let reader = io::FILE_reader(file, false);
    let mut buf = ~"";
    while !reader.eof() {
        let bytes = reader.read_bytes(4096u);
        buf += str::from_bytes(bytes);
    }
    os::fclose(file);
    return buf;
}

fn generic_writer(+process: fn~(markdown: ~str)) -> Writer {
    let ch = do task::spawn_listener
        |move process, po: comm::Port<WriteInstr>| {
        let mut markdown = ~"";
        let mut keep_going = true;
        while keep_going {
            match comm::recv(po) {
              Write(s) => markdown += s,
              Done => keep_going = false
            }
        }
        process(move markdown);
    };

    fn~(+instr: WriteInstr) {
        comm::send(ch, instr);
    }
}

fn make_local_filename(
    config: config::Config,
    page: doc::Page
) -> Path {
    let filename = make_filename(config, page);
    config.output_dir.push_rel(&filename)
}

fn make_filename(
    config: config::Config,
    page: doc::Page
) -> Path {
    let filename = {
        match page {
          doc::CratePage(doc) => {
            if config.output_format == config::PandocHtml &&
                config.output_style == config::DocPerMod {
                ~"index"
            } else {
                assert doc.topmod.name() != ~"";
                doc.topmod.name()
            }
          }
          doc::ItemPage(doc) => {
            str::connect(doc.path() + ~[doc.name()], ~"_")
          }
        }
    };
    let ext = match config.output_format {
      config::Markdown => ~"md",
      config::PandocHtml => ~"html"
    };

    Path(filename).with_filetype(ext)
}

#[test]
fn should_use_markdown_file_name_based_off_crate() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::Markdown,
        output_style: config::DocPerCrate,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"test", ~"");
    let page = doc::CratePage(doc.CrateDoc());
    let filename = make_local_filename(config, page);
    assert filename.to_str() == ~"output/dir/test.md";
}

#[test]
fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::PandocHtml,
        output_style: config::DocPerMod,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"", ~"");
    let page = doc::CratePage(doc.CrateDoc());
    let filename = make_local_filename(config, page);
    assert filename.to_str() == ~"output/dir/index.html";
}

#[test]
fn should_name_mod_file_names_by_path() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::PandocHtml,
        output_style: config::DocPerMod,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"", ~"mod a { mod b { } }");
    let modb = doc.cratemod().mods()[0].mods()[0];
    let page = doc::ItemPage(doc::ModTag(modb));
    let filename = make_local_filename(config, page);
    assert  filename == Path("output/dir/a_b.html");
}

#[cfg(test)]
mod test {
    #[legacy_exports];
    fn mk_doc(name: ~str, source: ~str) -> doc::Doc {
        do astsrv::from_str(source) |srv| {
            let doc = extract::from_srv(srv, name);
            let doc = path_pass::mk_pass().f(srv, doc);
            doc
        }
    }
}

fn write_file(path: &Path, s: ~str) {
    use io::WriterUtil;

    match io::file_writer(path, ~[io::Create, io::Truncate]) {
      result::Ok(writer) => {
        writer.write_str(s);
      }
      result::Err(e) => fail e
    }
}

fn future_writer_factory(
) -> (WriterFactory, comm::Port<(doc::Page, ~str)>) {
    let markdown_po = comm::Port();
    let markdown_ch = comm::Chan(&markdown_po);
    let writer_factory = fn~(page: doc::Page) -> Writer {
        let writer_po = comm::Port();
        let writer_ch = comm::Chan(&writer_po);
        do task::spawn {
            let (writer, future) = future_writer();
            comm::send(writer_ch, move writer);
            let s = future::get(&future);
            comm::send(markdown_ch, (page, s));
        }
        comm::recv(writer_po)
    };

    (move writer_factory, markdown_po)
}

fn future_writer() -> (Writer, future::Future<~str>) {
    let (chan, port) = pipes::stream();
    let writer = fn~(move chan, +instr: WriteInstr) {
        chan.send(copy instr);
    };
    let future = do future::from_fn |move port| {
        let mut res = ~"";
        loop {
            match port.recv() {
              Write(s) => res += s,
              Done => break
            }
        }
        res
    };
    (move writer, move future)
}
<commit_msg>rustdoc: Make markdown_writer::pandoc_writer UTF-8 safe<commit_after>use doc::ItemUtils;
use io::ReaderUtil;

export WriteInstr;
export Writer;
export WriterFactory;
export WriterUtils;
export make_writer_factory;
export future_writer_factory;
export make_filename;

enum WriteInstr {
    Write(~str),
    Done
}

type Writer = fn~(+v: WriteInstr);
type WriterFactory = fn~(page: doc::Page) -> Writer;

trait WriterUtils {
    fn write_str(str: ~str);
    fn write_line(str: ~str);
    fn write_done();
}

impl Writer: WriterUtils {
    fn write_str(str: ~str) {
        self(Write(str));
    }

    fn write_line(str: ~str) {
        self.write_str(str + ~"\n");
    }

    fn write_done() {
        self(Done)
    }
}

fn make_writer_factory(config: config::Config) -> WriterFactory {
    match config.output_format {
      config::Markdown => {
        markdown_writer_factory(config)
      }
      config::PandocHtml => {
        pandoc_writer_factory(config)
      }
    }
}

fn markdown_writer_factory(config: config::Config) -> WriterFactory {
    fn~(page: doc::Page) -> Writer {
        markdown_writer(config, page)
    }
}

fn pandoc_writer_factory(config: config::Config) -> WriterFactory {
    fn~(page: doc::Page) -> Writer {
        pandoc_writer(config, page)
    }
}

fn markdown_writer(
    config: config::Config,
    page: doc::Page
) -> Writer {
    let filename = make_local_filename(config, page);
    do generic_writer |markdown| {
        write_file(&filename, markdown);
    }
}

fn pandoc_writer(
    config: config::Config,
    page: doc::Page
) -> Writer {
    assert config.pandoc_cmd.is_some();
    let pandoc_cmd = config.pandoc_cmd.get();
    let filename = make_local_filename(config, page);

    let pandoc_args = ~[
        ~"--standalone",
        ~"--section-divs",
        ~"--from=markdown",
        ~"--to=html",
        ~"--css=rust.css",
        ~"--output=" + filename.to_str()
    ];

    do generic_writer |markdown| {
        use io::WriterUtil;

        debug!("pandoc cmd: %s", pandoc_cmd);
        debug!("pandoc args: %s", str::connect(pandoc_args, ~" "));

        let pipe_in = os::pipe();
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let pid = run::spawn_process(
            pandoc_cmd, pandoc_args, &None, &None,
            pipe_in.in, pipe_out.out, pipe_err.out);

        let writer = io::fd_writer(pipe_in.out, false);
        writer.write_str(markdown);

        os::close(pipe_in.in);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        os::close(pipe_in.out);

        let stdout_po = comm::Port();
        let stdout_ch = comm::Chan(&stdout_po);
        do task::spawn_sched(task::SingleThreaded) {
            comm::send(stdout_ch, readclose(pipe_out.in));
        }
        let stdout = comm::recv(stdout_po);

        let stderr_po = comm::Port();
        let stderr_ch = comm::Chan(&stderr_po);
        do task::spawn_sched(task::SingleThreaded) {
            comm::send(stderr_ch, readclose(pipe_err.in));
        }
        let stderr = comm::recv(stderr_po);

        let status = run::waitpid(pid);
        debug!("pandoc result: %i", status);
        if status != 0 {
            error!("pandoc-out: %s", stdout);
            error!("pandoc-err: %s", stderr);
            fail ~"pandoc failed";
        }
    }
}

fn readclose(fd: libc::c_int) -> ~str {
    // Copied from run::program_output
    let file = os::fdopen(fd);
    let reader = io::FILE_reader(file, false);
    let buf = io::with_bytes_writer(|writer| {
        let mut bytes = [mut 0, ..4096];
        while !reader.eof() {
            let nread = reader.read(bytes, bytes.len());
            writer.write(bytes.view(0, nread));
        }
    });
    os::fclose(file);
    str::from_bytes(buf)
}

fn generic_writer(+process: fn~(markdown: ~str)) -> Writer {
    let ch = do task::spawn_listener
        |move process, po: comm::Port<WriteInstr>| {
        let mut markdown = ~"";
        let mut keep_going = true;
        while keep_going {
            match comm::recv(po) {
              Write(s) => markdown += s,
              Done => keep_going = false
            }
        }
        process(move markdown);
    };

    fn~(+instr: WriteInstr) {
        comm::send(ch, instr);
    }
}

fn make_local_filename(
    config: config::Config,
    page: doc::Page
) -> Path {
    let filename = make_filename(config, page);
    config.output_dir.push_rel(&filename)
}

fn make_filename(
    config: config::Config,
    page: doc::Page
) -> Path {
    let filename = {
        match page {
          doc::CratePage(doc) => {
            if config.output_format == config::PandocHtml &&
                config.output_style == config::DocPerMod {
                ~"index"
            } else {
                assert doc.topmod.name() != ~"";
                doc.topmod.name()
            }
          }
          doc::ItemPage(doc) => {
            str::connect(doc.path() + ~[doc.name()], ~"_")
          }
        }
    };
    let ext = match config.output_format {
      config::Markdown => ~"md",
      config::PandocHtml => ~"html"
    };

    Path(filename).with_filetype(ext)
}

#[test]
fn should_use_markdown_file_name_based_off_crate() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::Markdown,
        output_style: config::DocPerCrate,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"test", ~"");
    let page = doc::CratePage(doc.CrateDoc());
    let filename = make_local_filename(config, page);
    assert filename.to_str() == ~"output/dir/test.md";
}

#[test]
fn should_name_html_crate_file_name_index_html_when_doc_per_mod() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::PandocHtml,
        output_style: config::DocPerMod,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"", ~"");
    let page = doc::CratePage(doc.CrateDoc());
    let filename = make_local_filename(config, page);
    assert filename.to_str() == ~"output/dir/index.html";
}

#[test]
fn should_name_mod_file_names_by_path() {
    let config = {
        output_dir: Path("output/dir"),
        output_format: config::PandocHtml,
        output_style: config::DocPerMod,
        .. config::default_config(&Path("input/test.rc"))
    };
    let doc = test::mk_doc(~"", ~"mod a { mod b { } }");
    let modb = doc.cratemod().mods()[0].mods()[0];
    let page = doc::ItemPage(doc::ModTag(modb));
    let filename = make_local_filename(config, page);
    assert  filename == Path("output/dir/a_b.html");
}

#[cfg(test)]
mod test {
    #[legacy_exports];
    fn mk_doc(name: ~str, source: ~str) -> doc::Doc {
        do astsrv::from_str(source) |srv| {
            let doc = extract::from_srv(srv, name);
            let doc = path_pass::mk_pass().f(srv, doc);
            doc
        }
    }
}

fn write_file(path: &Path, s: ~str) {
    use io::WriterUtil;

    match io::file_writer(path, ~[io::Create, io::Truncate]) {
      result::Ok(writer) => {
        writer.write_str(s);
      }
      result::Err(e) => fail e
    }
}

fn future_writer_factory(
) -> (WriterFactory, comm::Port<(doc::Page, ~str)>) {
    let markdown_po = comm::Port();
    let markdown_ch = comm::Chan(&markdown_po);
    let writer_factory = fn~(page: doc::Page) -> Writer {
        let writer_po = comm::Port();
        let writer_ch = comm::Chan(&writer_po);
        do task::spawn {
            let (writer, future) = future_writer();
            comm::send(writer_ch, move writer);
            let s = future::get(&future);
            comm::send(markdown_ch, (page, s));
        }
        comm::recv(writer_po)
    };

    (move writer_factory, markdown_po)
}

fn future_writer() -> (Writer, future::Future<~str>) {
    let (chan, port) = pipes::stream();
    let writer = fn~(move chan, +instr: WriteInstr) {
        chan.send(copy instr);
    };
    let future = do future::from_fn |move port| {
        let mut res = ~"";
        loop {
            match port.recv() {
              Write(s) => res += s,
              Done => break
            }
        }
        res
    };
    (move writer, move future)
}
<|endoftext|>


<commit_before>//! `core_arch`

#[macro_use]
mod macros;

#[cfg(any(target_arch = "arm", target_arch = "aarch64", doc))]
mod arm_shared;

mod simd;

#[doc = include_str!("core_arch_docs.md")]
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", doc))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", doc))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", doc))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use crate::core_arch::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", doc))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use crate::core_arch::aarch64::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// This module provides intrinsics specific to the WebAssembly
    /// architecture. Here you'll find intrinsics specific to WebAssembly that
    /// aren't otherwise surfaced somewhere in a cross-platform abstraction of
    /// `std`, and you'll also find functions for leveraging WebAssembly
    /// proposals such as [atomics] and [simd].
    ///
    /// Intrinsics in the `wasm32` module are modeled after the WebAssembly
    /// instructions that they represent. Most functions are named after the
    /// instruction they intend to correspond to, and the arguments/results
    /// correspond to the type signature of the instruction itself. Stable
    /// WebAssembly instructions are [documented online][instrdoc].
    ///
    /// [instrdoc]: https://webassembly.github.io/spec/core/valid/instructions.html
    ///
    /// If a proposal is not yet stable in WebAssembly itself then the functions
    /// within this function may be unstable and require the nightly channel of
    /// Rust to use. As the proposal itself stabilizes the intrinsics in this
    /// module should stabilize as well.
    ///
    /// [atomics]: https://github.com/webassembly/threads
    /// [simd]: https://github.com/webassembly/simd
    ///
    /// See the [module documentation](../index.html) for general information
    /// about the `arch` module and platform intrinsics.
    ///
    /// ## Atomics
    ///
    /// The [threads proposal][atomics] for WebAssembly adds a number of
    /// instructions for dealing with multithreaded programs. Most instructions
    /// added in the [atomics] proposal are exposed in Rust through the
    /// `std::sync::atomic` module. Some instructions, however, don't have
    /// direct equivalents in Rust so they're exposed here instead.
    ///
    /// Note that the instructions added in the [atomics] proposal can work in
    /// either a context with a shared wasm memory and without. These intrinsics
    /// are always available in the standard library, but you likely won't be
    /// able to use them too productively unless you recompile the standard
    /// library (and all your code) with `-Ctarget-feature=+atomics`.
    ///
    /// It's also worth pointing out that multi-threaded WebAssembly and its
    /// story in Rust is still in a somewhat "early days" phase as of the time
    /// of this writing. Pieces should mostly work but it generally requires a
    /// good deal of manual setup. At this time it's not as simple as "just call
    /// `std::thread::spawn`", but it will hopefully get there one day!
    ///
    /// ## SIMD
    ///
    /// The [simd proposal][simd] for WebAssembly added a new `v128` type for a
    /// 128-bit SIMD register. It also added a large array of instructions to
    /// operate on the `v128` type to perform data processing. Using SIMD on
    /// wasm is intended to be similar to as you would on `x86_64`, for example.
    /// You'd write a function such as:
    ///
    /// ```rust,ignore
    /// #[cfg(target_arch = "wasm32")]
    /// #[target_feature(enable = "simd128")]
    /// unsafe fn uses_simd() {
    ///     use std::arch::wasm32::*;
    ///     // ...
    /// }
    /// ```
    ///
    /// Unlike `x86_64`, however, WebAssembly does not currently have dynamic
    /// detection at runtime as to whether SIMD is supported (this is one of the
    /// motivators for the [conditional sections][condsections] and [feature
    /// detection] proposals, but that is still pretty early days). This means
    /// that your binary will either have SIMD and can only run on engines
    /// which support SIMD, or it will not have SIMD at all. For compatibility
    /// the standard library itself does not use any SIMD internally.
    /// Determining how best to ship your WebAssembly binary with SIMD is
    /// largely left up to you as it can can be pretty nuanced depending on
    /// your situation.
    ///
    /// [condsections]: https://github.com/webassembly/conditional-sections
    /// [feature detection]: https://github.com/WebAssembly/feature-detection
    ///
    /// To enable SIMD support at compile time you need to do one of two things:
    ///
    /// * First you can annotate functions with `#[target_feature(enable =
    ///   "simd128")]`. This causes just that one function to have SIMD support
    ///   available to it, and intrinsics will get inlined as usual in this
    ///   situation.
    ///
    /// * Second you can compile your program with `-Ctarget-feature=+simd128`.
    ///   This compilation flag blanket enables SIMD support for your entire
    ///   compilation. Note that this does not include the standard library
    ///   unless you [recompile the standard library][buildstd].
    ///
    /// [buildstd]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
    ///
    /// If you enable SIMD via either of these routes then you'll have a
    /// WebAssembly binary that uses SIMD instructions, and you'll need to ship
    /// that accordingly. Also note that if you call SIMD intrinsics but don't
    /// enable SIMD via either of these mechanisms, you'll still have SIMD
    /// generated in your program. This means to generate a binary without SIMD
    /// you'll need to avoid both options above plus calling into any intrinsics
    /// in this module.
    #[cfg(any(target_arch = "wasm32", doc))]
    #[doc(cfg(target_arch = "wasm32"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm32 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `wasm64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm64", doc))]
    #[doc(cfg(target_arch = "wasm64"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm64 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", doc))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", doc))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", doc))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use crate::core_arch::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", doc))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use crate::core_arch::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", doc))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use crate::core_arch::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", doc))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", doc))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", doc))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", doc))]
#[doc(cfg(any(target_arch = "arm")))]
mod arm;

#[cfg(any(target_arch = "wasm32", target_arch = "wasm64", doc))]
#[doc(cfg(any(target_arch = "wasm32", target_arch = "wasm64")))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", doc))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", doc))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", doc))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", doc))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<commit_msg>expose `wasm` intrinsics using `target_family = "wasm"` (#1241)<commit_after>//! `core_arch`

#[macro_use]
mod macros;

#[cfg(any(target_arch = "arm", target_arch = "aarch64", doc))]
mod arm_shared;

mod simd;

#[doc = include_str!("core_arch_docs.md")]
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", doc))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", doc))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use crate::core_arch::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", doc))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use crate::core_arch::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", doc))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use crate::core_arch::aarch64::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// This module provides intrinsics specific to the WebAssembly
    /// architecture. Here you'll find intrinsics specific to WebAssembly that
    /// aren't otherwise surfaced somewhere in a cross-platform abstraction of
    /// `std`, and you'll also find functions for leveraging WebAssembly
    /// proposals such as [atomics] and [simd].
    ///
    /// Intrinsics in the `wasm32` module are modeled after the WebAssembly
    /// instructions that they represent. Most functions are named after the
    /// instruction they intend to correspond to, and the arguments/results
    /// correspond to the type signature of the instruction itself. Stable
    /// WebAssembly instructions are [documented online][instrdoc].
    ///
    /// [instrdoc]: https://webassembly.github.io/spec/core/valid/instructions.html
    ///
    /// If a proposal is not yet stable in WebAssembly itself then the functions
    /// within this function may be unstable and require the nightly channel of
    /// Rust to use. As the proposal itself stabilizes the intrinsics in this
    /// module should stabilize as well.
    ///
    /// [atomics]: https://github.com/webassembly/threads
    /// [simd]: https://github.com/webassembly/simd
    ///
    /// See the [module documentation](../index.html) for general information
    /// about the `arch` module and platform intrinsics.
    ///
    /// ## Atomics
    ///
    /// The [threads proposal][atomics] for WebAssembly adds a number of
    /// instructions for dealing with multithreaded programs. Most instructions
    /// added in the [atomics] proposal are exposed in Rust through the
    /// `std::sync::atomic` module. Some instructions, however, don't have
    /// direct equivalents in Rust so they're exposed here instead.
    ///
    /// Note that the instructions added in the [atomics] proposal can work in
    /// either a context with a shared wasm memory and without. These intrinsics
    /// are always available in the standard library, but you likely won't be
    /// able to use them too productively unless you recompile the standard
    /// library (and all your code) with `-Ctarget-feature=+atomics`.
    ///
    /// It's also worth pointing out that multi-threaded WebAssembly and its
    /// story in Rust is still in a somewhat "early days" phase as of the time
    /// of this writing. Pieces should mostly work but it generally requires a
    /// good deal of manual setup. At this time it's not as simple as "just call
    /// `std::thread::spawn`", but it will hopefully get there one day!
    ///
    /// ## SIMD
    ///
    /// The [simd proposal][simd] for WebAssembly added a new `v128` type for a
    /// 128-bit SIMD register. It also added a large array of instructions to
    /// operate on the `v128` type to perform data processing. Using SIMD on
    /// wasm is intended to be similar to as you would on `x86_64`, for example.
    /// You'd write a function such as:
    ///
    /// ```rust,ignore
    /// #[cfg(target_arch = "wasm32")]
    /// #[target_feature(enable = "simd128")]
    /// unsafe fn uses_simd() {
    ///     use std::arch::wasm32::*;
    ///     // ...
    /// }
    /// ```
    ///
    /// Unlike `x86_64`, however, WebAssembly does not currently have dynamic
    /// detection at runtime as to whether SIMD is supported (this is one of the
    /// motivators for the [conditional sections][condsections] and [feature
    /// detection] proposals, but that is still pretty early days). This means
    /// that your binary will either have SIMD and can only run on engines
    /// which support SIMD, or it will not have SIMD at all. For compatibility
    /// the standard library itself does not use any SIMD internally.
    /// Determining how best to ship your WebAssembly binary with SIMD is
    /// largely left up to you as it can can be pretty nuanced depending on
    /// your situation.
    ///
    /// [condsections]: https://github.com/webassembly/conditional-sections
    /// [feature detection]: https://github.com/WebAssembly/feature-detection
    ///
    /// To enable SIMD support at compile time you need to do one of two things:
    ///
    /// * First you can annotate functions with `#[target_feature(enable =
    ///   "simd128")]`. This causes just that one function to have SIMD support
    ///   available to it, and intrinsics will get inlined as usual in this
    ///   situation.
    ///
    /// * Second you can compile your program with `-Ctarget-feature=+simd128`.
    ///   This compilation flag blanket enables SIMD support for your entire
    ///   compilation. Note that this does not include the standard library
    ///   unless you [recompile the standard library][buildstd].
    ///
    /// [buildstd]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std
    ///
    /// If you enable SIMD via either of these routes then you'll have a
    /// WebAssembly binary that uses SIMD instructions, and you'll need to ship
    /// that accordingly. Also note that if you call SIMD intrinsics but don't
    /// enable SIMD via either of these mechanisms, you'll still have SIMD
    /// generated in your program. This means to generate a binary without SIMD
    /// you'll need to avoid both options above plus calling into any intrinsics
    /// in this module.
    #[cfg(any(target_arch = "wasm32", doc))]
    #[doc(cfg(target_arch = "wasm32"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm32 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `wasm64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "wasm64", doc))]
    #[doc(cfg(target_arch = "wasm64"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm64 {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `wasm` target family.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_family = "wasm", doc))]
    #[doc(cfg(target_family = "wasm"))]
    #[stable(feature = "simd_wasm32", since = "1.33.0")]
    pub mod wasm {
        #[stable(feature = "simd_wasm32", since = "1.33.0")]
        pub use crate::core_arch::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", doc))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", doc))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use crate::core_arch::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", doc))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use crate::core_arch::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", doc))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use crate::core_arch::powerpc64::*;
    }

    /// Platform-specific intrinsics for the `NVPTX` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", doc))]
    #[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod nvptx {
        pub use crate::core_arch::nvptx::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", doc))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", doc))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", doc))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", doc))]
#[doc(cfg(any(target_arch = "arm")))]
mod arm;

#[cfg(any(target_family = "wasm", doc))]
#[doc(cfg(target_family = "wasm"))]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", doc))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", doc))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", doc))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

#[cfg(any(target_arch = "nvptx", target_arch = "nvptx64", doc))]
#[doc(cfg(any(target_arch = "nvptx", target_arch = "nvptx64")))]
mod nvptx;
<|endoftext|>


<commit_before>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(100);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(30);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
    // but for now it's too annoying...
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(&Interner),
        }
    }

    pub(crate) fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: &'a Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses.iter().filter_map(move |(self_ty, trait_id)| {
            if self_ty == ty {
                Some(*trait_id)
            } else {
                None
            }
        })
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(&Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    log::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(&Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    log::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            log::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            let solution = solver.solve_limited(&logging_db.0, goal, &should_continue);
            solution
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        log::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    let solution =
        if is_chalk_debug() { crate::tls::set_current_program(db, solve) } else { solve() };

    solution
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, self.lang_item_name().into())?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<commit_msg>Increase chalk overflow depth<commit_after>//! Trait solving using Chalk.

use std::env::var;

use chalk_ir::GoalData;
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};

use base_db::CrateId;
use hir_def::{lang_item::LangItemTarget, TraitId};
use stdx::panic_context;

use crate::{
    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};

/// This controls how much 'time' we give the Chalk solver before giving up.
const CHALK_SOLVER_FUEL: i32 = 100;

#[derive(Debug, Copy, Clone)]
pub(crate) struct ChalkContext<'a> {
    pub(crate) db: &'a dyn HirDatabase,
    pub(crate) krate: CrateId,
}

fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
    let overflow_depth =
        var("CHALK_OVERFLOW_DEPTH").ok().and_then(|s| s.parse().ok()).unwrap_or(300);
    let max_size = var("CHALK_SOLVER_MAX_SIZE").ok().and_then(|s| s.parse().ok()).unwrap_or(30);
    chalk_recursive::RecursiveSolver::new(overflow_depth, max_size, Some(Cache::new()))
}

/// A set of clauses that we assume to be true. E.g. if we are inside this function:
/// ```rust
/// fn foo<T: Default>(t: T) {}
/// ```
/// we assume that `T: Default`.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TraitEnvironment {
    pub krate: CrateId,
    // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
    // but for now it's too annoying...
    pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
    pub env: chalk_ir::Environment<Interner>,
}

impl TraitEnvironment {
    pub fn empty(krate: CrateId) -> Self {
        TraitEnvironment {
            krate,
            traits_from_clauses: Vec::new(),
            env: chalk_ir::Environment::new(&Interner),
        }
    }

    pub(crate) fn traits_in_scope_from_clauses<'a>(
        &'a self,
        ty: &'a Ty,
    ) -> impl Iterator<Item = TraitId> + 'a {
        self.traits_from_clauses.iter().filter_map(move |(self_ty, trait_id)| {
            if self_ty == ty {
                Some(*trait_id)
            } else {
                None
            }
        })
    }
}

/// Solve a trait goal using Chalk.
pub(crate) fn trait_solve_query(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: Canonical<InEnvironment<Goal>>,
) -> Option<Solution> {
    let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(&Interner) {
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
            db.trait_data(it.hir_trait_id()).name.to_string()
        }
        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
        _ => "??".to_string(),
    });
    log::info!("trait_solve_query({:?})", goal.value.goal);

    if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
        alias: AliasTy::Projection(projection_ty),
        ..
    }))) = &goal.value.goal.data(&Interner)
    {
        if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) {
            // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
            return Some(Solution::Ambig(Guidance::Unknown));
        }
    }

    // We currently don't deal with universes (I think / hope they're not yet
    // relevant for our use cases?)
    let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
    solve(db, krate, &u_canonical)
}

fn solve(
    db: &dyn HirDatabase,
    krate: CrateId,
    goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<Interner>>>,
) -> Option<chalk_solve::Solution<Interner>> {
    let context = ChalkContext { db, krate };
    log::debug!("solve goal: {:?}", goal);
    let mut solver = create_chalk_solver();

    let fuel = std::cell::Cell::new(CHALK_SOLVER_FUEL);

    let should_continue = || {
        db.unwind_if_cancelled();
        let remaining = fuel.get();
        fuel.set(remaining - 1);
        if remaining == 0 {
            log::debug!("fuel exhausted");
        }
        remaining > 0
    };

    let mut solve = || {
        let _ctx = if is_chalk_debug() || is_chalk_print() {
            Some(panic_context::enter(format!("solving {:?}", goal)))
        } else {
            None
        };
        let solution = if is_chalk_print() {
            let logging_db =
                LoggingRustIrDatabaseLoggingOnDrop(LoggingRustIrDatabase::new(context));
            let solution = solver.solve_limited(&logging_db.0, goal, &should_continue);
            solution
        } else {
            solver.solve_limited(&context, goal, &should_continue)
        };

        log::debug!("solve({:?}) => {:?}", goal, solution);

        solution
    };

    // don't set the TLS for Chalk unless Chalk debugging is active, to make
    // extra sure we only use it for debugging
    let solution =
        if is_chalk_debug() { crate::tls::set_current_program(db, solve) } else { solve() };

    solution
}

struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, ChalkContext<'a>>);

impl<'a> Drop for LoggingRustIrDatabaseLoggingOnDrop<'a> {
    fn drop(&mut self) {
        eprintln!("chalk program:\n{}", self.0);
    }
}

fn is_chalk_debug() -> bool {
    std::env::var("CHALK_DEBUG").is_ok()
}

fn is_chalk_print() -> bool {
    std::env::var("CHALK_PRINT").is_ok()
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum FnTrait {
    FnOnce,
    FnMut,
    Fn,
}

impl FnTrait {
    fn lang_item_name(self) -> &'static str {
        match self {
            FnTrait::FnOnce => "fn_once",
            FnTrait::FnMut => "fn_mut",
            FnTrait::Fn => "fn",
        }
    }

    pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> {
        let target = db.lang_item(krate, self.lang_item_name().into())?;
        match target {
            LangItemTarget::TraitId(t) => Some(t),
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    rc::Rc,
};

use stdweb::{
    _js_impl, js,
    traits::*,
    unstable::TryInto,
    web::{document, event, html_element::CanvasElement, window, CanvasRenderingContext2d},
};

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {
    stdweb::initialize();
}

fn get_mouse_button(button: event::MouseButton) -> MouseButton {
    match button {
        event::MouseButton::Wheel => MouseButton::Middle,
        event::MouseButton::Right => MouseButton::Right,
        _ => MouseButton::Left,
    }
}

fn get_key(code: &str, key: String) -> (Key, String) {
    let mut text = String::from("");

    let code = match code {
        "Backspace" => Key::Backspace,
        "Delete" => Key::Delete,
        "ControlLeft" => Key::Control,
        "ShiftLeft" => Key::ShiftL,
        "ShiftRight" => Key::ShiftR,
        "AltLeft" => Key::Alt,
        "ArrowUp" => Key::Up,
        "ArrowLeft" => Key::Left,
        "ArrowRight" => Key::Right,
        "ArrowDown" => Key::Down,
        _ => {
            text = key.clone();
            Key::from(key.chars().next().unwrap())
        }
    };

    (code, text)
}

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    render_context_2_d: RenderContext2D,
    pub mouse_move_events: Rc<RefCell<Vec<event::MouseMoveEvent>>>,
    pub mouse_up_events: Rc<RefCell<Vec<event::MouseUpEvent>>>,
    pub mouse_down_events: Rc<RefCell<Vec<event::MouseDownEvent>>>,
    pub key_up_events: Rc<RefCell<Vec<event::KeyUpEvent>>>,
    pub key_down_events: Rc<RefCell<Vec<event::KeyDownEvent>>>,
    pub resize_events: Rc<RefCell<Vec<event::ResizeEvent>>>,
    canvas: CanvasElement,
    adapter: A,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render context 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        while let Some(event) = self.mouse_move_events.borrow_mut().pop() {
            self.adapter
                .mouse(event.client_x() as f64, event.client_y() as f64);
        }

        while let Some(event) = self.mouse_down_events.borrow_mut().pop() {
            self.adapter.mouse_event(MouseEvent {
                x: event.client_x() as f64,
                y: event.client_y() as f64,
                button: get_mouse_button(event.button()),
                state: ButtonState::Down,
            });
        }

        while let Some(event) = self.mouse_up_events.borrow_mut().pop() {
            self.adapter.mouse_event(MouseEvent {
                x: event.client_x() as f64,
                y: event.client_y() as f64,
                button: get_mouse_button(event.button()),
                state: ButtonState::Up,
            });
        }

        while let Some(event) = self.key_down_events.borrow_mut().pop() {
            let key = get_key(event.code().as_str(), event.key());

            self.adapter.key_event(KeyEvent {
                key: key.0,
                state: ButtonState::Down,
                text: key.1,
            });
        }

        while let Some(event) = self.resize_events.borrow_mut().pop() {
            log("Blub");
            let window_size = (
                window().inner_width() as f64,
                window().inner_height() as f64,
            );
            let device_pixel_ratio = window().device_pixel_ratio();
            let context: CanvasRenderingContext2d = self.canvas.get_context().unwrap();

            let backing_store_ratio = js! {
                var context = @{&context};
                 return context.webkitBackingStorePixelRatio ||
                     context.mozBackingStorePixelRatio ||
                     context.msBackingStorePixelRatio ||
                     context.oBackingStorePixelRatio ||
                     context.backingStorePixelRatio || 1;
            };

            let ratio: f64 = js! {
                return @{&device_pixel_ratio} / @{&backing_store_ratio};
            }
            .try_into()
            .unwrap();

            if device_pixel_ratio != backing_store_ratio {
                self.canvas.set_width((window_size.0 * ratio) as u32);
                self.canvas.set_height((window_size.1 * ratio) as u32);

                js! {
                    @{&self.canvas}.style.width = @{&window_size.0} + "px";
                    @{&self.canvas}.style.height = @{&window_size.1} + "px";
                }

                context.scale(ratio, ratio);
            }
            // self.render_context_2_d.resize(window_size.0, window_size.1);
            self.adapter.resize(window_size.0, window_size.1);
        }
    }
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter + 'static,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(mut self) {
        window().request_animation_frame(move |_| {
            self.updater.update();
            self.update.set(false);
            self.window_shell.borrow_mut().drain_events();
            self.run();
        });
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rect,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rect::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rect>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(mut self) -> WindowShell {
        let canvas: CanvasElement = document()
            .create_element("canvas")
            .unwrap()
            .try_into()
            .unwrap();

        let window_size = (
            window().inner_width() as f64,
            window().inner_height() as f64,
        );

        canvas.set_width(window_size.0 as u32);
        canvas.set_height(window_size.1 as u32);

        let adapter = &mut self.adapter;
        adapter.resize(window_size.0, window_size.1);

        js! {
            document.body.style.padding = 0;
            document.body.style.margin = 0;
            @{&canvas}.style.display = "block";
            @{&canvas}.style.margin = "0";
        }

        // web event queues
        let mouse_move = Rc::new(RefCell::new(vec![]));
        let mouse_up = Rc::new(RefCell::new(vec![]));
        let mouse_down = Rc::new(RefCell::new(vec![]));
        let key_down = Rc::new(RefCell::new(vec![]));
        let key_up = Rc::new(RefCell::new(vec![]));
        let resize = Rc::new(RefCell::new(vec![]));

        let mouse_down_c = mouse_down.clone();
        canvas.add_event_listener(move |e: event::MouseDownEvent| {
            mouse_down_c.borrow_mut().push(e);
        });

        let mouse_up_c = mouse_up.clone();
        canvas.add_event_listener(move |e: event::MouseUpEvent| {
            mouse_up_c.borrow_mut().push(e);
        });

        let mouse_move_c = mouse_move.clone();
        canvas.add_event_listener(move |e: event::MouseMoveEvent| {
            mouse_move_c.borrow_mut().push(e);
        });

        let key_down_c = key_down.clone();
        document().add_event_listener(move |e: event::KeyDownEvent| {
            e.prevent_default();
            key_down_c.borrow_mut().push(e);
        });

        let key_up_c = key_up.clone();
        document().add_event_listener(move |e: event::KeyUpEvent| {
            e.prevent_default();
            key_up_c.borrow_mut().push(e);
        });

        let resize_c = resize.clone();
        document().add_event_listener(move |e: event::ResizeEvent| {
             e.prevent_default();
            resize_c.borrow_mut().push(e);
        });

        document().body().unwrap().append_child(&canvas);
        let context: CanvasRenderingContext2d = canvas.get_context().unwrap();

        let device_pixel_ratio = window().device_pixel_ratio();

        let backing_store_ratio = js! {
            var context = @{&context};
             return context.webkitBackingStorePixelRatio ||
                 context.mozBackingStorePixelRatio ||
                 context.msBackingStorePixelRatio ||
                 context.oBackingStorePixelRatio ||
                 context.backingStorePixelRatio || 1;
        };

        let ratio: f64 = js! {
            return @{&device_pixel_ratio} / @{&backing_store_ratio};
        }
        .try_into()
        .unwrap();

        if device_pixel_ratio != backing_store_ratio {
            let old_width = canvas.width();
            let old_height = canvas.height();
            canvas.set_width((old_width as f64 * ratio) as u32);
            canvas.set_height((old_height as f64 * ratio) as u32);

            js! {
                @{&canvas}.style.width = @{&old_width} + "px";
                @{&canvas}.style.height = @{&old_height} + "px";
            }

            context.scale(ratio, ratio);
        }

        let render_context_2_d = RenderContext2D::new(canvas.get_context().unwrap());

        document().set_title(&self.title[..]);

        stdweb::event_loop();

        WindowShell {
            render_context_2_d,
            adapter: self.adapter,
            mouse_move_events: mouse_move,
            mouse_up_events: mouse_up,
            mouse_down_events: mouse_down,
            key_down_events: key_down,
            key_up_events: key_up,
            resize_events: resize,
            canvas,
        }
    }
}

pub fn log(message: String) {
    js! {
        console.log(@{&message});
    }
}
<commit_msg>CI fix.<commit_after>//! This module contains a platform specific implementation of the window shell.

use std::{
    cell::{Cell, RefCell},
    rc::Rc,
};

use stdweb::{
    _js_impl, js,
    traits::*,
    unstable::TryInto,
    web::{document, event, html_element::CanvasElement, window, CanvasRenderingContext2d},
};

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {
    stdweb::initialize();
}

fn get_mouse_button(button: event::MouseButton) -> MouseButton {
    match button {
        event::MouseButton::Wheel => MouseButton::Middle,
        event::MouseButton::Right => MouseButton::Right,
        _ => MouseButton::Left,
    }
}

fn get_key(code: &str, key: String) -> (Key, String) {
    let mut text = String::from("");

    let code = match code {
        "Backspace" => Key::Backspace,
        "Delete" => Key::Delete,
        "ControlLeft" => Key::Control,
        "ShiftLeft" => Key::ShiftL,
        "ShiftRight" => Key::ShiftR,
        "AltLeft" => Key::Alt,
        "ArrowUp" => Key::Up,
        "ArrowLeft" => Key::Left,
        "ArrowRight" => Key::Right,
        "ArrowDown" => Key::Down,
        _ => {
            text = key.clone();
            Key::from(key.chars().next().unwrap())
        }
    };

    (code, text)
}

/// Concrete implementation of the window shell.
pub struct WindowShell
where
    A: WindowAdapter,
{
    render_context_2_d: RenderContext2D,
    pub mouse_move_events: Rc<RefCell<Vec<event::MouseMoveEvent>>>,
    pub mouse_up_events: Rc<RefCell<Vec<event::MouseUpEvent>>>,
    pub mouse_down_events: Rc<RefCell<Vec<event::MouseDownEvent>>>,
    pub key_up_events: Rc<RefCell<Vec<event::KeyUpEvent>>>,
    pub key_down_events: Rc<RefCell<Vec<event::KeyDownEvent>>>,
    pub resize_events: Rc<RefCell<Vec<event::ResizeEvent>>>,
    canvas: CanvasElement,
    adapter: A,
}

impl WindowShell
where
    A: WindowAdapter,
{
    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render context 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self) {
        while let Some(event) = self.mouse_move_events.borrow_mut().pop() {
            self.adapter
                .mouse(event.client_x() as f64, event.client_y() as f64);
        }

        while let Some(event) = self.mouse_down_events.borrow_mut().pop() {
            self.adapter.mouse_event(MouseEvent {
                x: event.client_x() as f64,
                y: event.client_y() as f64,
                button: get_mouse_button(event.button()),
                state: ButtonState::Down,
            });
        }

        while let Some(event) = self.mouse_up_events.borrow_mut().pop() {
            self.adapter.mouse_event(MouseEvent {
                x: event.client_x() as f64,
                y: event.client_y() as f64,
                button: get_mouse_button(event.button()),
                state: ButtonState::Up,
            });
        }

        while let Some(event) = self.key_down_events.borrow_mut().pop() {
            let key = get_key(event.code().as_str(), event.key());

            self.adapter.key_event(KeyEvent {
                key: key.0,
                state: ButtonState::Down,
                text: key.1,
            });
        }

        while let Some(event) = self.resize_events.borrow_mut().pop() {
            let window_size = (
                window().inner_width() as f64,
                window().inner_height() as f64,
            );
            let device_pixel_ratio = window().device_pixel_ratio();
            let context: CanvasRenderingContext2d = self.canvas.get_context().unwrap();

            let backing_store_ratio = js! {
                var context = @{&context};
                 return context.webkitBackingStorePixelRatio ||
                     context.mozBackingStorePixelRatio ||
                     context.msBackingStorePixelRatio ||
                     context.oBackingStorePixelRatio ||
                     context.backingStorePixelRatio || 1;
            };

            let ratio: f64 = js! {
                return @{&device_pixel_ratio} / @{&backing_store_ratio};
            }
            .try_into()
            .unwrap();

            if device_pixel_ratio != backing_store_ratio {
                self.canvas.set_width((window_size.0 * ratio) as u32);
                self.canvas.set_height((window_size.1 * ratio) as u32);

                js! {
                    @{&self.canvas}.style.width = @{&window_size.0} + "px";
                    @{&self.canvas}.style.height = @{&window_size.1} + "px";
                }

                context.scale(ratio, ratio);
            }
            // self.render_context_2_d.resize(window_size.0, window_size.1);
            self.adapter.resize(window_size.0, window_size.1);
        }
    }
}

/// Implementation of the OrbClient based shell runner.
pub struct ShellRunner
where
    A: WindowAdapter + 'static,
{
    pub window_shell: Rc<RefCell<WindowShell>>,
    pub update: Rc<Cell<bool>>,
    pub running: Rc<Cell<bool>>,
    pub updater: Box<dyn Updater>,
}

impl ShellRunner
where
    A: WindowAdapter,
{
    pub fn run(mut self) {
        window().request_animation_frame(move |_| {
            self.updater.update();
            self.update.set(false);
            self.window_shell.borrow_mut().drain_events();
            self.run();
        });
    }
}

/// Constructs the window shell
pub struct WindowBuilder
where
    A: WindowAdapter,
{
    title: String,

    resizeable: bool,

    bounds: Rect,

    adapter: A,
}

impl WindowBuilder
where
    A: WindowAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        WindowBuilder {
            adapter,
            title: String::default(),
            resizeable: false,
            bounds: Rect::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rect>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(mut self) -> WindowShell {
        let canvas: CanvasElement = document()
            .create_element("canvas")
            .unwrap()
            .try_into()
            .unwrap();

        let window_size = (
            window().inner_width() as f64,
            window().inner_height() as f64,
        );

        canvas.set_width(window_size.0 as u32);
        canvas.set_height(window_size.1 as u32);

        let adapter = &mut self.adapter;
        adapter.resize(window_size.0, window_size.1);

        js! {
            document.body.style.padding = 0;
            document.body.style.margin = 0;
            @{&canvas}.style.display = "block";
            @{&canvas}.style.margin = "0";
        }

        // web event queues
        let mouse_move = Rc::new(RefCell::new(vec![]));
        let mouse_up = Rc::new(RefCell::new(vec![]));
        let mouse_down = Rc::new(RefCell::new(vec![]));
        let key_down = Rc::new(RefCell::new(vec![]));
        let key_up = Rc::new(RefCell::new(vec![]));
        let resize = Rc::new(RefCell::new(vec![]));

        let mouse_down_c = mouse_down.clone();
        canvas.add_event_listener(move |e: event::MouseDownEvent| {
            mouse_down_c.borrow_mut().push(e);
        });

        let mouse_up_c = mouse_up.clone();
        canvas.add_event_listener(move |e: event::MouseUpEvent| {
            mouse_up_c.borrow_mut().push(e);
        });

        let mouse_move_c = mouse_move.clone();
        canvas.add_event_listener(move |e: event::MouseMoveEvent| {
            mouse_move_c.borrow_mut().push(e);
        });

        let key_down_c = key_down.clone();
        document().add_event_listener(move |e: event::KeyDownEvent| {
            e.prevent_default();
            key_down_c.borrow_mut().push(e);
        });

        let key_up_c = key_up.clone();
        document().add_event_listener(move |e: event::KeyUpEvent| {
            e.prevent_default();
            key_up_c.borrow_mut().push(e);
        });

        let resize_c = resize.clone();
        document().add_event_listener(move |e: event::ResizeEvent| {
             e.prevent_default();
            resize_c.borrow_mut().push(e);
        });

        document().body().unwrap().append_child(&canvas);
        let context: CanvasRenderingContext2d = canvas.get_context().unwrap();

        let device_pixel_ratio = window().device_pixel_ratio();

        let backing_store_ratio = js! {
            var context = @{&context};
             return context.webkitBackingStorePixelRatio ||
                 context.mozBackingStorePixelRatio ||
                 context.msBackingStorePixelRatio ||
                 context.oBackingStorePixelRatio ||
                 context.backingStorePixelRatio || 1;
        };

        let ratio: f64 = js! {
            return @{&device_pixel_ratio} / @{&backing_store_ratio};
        }
        .try_into()
        .unwrap();

        if device_pixel_ratio != backing_store_ratio {
            let old_width = canvas.width();
            let old_height = canvas.height();
            canvas.set_width((old_width as f64 * ratio) as u32);
            canvas.set_height((old_height as f64 * ratio) as u32);

            js! {
                @{&canvas}.style.width = @{&old_width} + "px";
                @{&canvas}.style.height = @{&old_height} + "px";
            }

            context.scale(ratio, ratio);
        }

        let render_context_2_d = RenderContext2D::new(canvas.get_context().unwrap());

        document().set_title(&self.title[..]);

        stdweb::event_loop();

        WindowShell {
            render_context_2_d,
            adapter: self.adapter,
            mouse_move_events: mouse_move,
            mouse_up_events: mouse_up,
            mouse_down_events: mouse_down,
            key_down_events: key_down,
            key_up_events: key_up,
            resize_events: resize,
            canvas,
        }
    }
}

pub fn log(message: String) {
    js! {
        console.log(@{&message});
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub struct MessageBuilder {
    nextSize : uint,
    allocationStrategy : AllocationStrategy,
    segmentBuilders : ~[@mut SegmentBuilder],

    segments : ~[~[u8]]
    // It would probably be nicer if this were a vector of @mut[u8]s
    // and the SegmentBuilders also directly their respective
    // @mut[u8]s. Only problem is, I don't know how to implement
    // `asReader` in that case.
}

impl MessageBuilder {

    pub fn new(firstSegmentWords : uint, allocationStrategy : AllocationStrategy)
        -> @mut MessageBuilder {
        let result = @mut MessageBuilder {
            nextSize : firstSegmentWords,
            allocationStrategy : allocationStrategy,
            segmentBuilders : ~[],
            segments : ~[]
        };

        let builder =
            @mut SegmentBuilder::new(result, firstSegmentWords);

        result.segments.push(std::vec::from_elem(firstSegmentWords * BYTES_PER_WORD, 0u8));
        result.segmentBuilders.push(builder);

        result
    }

    pub fn new_default() -> @mut MessageBuilder {
        MessageBuilder::new(SUGGESTED_FIRST_SEGMENT_WORDS, SUGGESTED_ALLOCATION_STRATEGY)
    }

    pub fn allocateSegment(@mut self, minimumSize : WordCount) -> @mut SegmentBuilder {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let segment : ~[u8] = std::vec::from_elem(size * BYTES_PER_WORD, 0u8);
        let result  = @mut SegmentBuilder::new(self, size);
        self.segments.push(segment);
        self.segmentBuilders.push(result);

        match self.allocationStrategy {
            GROW_HEURISTICALLY => { self.nextSize += size; }
            _ => { }
        }

        result
    }

    pub fn getSegmentWithAvailable(@mut self, minimumAvailable : WordCount)
        -> @mut SegmentBuilder {
        if (self.segmentBuilders.last().available() >= minimumAvailable) {
            return self.segmentBuilders[self.segments.len() - 1];
        } else {
            return self.allocateSegment(minimumAvailable);
        }
    }

    pub fn initRoot<T : layout::HasStructSize + layout::FromStructBuilder>(@ mut self) -> T {

        // Rolled in this stuff form getRootSegment.
        let rootSegment = self.segmentBuilders[0];

        match rootSegment.allocate(WORDS_PER_POINTER) {
            None => {fail!("could not allocate root pointer") }
            Some(location) => {
                assert!(location == 0,
                        "First allocated word of new segment was not at offset 0");

                let sb = layout::StructBuilder::initRoot(rootSegment, location,
                                                         layout::HasStructSize::structSize::<T>());
                return layout::FromStructBuilder::fromStructBuilder(sb);
            }
        }

    }

    pub fn asReader<T>(& self, f : &fn(r : MessageReader) -> T) -> T {
        let mut segments : ~[&[u8]] = ~[];

        for ii in range(0, self.segments.len()) {
            segments.push(self.segments[ii].as_slice());
        }

        f(MessageReader {segments : segments, options : DEFAULT_READER_OPTIONS})
    }

    // break the reference cycle
    pub fn release(&mut self) {
        self.segmentBuilders.clear()
    }

}
<commit_msg>fix typo<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;
use common::*;
use arena::*;
use layout;

pub struct ReaderOptions {
    traversalLimitInWords : u64,
    nestingLimit : uint
}

pub static DEFAULT_READER_OPTIONS : ReaderOptions =
    ReaderOptions { traversalLimitInWords : 8 * 1024 * 1024, nestingLimit : 64 };

pub struct MessageReader<'self> {
    segments : &'self [ &'self [u8]],
    options : ReaderOptions,
//    arena : ReaderArena<'self>
}

type SegmentId = u32;

impl <'self> MessageReader<'self> {

    #[inline]
    pub fn getSegment(&self, id : uint) -> &'self [u8] {
        self.segments[id]
    }

    #[inline]
    pub fn getSegmentReader<'a>(&'a self, id : SegmentId) -> SegmentReader<'a> {
        SegmentReader { messageReader : self, segment : self.getSegment(id as uint) }
    }

    #[inline]
    pub fn getOptions<'a>(&'a self) -> &'a ReaderOptions {
        return &self.options;
    }

    pub fn getRoot<'a>(&'a self) -> layout::StructReader<'a> {
        let segment = self.getSegmentReader(0);

        return layout::StructReader::readRoot(0, segment,
                                              self.options.nestingLimit as int);
    }

}

pub enum AllocationStrategy {
    FIXED_SIZE,
    GROW_HEURISTICALLY
}

pub static SUGGESTED_FIRST_SEGMENT_WORDS : uint = 1024;
pub static SUGGESTED_ALLOCATION_STRATEGY : AllocationStrategy = GROW_HEURISTICALLY;

pub struct MessageBuilder {
    nextSize : uint,
    allocationStrategy : AllocationStrategy,
    segmentBuilders : ~[@mut SegmentBuilder],

    segments : ~[~[u8]]
    // It would probably be nicer if this were a vector of @mut[u8]s
    // and the SegmentBuilders also directly held their respective
    // @mut[u8]s. Only problem is, I don't know how to implement
    // `asReader` in that case.
}

impl MessageBuilder {

    pub fn new(firstSegmentWords : uint, allocationStrategy : AllocationStrategy)
        -> @mut MessageBuilder {
        let result = @mut MessageBuilder {
            nextSize : firstSegmentWords,
            allocationStrategy : allocationStrategy,
            segmentBuilders : ~[],
            segments : ~[]
        };

        let builder =
            @mut SegmentBuilder::new(result, firstSegmentWords);

        result.segments.push(std::vec::from_elem(firstSegmentWords * BYTES_PER_WORD, 0u8));
        result.segmentBuilders.push(builder);

        result
    }

    pub fn new_default() -> @mut MessageBuilder {
        MessageBuilder::new(SUGGESTED_FIRST_SEGMENT_WORDS, SUGGESTED_ALLOCATION_STRATEGY)
    }

    pub fn allocateSegment(@mut self, minimumSize : WordCount) -> @mut SegmentBuilder {
        let size = std::cmp::max(minimumSize, self.nextSize);
        let segment : ~[u8] = std::vec::from_elem(size * BYTES_PER_WORD, 0u8);
        let result  = @mut SegmentBuilder::new(self, size);
        self.segments.push(segment);
        self.segmentBuilders.push(result);

        match self.allocationStrategy {
            GROW_HEURISTICALLY => { self.nextSize += size; }
            _ => { }
        }

        result
    }

    pub fn getSegmentWithAvailable(@mut self, minimumAvailable : WordCount)
        -> @mut SegmentBuilder {
        if (self.segmentBuilders.last().available() >= minimumAvailable) {
            return self.segmentBuilders[self.segments.len() - 1];
        } else {
            return self.allocateSegment(minimumAvailable);
        }
    }

    pub fn initRoot<T : layout::HasStructSize + layout::FromStructBuilder>(@ mut self) -> T {

        // Rolled in this stuff form getRootSegment.
        let rootSegment = self.segmentBuilders[0];

        match rootSegment.allocate(WORDS_PER_POINTER) {
            None => {fail!("could not allocate root pointer") }
            Some(location) => {
                assert!(location == 0,
                        "First allocated word of new segment was not at offset 0");

                let sb = layout::StructBuilder::initRoot(rootSegment, location,
                                                         layout::HasStructSize::structSize::<T>());
                return layout::FromStructBuilder::fromStructBuilder(sb);
            }
        }

    }

    pub fn asReader<T>(& self, f : &fn(r : MessageReader) -> T) -> T {
        let mut segments : ~[&[u8]] = ~[];

        for ii in range(0, self.segments.len()) {
            segments.push(self.segments[ii].as_slice());
        }

        f(MessageReader {segments : segments, options : DEFAULT_READER_OPTIONS})
    }

    // break the reference cycle
    pub fn release(&mut self) {
        self.segmentBuilders.clear()
    }

}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/100_doors
fn main() {
	for i in std::iter::range_inclusive(1,100) {
		let x = (i as f64).powf(&0.5);
		let state = if x == x.round() {"open"} else {"closed"};
		println!("Door {} is {}", i, state);
	}
}
<commit_msg>Update 100_doors.rs<commit_after>// Implements http://rosettacode.org/wiki/100_doors
#![cfg(not_tested)]
fn main() {
	for i in std::iter::range_inclusive(1,100) {
		let x = (i as f64).powf(&0.5);
		let state = if x == x.round() {"open"} else {"closed"};
		println!("Door {} is {}", i, state);
	}
}
<|endoftext|>