<commit_before>extern crate git2;

use git2::*;
use std::process::Command;
use std::path::Path;
use std::path::PathBuf;

const TMP_NAME: &'static str = "tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

pub trait RepoHost
{
    fn remote_url(&self, &str) -> String;
    fn create_project(&self, &str) -> String;
    fn fetch_url(&self, module: &str) -> String { self.remote_url(module) }
}

pub struct Scratch<'a>
{
    repo: Repository,
    host: &'a RepoHost,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        self.host.create_project(&module);

        let remote_name = format!("{}", module);
        let fetch_url = self.host.fetch_url(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
                     &remote_name,
                     &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        remote.fetch(&[&rs],None,None).expect("fetch failed");
        return self.repo
            .revparse_single(&format!("remotes/{}/{}", module, branch)).ok();
    }

    fn call_git(self: &Scratch<'a>, cmd: &str) -> Result<String, Error>
    {
        let args: Vec<&str> = cmd.split(" ").collect();
        let repo_path = &self.repo.path();
        let mut c = Command::new("git");
        c.env("GIT_DIR", repo_path.as_os_str());
        c.args(&args);

        let output = c.output()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
        Ok(String::from_utf8(output.stderr).expect("cannot decode utf8"))
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        // create tmp branch
        shell.command(&format!("git branch -f {} {}", TMP_NAME, rev));
        // force push
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));
        // delete tmp branch
        shell.command(&format!("git branch -D {}", TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Result<Oid, Error>
    {
        if parents.len() != 0 {
            try!(self.repo.set_head_detached(parents[0].id()));
        }
        self.repo.commit(Some("HEAD"),
                         &base.author(),
                         &base.committer(),
                         &base.message().unwrap_or("no message"),
                         tree,
                         parents)
    }

    fn push(&self, oid: Oid, module: &str, target: &str)
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        debug!("{}",
            self.call_git(&format!("push {} HEAD:{}",
                          self.host.remote_url(module),
                          target)).expect("can't push")
        );
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn module_to_subfolder(&self,
                           module_path: &Path,
                           module_tree: &Tree,
                           master_tree: &Tree)
        -> Result<Oid, Error>
    {
        assert!(module_path.components().count() == 2); // FIXME: drop this requirement
        let parent_path = module_path.parent().expect("module not in subdir");
        let module_name = module_path.file_name().expect("no module name");

        let modules_tree = {
            let mut builder = try!(self.repo
                .treebuilder(Some(&self.subtree(master_tree, parent_path)
                    .unwrap())));
            try!(builder.insert(module_name, module_tree.id(), 0o0040000)); // GIT_FILEMODE_TREE
            try!(builder.write())
        };

        let full_tree = {
            let mut builder = try!(self.repo.treebuilder(Some(master_tree)));
            try!(builder.insert(parent_path, modules_tree, 0o0040000)); // GIT_FILEMODE_TREE
            try!(builder.write())
        };
        Ok(full_tree)
    }

    fn module_paths(&self, object: &Object) -> Vec<String>
    {
        let mut names = Vec::<String>::new();
        let commit = object.as_commit().expect("module_paths: object is not a commit");
        let tree: Tree = commit.tree().expect("module_paths: commit has no tree");

        if let Ok(tree_object) = tree.get_path(&Path::new("modules")) {
            let modules_o = tree_object.to_object(&self.repo).expect("module_paths: to_object");
            if let Some(modules) = modules_o.as_tree() {

                for module in modules.iter() {
                    names.push(format!("modules/{}",
                                       module.name().expect("module_paths: TreeItem has no name"))
                        .to_string());
                }
            }
        }
        return names;
    }

    fn split_subdir(&self, module: &str, newrev: &Oid) -> Object
    {
        // TODO: implement using libgit
        let shell = Shell { cwd: self.repo.path().to_path_buf() };
        shell.command("rm -Rf refs/original");

        self.call_git(&format!("branch -f initial_{} {}", module, newrev))
            .expect("create branch");

        self.call_git(&format!("filter-branch -f --subdirectory-filter {}/ -- initial_{}",
                               module,
                               module))
            .expect("error in filter-branch");

        return self.repo
            .revparse_single(&format!("initial_{}", module))
            .expect("can't find rewritten branch");
    }
}

pub fn module_review_upload(scratch: &Scratch,
                            newrev: Object,
                            module: &str,
                            central: &str)
    -> Result<(), Error>
{
    debug!(".\n\n==== Doing review upload for module {}", &module);

    let new = newrev.id();
    let old = scratch.tracking(&module, "master").expect("no tracking branch 1").id();

    if !try!(scratch.repo.graph_descendant_of(new, old)) {
        debug!(".");
        debug!("==============================================================================");
        debug!("================ Commit not based on master, rebase first! ===================");
        debug!("==============================================================================");
        return Ok(());
    }

    let walk = {
        let mut walk = try!(scratch.repo.revwalk());
        walk.set_sorting(SORT_REVERSE | SORT_TIME);
        try!(walk.push_range(&format!("{}..{}", old, new)));
        walk
    };

    debug!("==== Rewriting commits from {} to {}", old, new);

    let mut current_oid = scratch.tracking(central, "master").expect("no central tracking").id();
    for rev in walk {
        let currev = format!("{}", try!(rev));
        let oldrev = format!("{}", old);
        if oldrev == currev {
            continue;
        }
        debug!("==== Rewriting commit {}", currev);

        let module_commit_obj = try!(scratch.repo.revparse_single(&currev));
        let module_commit = try!(module_commit_obj.as_commit()
            .ok_or(Error::from_str("object is not actually a commit")));
        let module_tree = try!(module_commit.tree());

        let parent_commit = try!(scratch.repo.find_commit(current_oid));

        let new_tree = {
            let master_tree: Tree = try!(parent_commit.tree());
            let new_tree_oid =
                try!(scratch.module_to_subfolder(Path::new(module), &module_tree, &master_tree));
            try!(scratch.repo.find_tree(new_tree_oid))
        };

        current_oid = try!(scratch.rewrite(module_commit, &vec![&parent_commit], &new_tree));
    }

    debug!("");
    debug!("");
    debug!("====================== Doing actual upload in central git ========================");

    scratch.push(current_oid, central, "refs/for/master");

    debug!("==== The review upload may have worked, even if it says error below. Look UP! ====");
    Ok(())
}

pub fn central_submit(scratch: &Scratch, newrev: Object) -> Result<(), Error>
{
    debug!(" ---> central_submit (sha1 of commit: {})", &newrev.id());

    let central_commit = try!(newrev.as_commit()
        .ok_or(Error::from_str("could not get commit from obj")));
    let central_tree = try!(central_commit.tree());

    for module in scratch.module_paths(&newrev) {
        debug!("");
        debug!("==== fetching tracking branch for module: {}", &module);
        let module_master_commit_obj = match scratch.tracking(&module, "master") {
            Some(obj) => obj,
            None => {
                error!("====    no tracking branch for module {} => project does not exist or is empty", &module);
                error!("====    initializing with subdir history");
                let commit = scratch.split_subdir(&module, &newrev.id());
                scratch.host.create_project(&module);
                scratch.push(commit.id(), &module, "refs/heads/master");
                scratch.tracking(&module, "master").expect("no tracking branch 3")
            }
        };

        let parents = vec![module_master_commit_obj.as_commit()
            .expect("could not get commit from obj")];

        debug!("==== checking for changes in module: {:?}", module);

        // new tree is sub-tree of complete central tree
        let old_tree = try!(parents[0].tree());
        let new_tree = try!(scratch.repo
            .find_tree(try!(central_tree.get_path(&Path::new(&module))).id()));

        // if sha1's are equal the content is equal
        if new_tree.id() != old_tree.id() {
            debug!("====    commit changes module => make commit on module");
            let module_commit = try!(scratch.rewrite(central_commit, &parents, &new_tree));
            scratch.push(module_commit, &module, "master");
        }
        else {
            debug!("====    commit does not change module => skipping");
        }
    }
    Ok(())
}

pub struct Shell
{
    pub cwd: PathBuf,
}

impl Shell
{
    pub fn command(&self, cmd: &str) -> String
    {
        let output = Command::new("sh")
            .current_dir(&self.cwd)
            .arg("-c")
            .arg(&cmd)
            .output().unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        return String::from_utf8(output.stdout).expect("failed to decode utf8").trim().to_string();
    }
}
<commit_msg>output was treated differently in debug and println<commit_after>extern crate git2;

use git2::*;
use std::process::Command;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use std::thread;

const TMP_NAME: &'static str = "tmp_fd2db5f8_bac2_4a1e_9487_4ac3414788aa";

pub trait RepoHost
{
    fn remote_url(&self, &str) -> String;
    fn create_project(&self, &str) -> String;
    fn fetch_url(&self, module: &str) -> String { self.remote_url(module) }
}

pub struct Scratch<'a>
{
    repo: Repository,
    host: &'a RepoHost,
}

impl<'a> Scratch<'a>
{
    pub fn new(path: &Path, host: &'a RepoHost) -> Scratch<'a>
    {
        Scratch {
            repo: Repository::init_bare(&path).expect("could not init scratch"),
            host: host,
        }
    }

    fn tracking(&self, module: &str, branch: &str) -> Option<Object>
    {
        self.host.create_project(&module);

        let remote_name = format!("{}", module);
        let fetch_url = self.host.fetch_url(&module);
        let mut remote = if let Ok(remote) = self.repo.find_remote(&remote_name) {
            remote
        }
        else {
            debug!("==== create remote (remote_name:{}, remote_url:{})",
            &remote_name,
            &fetch_url);
            self.repo.remote(&remote_name, &fetch_url).expect("can't create remote")
        };

        let rs = remote.get_refspec(0).unwrap().str().unwrap().to_string();
        remote.fetch(&[&rs],None,None).expect("fetch failed");
        return self.repo
            .revparse_single(&format!("remotes/{}/{}", module, branch)).ok();
    }

    fn call_git(self: &Scratch<'a>, cmd: &str) -> Result<String, Error>
    {
        let args: Vec<&str> = cmd.split(" ").collect();
        let repo_path = &self.repo.path();
        let mut c = Command::new("git");
        c.env("GIT_DIR", repo_path.as_os_str());
        c.args(&args);

        let output = c.output()
            .unwrap_or_else(|e| panic!("failed to execute process: {}", e));
        Ok(String::from_utf8(output.stderr).expect("cannot decode utf8"))
    }

    // force push of the new revision-object to temp repo
    pub fn transfer(&self, rev: &str, source: &Path) -> Object
    {
        // TODO: implement using libgit
        let target = &self.repo.path();
        let shell = Shell { cwd: source.to_path_buf() };
        // create tmp branch
        shell.command(&format!("git branch -f {} {}", TMP_NAME, rev));
        // force push
        shell.command(&format!("git push --force {} {}",
                               &target.to_string_lossy(),
                               TMP_NAME));
        // delete tmp branch
        shell.command(&format!("git branch -D {}", TMP_NAME));

        let obj = self.repo.revparse_single(rev).expect("can't find transfered ref");
        return obj;
    }

    // takes everything from base except it's tree and replaces it with the tree
    // given
    fn rewrite(&self, base: &Commit, parents: &[&Commit], tree: &Tree) -> Result<Oid, Error>
    {
        if parents.len() != 0 {
            try!(self.repo.set_head_detached(parents[0].id()));
        }
        self.repo.commit(Some("HEAD"),
        &base.author(),
        &base.committer(),
        &base.message().unwrap_or("no message"),
        tree,
        parents)
    }

    fn push(&self, oid: Oid, module: &str, target: &str)
    {
        let commit = &self.repo.find_commit(oid).expect("can't find commit");
        self.repo.set_head_detached(commit.id()).expect("can't detach HEAD");
        let output = self.call_git(&format!("push {} HEAD:{}",
                                      self.host.remote_url(module),
                                      target)).expect("can't push");
        debug!("{}", output);
    }

    fn subtree(&self, tree: &Tree, path: &Path) -> Option<Tree>
    {
        if let Some(oid) = tree.get_path(path).map(|x| x.id()).ok() {
            return self.repo.find_tree(oid).ok();
        }
        else {
            return None;
        }
    }

    fn module_to_subfolder(&self,
                           module_path: &Path,
                           module_tree: &Tree,
                           master_tree: &Tree)
        -> Result<Oid, Error>
        {
            assert!(module_path.components().count() == 2); // FIXME: drop this requirement
            let parent_path = module_path.parent().expect("module not in subdir");
            let module_name = module_path.file_name().expect("no module name");

            let modules_tree = {
                let mut builder = try!(self.repo
                                       .treebuilder(Some(&self.subtree(master_tree, parent_path)
                                                         .unwrap())));
                try!(builder.insert(module_name, module_tree.id(), 0o0040000)); // GIT_FILEMODE_TREE
                try!(builder.write())
            };

            let full_tree = {
                let mut builder = try!(self.repo.treebuilder(Some(master_tree)));
                try!(builder.insert(parent_path, modules_tree, 0o0040000)); // GIT_FILEMODE_TREE
                try!(builder.write())
            };
            Ok(full_tree)
        }

    fn module_paths(&self, object: &Object) -> Vec<String>
    {
        let mut names = Vec::<String>::new();
        let commit = object.as_commit().expect("module_paths: object is not a commit");
        let tree: Tree = commit.tree().expect("module_paths: commit has no tree");

        if let Ok(tree_object) = tree.get_path(&Path::new("modules")) {
            let modules_o = tree_object.to_object(&self.repo).expect("module_paths: to_object");
            if let Some(modules) = modules_o.as_tree() {

                for module in modules.iter() {
                    names.push(format!("modules/{}",
                                       module.name().expect("module_paths: TreeItem has no name"))
                               .to_string());
                }
            }
        }
        return names;
    }

    fn split_subdir(&self, module: &str, newrev: &Oid) -> Object
    {
        // TODO: implement using libgit
        let shell = Shell { cwd: self.repo.path().to_path_buf() };
        shell.command("rm -Rf refs/original");

        self.call_git(&format!("branch -f initial_{} {}", module, newrev))
            .expect("create branch");

        self.call_git(&format!("filter-branch -f --subdirectory-filter {}/ -- initial_{}",
                               module,
                               module))
            .expect("error in filter-branch");

        return self.repo
            .revparse_single(&format!("initial_{}", module))
            .expect("can't find rewritten branch");
    }
}

pub fn module_review_upload(scratch: &Scratch,
                            newrev: Object,
                            module: &str,
                            central: &str)
    -> Result<(), Error>
{
    debug!(".\n\n==== Doing review upload for module {}", &module);

    let new = newrev.id();
    let old = scratch.tracking(&module, "master").expect("no tracking branch 1").id();

    if !try!(scratch.repo.graph_descendant_of(new, old)) {
        debug!(".");
        debug!("==============================================================================");
        debug!("================ Commit not based on master, rebase first! ===================");
        debug!("==============================================================================");
        return Ok(());
    }

    let walk = {
        let mut walk = try!(scratch.repo.revwalk());
        walk.set_sorting(SORT_REVERSE | SORT_TIME);
        try!(walk.push_range(&format!("{}..{}", old, new)));
        walk
    };

    debug!("==== Rewriting commits from {} to {}", old, new);

    let mut current_oid = scratch.tracking(central, "master").expect("no central tracking").id();
    for rev in walk {
        let currev = format!("{}", try!(rev));
        let oldrev = format!("{}", old);
        if oldrev == currev {
            continue;
        }
        debug!("==== Rewriting commit {}", currev);

        let module_commit_obj = try!(scratch.repo.revparse_single(&currev));
        let module_commit = try!(module_commit_obj.as_commit()
                                 .ok_or(Error::from_str("object is not actually a commit")));
        let module_tree = try!(module_commit.tree());

        let parent_commit = try!(scratch.repo.find_commit(current_oid));

        let new_tree = {
            let master_tree: Tree = try!(parent_commit.tree());
            let new_tree_oid =
                try!(scratch.module_to_subfolder(Path::new(module), &module_tree, &master_tree));
            try!(scratch.repo.find_tree(new_tree_oid))
        };

        current_oid = try!(scratch.rewrite(module_commit, &vec![&parent_commit], &new_tree));
    }

    debug!("");
    debug!("");
    debug!("====================== Doing actual upload in central git ========================");

    scratch.push(current_oid, central, "refs/for/master");

    debug!("==== The review upload may have worked, even if it says error below. Look UP! ====");
    Ok(())
}

pub fn central_submit(scratch: &Scratch, newrev: Object) -> Result<(), Error>
{
    debug!(" ---> central_submit (sha1 of commit: {})", &newrev.id());

    let central_commit = try!(newrev.as_commit()
                              .ok_or(Error::from_str("could not get commit from obj")));
    let central_tree = try!(central_commit.tree());

    for module in scratch.module_paths(&newrev) {
        debug!("");
        debug!("==== fetching tracking branch for module: {}", &module);
        let module_master_commit_obj = match scratch.tracking(&module, "master") {
            Some(obj) => obj,
            None => {
                error!("====    no tracking branch for module {} => project does not exist or is empty", &module);
                error!("====    initializing with subdir history");
                let commit = scratch.split_subdir(&module, &newrev.id());
                scratch.host.create_project(&module);
                scratch.push(commit.id(), &module, "refs/heads/master");
                scratch.tracking(&module, "master").expect("no tracking branch 3")
            }
        };

        let parents = vec![module_master_commit_obj.as_commit()
            .expect("could not get commit from obj")];

        debug!("==== checking for changes in module: {:?}", module);

        // new tree is sub-tree of complete central tree
        let old_tree = try!(parents[0].tree());
        let new_tree = try!(scratch.repo
                            .find_tree(try!(central_tree.get_path(&Path::new(&module))).id()));

        // if sha1's are equal the content is equal
        if new_tree.id() != old_tree.id() {
            debug!("====    commit changes module => make commit on module");
            let module_commit = try!(scratch.rewrite(central_commit, &parents, &new_tree));
            scratch.push(module_commit, &module, "master");
        }
        else {
            debug!("====    commit does not change module => skipping");
        }
    }
    Ok(())
}

pub struct Shell
{
    pub cwd: PathBuf,
}

impl Shell
{
    pub fn command(&self, cmd: &str) -> String
    {
        let output = Command::new("sh")
            .current_dir(&self.cwd)
            .arg("-c")
            .arg(&cmd)
            .output().unwrap_or_else(|e| panic!("failed to execute process: {}", e));

        return String::from_utf8(output.stdout).expect("failed to decode utf8").trim().to_string();
    }
}
<|endoftext|>


<commit_before>//! This file was generated by asn1tools version 0.145.2 Sun Jan 20 10:31:38 2019.

struct Encoder<'a> {
    buf: &'a mut [u8],
    size: isize,
    pos: isize
}

struct Decoder<'a> {
    buf: &'a[u8],
    size: isize,
    pos: isize
}

impl<'a> Encoder<'a> {

    fn new(dst: &'a mut [u8]) -> Encoder {
        Encoder {
            size: 8 * dst.len() as isize,
            buf: dst,
            pos: 0
        }
    }

    fn get_result(&self) -> Result<usize, &'static str>
    {
        if self.size >= 0 {
            return Ok((self.pos as usize + 7) / 8);
        } else {
            return Err("error");
        }
    }

    fn abort(&mut self, error: isize)
    {
        if self.size >= 0 {
            self.size = -error;
            self.pos = -error;
        }
    }

    fn alloc(&mut self, size: usize) -> isize
    {
        let pos: isize;

        if self.pos + size as isize <= self.size {
            pos = self.pos;
            self.pos += size as isize;
        } else {
            pos = -1;
            self.abort(3);
        }

        return pos;
    }

    fn append_bit(&mut self, value: u8)
    {
        let pos: isize;

        pos = self.alloc(1);

        if pos < 0 {
            return;
        }

        if pos % 8 == 0 {
            self.buf[pos as usize / 8] = 0;
        }

        self.buf[pos as usize / 8] |= value << (7 - (pos % 8));
    }

    fn append_bytes(&mut self, buf: &[u8])
    {
        let pos: isize;
        let byte_pos: usize;
        let pos_in_byte: usize;

        pos = self.alloc(8 * buf.len());

        if pos < 0 {
            return;
        }

        byte_pos = pos as usize / 8;
        pos_in_byte = pos as usize % 8;

        if pos_in_byte == 0 {
            self.buf.get_mut(byte_pos..byte_pos + buf.len())
                .unwrap()
                .copy_from_slice(buf.get(0..buf.len()).unwrap());
        } else {
            for i in 0..buf.len() {
                self.buf[byte_pos + i] |= buf[i] >> pos_in_byte;
                self.buf[byte_pos + i + 1] = buf[i] << (8 - pos_in_byte);
            }
        }
    }

    fn append_u8(&mut self, value: u8)
    {
        self.append_bytes(&[value]);
    }

    fn append_u16(&mut self, value: u16)
    {
        self.append_bytes(&[(value >> 8) as u8,
                            value as u8]);
    }

    fn append_u32(&mut self, value: u32)
    {
        self.append_bytes(&[(value >> 24) as u8,
                            (value >> 16) as u8,
                            (value >> 8) as u8,
                            value as u8]);
    }

    fn append_u64(&mut self, value: u64)
    {
        self.append_bytes(&[(value >> 56) as u8,
                            (value >> 48) as u8,
                            (value >> 40) as u8,
                            (value >> 32) as u8,
                            (value >> 24) as u8,
                            (value >> 16) as u8,
                            (value >> 8) as u8,
                            value as u8]);
    }

    fn append_i8(&mut self, value: i8)
    {
        self.append_u8((value as u8).wrapping_add(128));
    }

    fn append_i16(&mut self, value: i16)
    {
        self.append_u16((value as u16).wrapping_add(32768));
    }

    fn append_i32(&mut self, value: i32)
    {
        self.append_u32((value as u32).wrapping_add(2147483648));
    }

    fn append_i64(&mut self, value: i64)
    {
        self.append_u64((value as u64).wrapping_add(9223372036854775808));
    }

    fn append_bool(&mut self, value: bool)
    {
        self.append_bit(value as u8);
    }
}

impl<'a> Decoder<'a> {

    fn new(src: &'a[u8]) -> Decoder {
        Decoder {
            buf: src,
            size: 8 * src.len() as isize,
            pos: 0
        }
    }

    fn get_result(&self) -> Result<usize, &'static str>
    {
        if self.size >= 0 {
            return Ok((self.pos as usize + 7) / 8);
        } else {
            return Err("error");
        }
    }

    fn abort(&mut self, error: isize)
    {
        if self.size >= 0 {
            self.size = -error;
            self.pos = -error;
        }
    }

    fn free(&mut self, size: usize) -> isize
    {
        let pos: isize;

        if self.pos + size as isize <= self.size {
            pos = self.pos;
            self.pos += size as isize;
        } else {
            pos = -1;
            self.abort(2);
        }

        return pos;
    }

    fn read_bit(&mut self) -> u8
    {
        let pos: isize;
        let value: u8;

        pos = self.free(1);

        if pos >= 0 {
            value = (self.buf[pos as usize / 8] >> (7 - (pos % 8))) & 1;
        } else {
            value = 0;
        }

        return value;
    }

    fn read_bytes(&mut self, buf: &mut [u8])
    {
        let pos: isize;
        let byte_pos: usize;
        let pos_in_byte: usize;

        pos = self.free(8 * buf.len());

        if pos < 0 {
            return;
        }

        byte_pos = pos as usize / 8;
        pos_in_byte = pos as usize % 8;

        if pos_in_byte == 0 {
            buf.copy_from_slice(self.buf.get(byte_pos..byte_pos + buf.len()).unwrap());
        } else {
            for i in 0..buf.len() {
                buf[i] = self.buf[byte_pos + i] << pos_in_byte;
                buf[i] |= self.buf[byte_pos + i + 1] >> (8 - pos_in_byte);
            }
        }
    }

    fn read_u8(&mut self) -> u8
    {
        let mut value = [0; 1];

        self.read_bytes(&mut value);

        return value[0];
    }

    fn read_u16(&mut self) -> u16
    {
        let mut buf = [0; 2];

        self.read_bytes(&mut buf);

        return ((buf[0] as u16) << 8) | (buf[1] as u16);
    }

    fn read_u32(&mut self) -> u32
    {
        let mut buf = [0; 4];

        self.read_bytes(&mut buf);

        return ((buf[0] as u32) << 24)
               | ((buf[1] as u32) << 16)
               | ((buf[2] as u32) << 8)
               | (buf[3] as u32);
    }

    fn read_u64(&mut self) -> u64
    {
        let mut buf = [0; 8];

        self.read_bytes(&mut buf);

        return ((buf[0] as u64) << 56)
               | ((buf[1] as u64) << 48)
               | ((buf[2] as u64) << 40)
               | ((buf[3] as u64) << 32)
               | ((buf[4] as u64) << 24)
               | ((buf[5] as u64) << 16)
               | ((buf[6] as u64) << 8)
               | buf[7] as u64;
    }

    fn read_i8(&mut self) -> i8
    {
        return self.read_u8().wrapping_sub(128) as i8;
    }

    fn read_i16(&mut self) -> i16
    {
        return self.read_u16().wrapping_sub(32768) as i16;
    }

    fn read_i32(&mut self) -> i32
    {
        return self.read_u32().wrapping_sub(2147483648) as i32;
    }

    fn read_i64(&mut self) -> i64
    {
        return self.read_u64().wrapping_sub(9223372036854775808) as i64;
    }

    fn read_bool(&mut self) -> bool
    {
        return self.read_bit() != 0;
    }
}

/// Type A in module RustSource.
#[derive(Debug, Default, PartialEq)]
pub struct RustSourceAJ {
    pub buf: [u8; 11]
}

#[derive(Debug, Default, PartialEq)]
pub struct RustSourceA {
    pub a: i8,
    pub b: i16,
    pub c: i32,
    pub d: i64,
    pub e: u8,
    pub f: u16,
    pub g: u32,
    pub h: u64,
    pub i: bool,
    pub j: RustSourceAJ
}

impl RustSourceA {

    pub fn to_bytes(&mut self, mut dst: &mut [u8]) -> Result<usize, &'static str>
    {
        let mut encoder = Encoder::new(&mut dst);

        self.to_bytes_inner(&mut encoder);

        return encoder.get_result();
    }

    pub fn from_bytes(&mut self, src: &[u8]) -> Result<usize, &'static str>
    {
        let mut decoder = Decoder::new(&src);

        self.from_bytes_inner(&mut decoder);

        return decoder.get_result();
    }

    fn to_bytes_inner(&mut self, encoder: &mut Encoder)
    {
        encoder.append_i8(self.a);
        encoder.append_i16(self.b);
        encoder.append_i32(self.c);
        encoder.append_i64(self.d);
        encoder.append_u8(self.e);
        encoder.append_u16(self.f);
        encoder.append_u32(self.g);
        encoder.append_u64(self.h);
        encoder.append_bool(self.i);
        encoder.append_bytes(&self.j.buf);
    }

    fn from_bytes_inner(&mut self, decoder: &mut Decoder)
    {
        self.a = decoder.read_i8();
        self.b = decoder.read_i16();
        self.c = decoder.read_i32();
        self.d = decoder.read_i64();
        self.e = decoder.read_u8();
        self.f = decoder.read_u16();
        self.g = decoder.read_u32();
        self.h = decoder.read_u64();
        self.i = decoder.read_bool();
        decoder.read_bytes(&mut self.j.buf);
    }
}
<commit_msg>Use to_be_bytes() and from_be_bytes() in generated Rust code.<commit_after>//! This file was generated by asn1tools version 0.145.2 Sun Jan 20 10:31:38 2019.

struct Encoder<'a> {
    buf: &'a mut [u8],
    size: isize,
    pos: isize
}

struct Decoder<'a> {
    buf: &'a[u8],
    size: isize,
    pos: isize
}

impl<'a> Encoder<'a> {

    fn new(dst: &'a mut [u8]) -> Encoder {
        Encoder {
            size: 8 * dst.len() as isize,
            buf: dst,
            pos: 0
        }
    }

    fn get_result(&self) -> Result<usize, &'static str>
    {
        if self.size >= 0 {
            return Ok((self.pos as usize + 7) / 8);
        } else {
            return Err("error");
        }
    }

    fn abort(&mut self, error: isize)
    {
        if self.size >= 0 {
            self.size = -error;
            self.pos = -error;
        }
    }

    fn alloc(&mut self, size: usize) -> isize
    {
        let pos: isize;

        if self.pos + size as isize <= self.size {
            pos = self.pos;
            self.pos += size as isize;
        } else {
            pos = -1;
            self.abort(3);
        }

        return pos;
    }

    fn append_bit(&mut self, value: u8)
    {
        let pos: isize;

        pos = self.alloc(1);

        if pos < 0 {
            return;
        }

        if pos % 8 == 0 {
            self.buf[pos as usize / 8] = 0;
        }

        self.buf[pos as usize / 8] |= value << (7 - (pos % 8));
    }

    fn append_bytes(&mut self, buf: &[u8])
    {
        let pos: isize;
        let byte_pos: usize;
        let pos_in_byte: usize;

        pos = self.alloc(8 * buf.len());

        if pos < 0 {
            return;
        }

        byte_pos = pos as usize / 8;
        pos_in_byte = pos as usize % 8;

        if pos_in_byte == 0 {
            self.buf.get_mut(byte_pos..byte_pos + buf.len())
                .unwrap()
                .copy_from_slice(buf.get(0..buf.len()).unwrap());
        } else {
            for i in 0..buf.len() {
                self.buf[byte_pos + i] |= buf[i] >> pos_in_byte;
                self.buf[byte_pos + i + 1] = buf[i] << (8 - pos_in_byte);
            }
        }
    }

    fn append_u8(&mut self, value: u8)
    {
        self.append_bytes(&[value]);
    }

    fn append_u16(&mut self, value: u16)
    {
        self.append_bytes(&value.to_be_bytes());
    }

    fn append_u32(&mut self, value: u32)
    {
        self.append_bytes(&value.to_be_bytes());
    }

    fn append_u64(&mut self, value: u64)
    {
        self.append_bytes(&value.to_be_bytes());
    }

    fn append_i8(&mut self, value: i8)
    {
        self.append_u8((value as u8).wrapping_add(128));
    }

    fn append_i16(&mut self, value: i16)
    {
        self.append_u16((value as u16).wrapping_add(32768));
    }

    fn append_i32(&mut self, value: i32)
    {
        self.append_u32((value as u32).wrapping_add(2147483648));
    }

    fn append_i64(&mut self, value: i64)
    {
        self.append_u64((value as u64).wrapping_add(9223372036854775808));
    }

    fn append_bool(&mut self, value: bool)
    {
        self.append_bit(value as u8);
    }
}

impl<'a> Decoder<'a> {

    fn new(src: &'a[u8]) -> Decoder {
        Decoder {
            buf: src,
            size: 8 * src.len() as isize,
            pos: 0
        }
    }

    fn get_result(&self) -> Result<usize, &'static str>
    {
        if self.size >= 0 {
            return Ok((self.pos as usize + 7) / 8);
        } else {
            return Err("error");
        }
    }

    fn abort(&mut self, error: isize)
    {
        if self.size >= 0 {
            self.size = -error;
            self.pos = -error;
        }
    }

    fn free(&mut self, size: usize) -> isize
    {
        let pos: isize;

        if self.pos + size as isize <= self.size {
            pos = self.pos;
            self.pos += size as isize;
        } else {
            pos = -1;
            self.abort(2);
        }

        return pos;
    }

    fn read_bit(&mut self) -> u8
    {
        let pos: isize;
        let value: u8;

        pos = self.free(1);

        if pos >= 0 {
            value = (self.buf[pos as usize / 8] >> (7 - (pos % 8))) & 1;
        } else {
            value = 0;
        }

        return value;
    }

    fn read_bytes(&mut self, buf: &mut [u8])
    {
        let pos: isize;
        let byte_pos: usize;
        let pos_in_byte: usize;

        pos = self.free(8 * buf.len());

        if pos < 0 {
            return;
        }

        byte_pos = pos as usize / 8;
        pos_in_byte = pos as usize % 8;

        if pos_in_byte == 0 {
            buf.copy_from_slice(self.buf.get(byte_pos..byte_pos + buf.len()).unwrap());
        } else {
            for i in 0..buf.len() {
                buf[i] = self.buf[byte_pos + i] << pos_in_byte;
                buf[i] |= self.buf[byte_pos + i + 1] >> (8 - pos_in_byte);
            }
        }
    }

    fn read_u8(&mut self) -> u8
    {
        let mut buf = [0; 1];

        self.read_bytes(&mut buf);

        return u8::from_be_bytes(buf);
    }

    fn read_u16(&mut self) -> u16
    {
        let mut buf = [0; 2];

        self.read_bytes(&mut buf);

        return u16::from_be_bytes(buf);
    }

    fn read_u32(&mut self) -> u32
    {
        let mut buf = [0; 4];

        self.read_bytes(&mut buf);

        return u32::from_be_bytes(buf);
    }

    fn read_u64(&mut self) -> u64
    {
        let mut buf = [0; 8];

        self.read_bytes(&mut buf);

        return u64::from_be_bytes(buf);
    }

    fn read_i8(&mut self) -> i8
    {
        return self.read_u8().wrapping_sub(128) as i8;
    }

    fn read_i16(&mut self) -> i16
    {
        return self.read_u16().wrapping_sub(32768) as i16;
    }

    fn read_i32(&mut self) -> i32
    {
        return self.read_u32().wrapping_sub(2147483648) as i32;
    }

    fn read_i64(&mut self) -> i64
    {
        return self.read_u64().wrapping_sub(9223372036854775808) as i64;
    }

    fn read_bool(&mut self) -> bool
    {
        return self.read_bit() != 0;
    }
}

/// Type A in module RustSource.
#[derive(Debug, Default, PartialEq)]
pub struct RustSourceAJ {
    pub buf: [u8; 11]
}

#[derive(Debug, Default, PartialEq)]
pub struct RustSourceA {
    pub a: i8,
    pub b: i16,
    pub c: i32,
    pub d: i64,
    pub e: u8,
    pub f: u16,
    pub g: u32,
    pub h: u64,
    pub i: bool,
    pub j: RustSourceAJ
}

impl RustSourceA {

    pub fn to_bytes(&mut self, mut dst: &mut [u8]) -> Result<usize, &'static str>
    {
        let mut encoder = Encoder::new(&mut dst);

        self.to_bytes_inner(&mut encoder);

        return encoder.get_result();
    }

    pub fn from_bytes(&mut self, src: &[u8]) -> Result<usize, &'static str>
    {
        let mut decoder = Decoder::new(&src);

        self.from_bytes_inner(&mut decoder);

        return decoder.get_result();
    }

    fn to_bytes_inner(&mut self, encoder: &mut Encoder)
    {
        encoder.append_i8(self.a);
        encoder.append_i16(self.b);
        encoder.append_i32(self.c);
        encoder.append_i64(self.d);
        encoder.append_u8(self.e);
        encoder.append_u16(self.f);
        encoder.append_u32(self.g);
        encoder.append_u64(self.h);
        encoder.append_bool(self.i);
        encoder.append_bytes(&self.j.buf);
    }

    fn from_bytes_inner(&mut self, decoder: &mut Decoder)
    {
        self.a = decoder.read_i8();
        self.b = decoder.read_i16();
        self.c = decoder.read_i32();
        self.d = decoder.read_i64();
        self.e = decoder.read_u8();
        self.f = decoder.read_u16();
        self.g = decoder.read_u32();
        self.h = decoder.read_u64();
        self.i = decoder.read_bool();
        decoder.read_bytes(&mut self.j.buf);
    }
}
<|endoftext|>


<commit_before>
fn main() {
    println!("cargo:include=/home/sthiele/develop/clingo-rs/clingo/libgringo");
    println!("cargo:rustc-link-search=native=/home/sthiele/develop/clingo-rs/clingo/build/release");
    println!("cargo:rustc-link-lib=dylib=gringo");
    println!("cargo:rustc-link-lib=dylib=reify");
    println!("cargo:rustc-link-lib=dylib=lp");
    println!("cargo:rustc-link-lib=dylib=stdc++");
    println!("cargo:rustc-link-lib=dylib=python3.5m");
}

<commit_msg>use relative paths<commit_after>
fn main() {
    println!("cargo:include=clingo/libgringo");
    println!("cargo:rustc-link-search=native=clingo/build/release");
    println!("cargo:rustc-link-lib=dylib=gringo");
    println!("cargo:rustc-link-lib=dylib=reify");
    println!("cargo:rustc-link-lib=dylib=lp");
    println!("cargo:rustc-link-lib=dylib=stdc++");
    println!("cargo:rustc-link-lib=dylib=python3.5m");
}

<|endoftext|>


<commit_before>use super::*;
use expect_test::expect;

#[test]
fn inner_item_smoke() {
    check_at(
        r#"
struct inner {}
fn outer() {
    $0
    fn inner() {}
}
"#,
        expect![[r#"
            block scope
            inner: v
            crate
            inner: t
            outer: v
        "#]],
    );
}

#[test]
fn use_from_crate() {
    check_at(
        r#"
struct Struct;
fn outer() {
    use Struct;
    use crate::Struct as CrateStruct;
    use self::Struct as SelfStruct;
    $0
}
"#,
        expect![[r#"
            block scope
            CrateStruct: t v
            SelfStruct: t v
            Struct: t v
            crate
            Struct: t v
            outer: v
        "#]],
    );
}

#[test]
fn merge_namespaces() {
    check_at(
        r#"
struct name {}
fn outer() {
    fn name() {}

    use name as imported; // should import both `name`s

    $0
}
"#,
        expect![[r#"
            block scope
            imported: t v
            name: v
            crate
            name: t
            outer: v
        "#]],
    );
}

#[test]
fn nested_blocks() {
    check_at(
        r#"
fn outer() {
    struct inner1 {}
    fn inner() {
        use inner1;
        use outer;
        fn inner2() {}
        $0
    }
}
"#,
        expect![[r#"
            block scope
            inner1: t
            inner2: v
            outer: v
            block scope
            inner: v
            inner1: t
            crate
            outer: v
        "#]],
    );
}

#[test]
fn super_imports() {
    check_at(
        r#"
mod module {
    fn f() {
        use super::Struct;
        $0
    }
}

struct Struct {}
"#,
        expect![[r#"
            block scope
            Struct: t
            crate
            Struct: t
            module: t

            crate::module
            f: v
        "#]],
    );
}

#[test]
fn legacy_macro_items() {
    // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
    // correctly.
    check_at(
        r#"
macro_rules! hit {
    () => {
        struct Hit {}
    }
}

fn f() {
    hit!();
    $0
}
"#,
        expect![[r#"
            block scope
            Hit: t
            crate
            f: v
        "#]],
    );
}

#[test]
fn macro_resolve() {
    check_at(
        r#"
//- /lib.rs crate:lib deps:core
use core::mark;

fn f() {
    fn nested() {
        mark::hit!(Hit);
        $0
    }
}
//- /core.rs crate:core
pub mod mark {
    #[macro_export]
    macro_rules! _hit {
        ($name:ident) => {
            struct $name {}
        }
    }

    pub use crate::_hit as hit;
}
"#,
        expect![[r#"
            block scope
            Hit: t
            block scope
            nested: v
            crate
            f: v
            mark: t
        "#]],
    );
}
<commit_msg>Test for name resolution with DefMap shortcut<commit_after>use super::*;
use expect_test::expect;

#[test]
fn inner_item_smoke() {
    check_at(
        r#"
struct inner {}
fn outer() {
    $0
    fn inner() {}
}
"#,
        expect![[r#"
            block scope
            inner: v
            crate
            inner: t
            outer: v
        "#]],
    );
}

#[test]
fn use_from_crate() {
    check_at(
        r#"
struct Struct;
fn outer() {
    use Struct;
    use crate::Struct as CrateStruct;
    use self::Struct as SelfStruct;
    $0
}
"#,
        expect![[r#"
            block scope
            CrateStruct: t v
            SelfStruct: t v
            Struct: t v
            crate
            Struct: t v
            outer: v
        "#]],
    );
}

#[test]
fn merge_namespaces() {
    check_at(
        r#"
struct name {}
fn outer() {
    fn name() {}

    use name as imported; // should import both `name`s

    $0
}
"#,
        expect![[r#"
            block scope
            imported: t v
            name: v
            crate
            name: t
            outer: v
        "#]],
    );
}

#[test]
fn nested_blocks() {
    check_at(
        r#"
fn outer() {
    struct inner1 {}
    fn inner() {
        use inner1;
        use outer;
        fn inner2() {}
        $0
    }
}
"#,
        expect![[r#"
            block scope
            inner1: t
            inner2: v
            outer: v
            block scope
            inner: v
            inner1: t
            crate
            outer: v
        "#]],
    );
}

#[test]
fn super_imports() {
    check_at(
        r#"
mod module {
    fn f() {
        use super::Struct;
        $0
    }
}

struct Struct {}
"#,
        expect![[r#"
            block scope
            Struct: t
            crate
            Struct: t
            module: t

            crate::module
            f: v
        "#]],
    );
}

#[test]
fn legacy_macro_items() {
    // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
    // correctly.
    check_at(
        r#"
macro_rules! hit {
    () => {
        struct Hit {}
    }
}

fn f() {
    hit!();
    $0
}
"#,
        expect![[r#"
            block scope
            Hit: t
            crate
            f: v
        "#]],
    );
}

#[test]
fn macro_resolve() {
    check_at(
        r#"
//- /lib.rs crate:lib deps:core
use core::mark;

fn f() {
    fn nested() {
        mark::hit!(Hit);
        $0
    }
}
//- /core.rs crate:core
pub mod mark {
    #[macro_export]
    macro_rules! _hit {
        ($name:ident) => {
            struct $name {}
        }
    }

    pub use crate::_hit as hit;
}
"#,
        expect![[r#"
            block scope
            Hit: t
            block scope
            nested: v
            crate
            f: v
            mark: t
        "#]],
    );
}

#[test]
fn macro_resolve_legacy() {
    check_at(
        r#"
//- /lib.rs
mod module;

//- /module.rs
macro_rules! m {
    () => {
        struct Def {}
    };
}

fn f() {
    {
        m!();
        $0
    }
}
        "#,
        expect![[r#"
            block scope
            Def: t
            crate
            module: t

            crate::module
            f: v
        "#]],
    )
}
<|endoftext|>


<commit_before>use expect_test::expect;

use crate::TopEntryPoint;

#[test]
fn source_file() {
    check(
        TopEntryPoint::SourceFile,
        "",
        expect![[r#"
        SOURCE_FILE
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "struct S;",
        expect![[r#"
        SOURCE_FILE
          STRUCT
            STRUCT_KW "struct"
            WHITESPACE " "
            NAME
              IDENT "S"
            SEMICOLON ";"
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "@error@",
        expect![[r#"
        SOURCE_FILE
          ERROR
            AT "@"
          MACRO_CALL
            PATH
              PATH_SEGMENT
                NAME_REF
                  IDENT "error"
          ERROR
            AT "@"
        error 0: expected an item
        error 6: expected BANG
        error 6: expected `{`, `[`, `(`
        error 6: expected SEMICOLON
        error 6: expected an item
    "#]],
    );
}

#[test]
fn macro_stmt() {
    check(
        TopEntryPoint::MacroStmts,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_STMTS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected expression
        "##]],
    );
    check(
        TopEntryPoint::MacroStmts,
        "let x = 1 2 struct S;",
        expect![[r#"
            MACRO_STMTS
              LET_STMT
                LET_KW "let"
                WHITESPACE " "
                IDENT_PAT
                  NAME
                    IDENT "x"
                WHITESPACE " "
                EQ "="
                WHITESPACE " "
                LITERAL
                  INT_NUMBER "1"
              WHITESPACE " "
              EXPR_STMT
                LITERAL
                  INT_NUMBER "2"
              WHITESPACE " "
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
        "#]],
    );
}

#[track_caller]
fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
    let (parsed, _errors) = super::parse(entry, input);
    expect.assert_eq(&parsed)
}
<commit_msg>add test for macro items<commit_after>use expect_test::expect;

use crate::TopEntryPoint;

#[test]
fn source_file() {
    check(
        TopEntryPoint::SourceFile,
        "",
        expect![[r#"
        SOURCE_FILE
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "struct S;",
        expect![[r#"
        SOURCE_FILE
          STRUCT
            STRUCT_KW "struct"
            WHITESPACE " "
            NAME
              IDENT "S"
            SEMICOLON ";"
    "#]],
    );

    check(
        TopEntryPoint::SourceFile,
        "@error@",
        expect![[r#"
        SOURCE_FILE
          ERROR
            AT "@"
          MACRO_CALL
            PATH
              PATH_SEGMENT
                NAME_REF
                  IDENT "error"
          ERROR
            AT "@"
        error 0: expected an item
        error 6: expected BANG
        error 6: expected `{`, `[`, `(`
        error 6: expected SEMICOLON
        error 6: expected an item
    "#]],
    );
}

#[test]
fn macro_stmt() {
    check(
        TopEntryPoint::MacroStmts,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_STMTS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected expression
        "##]],
    );
    check(
        TopEntryPoint::MacroStmts,
        "let x = 1 2 struct S;",
        expect![[r#"
            MACRO_STMTS
              LET_STMT
                LET_KW "let"
                WHITESPACE " "
                IDENT_PAT
                  NAME
                    IDENT "x"
                WHITESPACE " "
                EQ "="
                WHITESPACE " "
                LITERAL
                  INT_NUMBER "1"
              WHITESPACE " "
              EXPR_STMT
                LITERAL
                  INT_NUMBER "2"
              WHITESPACE " "
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
        "#]],
    );
}

#[test]
fn macro_items() {
    check(
        TopEntryPoint::MacroItems,
        "#!/usr/bin/rust",
        expect![[r##"
            MACRO_ITEMS
              ERROR
                SHEBANG "#!/usr/bin/rust"
            error 0: expected an item
        "##]],
    );
    check(
        TopEntryPoint::MacroItems,
        "struct S; foo!{}",
        expect![[r#"
            MACRO_ITEMS
              STRUCT
                STRUCT_KW "struct"
                WHITESPACE " "
                NAME
                  IDENT "S"
                SEMICOLON ";"
              WHITESPACE " "
              MACRO_CALL
                PATH
                  PATH_SEGMENT
                    NAME_REF
                      IDENT "foo"
                BANG "!"
                TOKEN_TREE
                  L_CURLY "{"
                  R_CURLY "}"
        "#]],
    );
}

#[track_caller]
fn check(entry: TopEntryPoint, input: &str, expect: expect_test::Expect) {
    let (parsed, _errors) = super::parse(entry, input);
    expect.assert_eq(&parsed)
}
<|endoftext|>


<commit_before>//! The `Parse` trait for CSS properties, and utilities for parsers.

use cssparser::{Parser, ParserInput, Token};
use markup5ever::QualName;
use std::str;

use crate::error::*;

/// Trait to parse values using `cssparser::Parser`.
pub trait Parse: Sized {
    /// Parses a value out of the `parser`.
    ///
    /// All value types should implement this for composability.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>>;

    /// Convenience function to parse a value out of a `&str`.
    ///
    /// This is useful mostly for tests which want to avoid creating a
    /// `cssparser::Parser` by hand.  Property types do not need to reimplement this.
    fn parse_str(s: &str) -> Result<Self, ParseError<'_>> {
        let mut input = ParserInput::new(s);
        let mut parser = Parser::new(&mut input);

        let res = Self::parse(&mut parser)?;
        parser.expect_exhausted()?;

        Ok(res)
    }
}

/// Consumes a comma if it exists, or does nothing.
pub fn optional_comma<'i, 't>(parser: &mut Parser<'i, 't>) {
    let _ = parser.try_parse(|p| p.expect_comma());
}

/// Parses an `f32` and ensures that it is not an infinity or NaN.
pub fn finite_f32(n: f32) -> Result<f32, ValueErrorKind> {
    if n.is_finite() {
        Ok(n)
    } else {
        Err(ValueErrorKind::Value("expected finite number".to_string()))
    }
}

pub trait ParseValue<T: Parse> {
    /// Parses a `value` string into a type `T`.
    fn parse(&self, value: &str) -> Result<T, ElementError>;

    /// Parses a `value` string into a type `T` with an optional validation function.
    fn parse_and_validate<F: FnOnce(T) -> Result<T, ValueErrorKind>>(
        &self,
        value: &str,
        validate: F,
    ) -> Result<T, ElementError>;
}

impl<T: Parse> ParseValue<T> for QualName {
    fn parse(&self, value: &str) -> Result<T, ElementError> {
        let mut input = ParserInput::new(value);
        let mut parser = Parser::new(&mut input);

        T::parse(&mut parser).attribute(self.clone())
    }

    fn parse_and_validate<F: FnOnce(T) -> Result<T, ValueErrorKind>>(
        &self,
        value: &str,
        validate: F,
    ) -> Result<T, ElementError> {
        let mut input = ParserInput::new(value);
        let mut parser = Parser::new(&mut input);

        let v = T::parse(&mut parser).attribute(self.clone())?;

        validate(v)
            .map_err(|e| parser.new_custom_error(e))
            .attribute(self.clone())
    }
}

impl<T: Parse> Parse for Option<T> {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        T::parse(parser).map(Some)
    }
}

impl Parse for f64 {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let n = parser.expect_number()?;
        if n.is_finite() {
            Ok(f64::from(n))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error("expected finite number")))
        }
    }
}

/// CSS number-optional-number
///
/// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NumberOptionalNumber<T: Parse>(pub T, pub T);

impl<T: Parse + Copy> Parse for NumberOptionalNumber<T> {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let x = Parse::parse(parser)?;

        if !parser.is_exhausted() {
            optional_comma(parser);
            let y = Parse::parse(parser)?;
            Ok(NumberOptionalNumber(x, y))
        } else {
            Ok(NumberOptionalNumber(x, x))
        }
    }
}

impl Parse for i32 {
    /// CSS integer
    ///
    /// https://www.w3.org/TR/SVG11/types.html#DataTypeInteger
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parser.expect_integer()?)
    }
}

/// Parses a list of identifiers from a `cssparser::Parser`
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate librsvg;
/// # use cssparser::{ParserInput, Parser};
/// # fn main() -> Result<(), cssparser::BasicParseError<'static>> {
/// # let mut input = ParserInput::new("true");
/// # let mut parser = Parser::new(&mut input);
/// let my_boolean = parse_identifiers!(
///     parser,
///     "true" => true,
///     "false" => false,
/// )?;
/// # Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! parse_identifiers {
    ($parser:expr,
     $($str:expr => $val:expr,)+) => {
        {
            let loc = $parser.current_source_location();
            let token = $parser.next()?;

            match token {
                $(cssparser::Token::Ident(ref cow) if cow.eq_ignore_ascii_case($str) => Ok($val),)+

                _ => Err(loc.new_basic_unexpected_token_error(token.clone()))
            }
        }
    };
}

/// https://www.w3.org/TR/css-values-4/#custom-idents
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CustomIdent(String);

impl Parse for CustomIdent {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let token = parser.next()?;

        match token {
            // CSS-wide keywords and "default" are errors here
            // https://www.w3.org/TR/css-values-4/#css-wide-keywords
            Token::Ident(ref cow) => {
                for s in &["initial", "inherit", "unset", "default"] {
                    if cow.eq_ignore_ascii_case(s) {
                        return Err(loc.new_basic_unexpected_token_error(token.clone()).into());
                    }
                }

                Ok(CustomIdent(cow.as_ref().to_string()))
            }

            _ => Err(loc.new_basic_unexpected_token_error(token.clone()).into()),
        }
    }
}

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

    #[test]
    fn parses_number_optional_number() {
        assert_eq!(
            NumberOptionalNumber::parse_str("1, 2").unwrap(),
            NumberOptionalNumber(1.0, 2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1 2").unwrap(),
            NumberOptionalNumber(1.0, 2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1").unwrap(),
            NumberOptionalNumber(1.0, 1.0)
        );

        assert_eq!(
            NumberOptionalNumber::parse_str("-1, -2").unwrap(),
            NumberOptionalNumber(-1.0, -2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1 -2").unwrap(),
            NumberOptionalNumber(-1.0, -2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1").unwrap(),
            NumberOptionalNumber(-1.0, -1.0)
        );
    }

    #[test]
    fn invalid_number_optional_number() {
        assert!(NumberOptionalNumber::<f64>::parse_str("").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("x1").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 , x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 , 2x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 2 x").is_err());
    }

    #[test]
    fn parses_integer() {
        assert_eq!(i32::parse_str("1").unwrap(), 1);
        assert_eq!(i32::parse_str("-1").unwrap(), -1);
    }

    #[test]
    fn invalid_integer() {
        assert!(i32::parse_str("").is_err());
        assert!(i32::parse_str("1x").is_err());
        assert!(i32::parse_str("1.5").is_err());
    }

    #[test]
    fn parses_integer_optional_integer() {
        assert_eq!(
            NumberOptionalNumber::parse_str("1, 2").unwrap(),
            NumberOptionalNumber(1, 2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1 2").unwrap(),
            NumberOptionalNumber(1, 2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1").unwrap(),
            NumberOptionalNumber(1, 1)
        );

        assert_eq!(
            NumberOptionalNumber::parse_str("-1, -2").unwrap(),
            NumberOptionalNumber(-1, -2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1 -2").unwrap(),
            NumberOptionalNumber(-1, -2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1").unwrap(),
            NumberOptionalNumber(-1, -1)
        );
    }

    #[test]
    fn invalid_integer_optional_integer() {
        assert!(NumberOptionalNumber::<i32>::parse_str("").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("x1").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 , x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 , 2x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 2 x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1.5").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 2.5").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1, 2.5").is_err());
    }

    #[test]
    fn parses_custom_ident() {
        assert_eq!(
            CustomIdent::parse_str("hello").unwrap(),
            CustomIdent("hello".to_string())
        );
    }

    #[test]
    fn invalid_custom_ident_yields_error() {
        assert!(CustomIdent::parse_str("initial").is_err());
        assert!(CustomIdent::parse_str("inherit").is_err());
        assert!(CustomIdent::parse_str("unset").is_err());
        assert!(CustomIdent::parse_str("default").is_err());
        assert!(CustomIdent::parse_str("").is_err());
    }
}
<commit_msg>parsers: helper structs for NonZero and NonNegative numbers<commit_after>//! The `Parse` trait for CSS properties, and utilities for parsers.

use cssparser::{Parser, ParserInput, Token};
use markup5ever::QualName;
use std::str;

use crate::error::*;

/// Trait to parse values using `cssparser::Parser`.
pub trait Parse: Sized {
    /// Parses a value out of the `parser`.
    ///
    /// All value types should implement this for composability.
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>>;

    /// Convenience function to parse a value out of a `&str`.
    ///
    /// This is useful mostly for tests which want to avoid creating a
    /// `cssparser::Parser` by hand.  Property types do not need to reimplement this.
    fn parse_str(s: &str) -> Result<Self, ParseError<'_>> {
        let mut input = ParserInput::new(s);
        let mut parser = Parser::new(&mut input);

        let res = Self::parse(&mut parser)?;
        parser.expect_exhausted()?;

        Ok(res)
    }
}

/// Consumes a comma if it exists, or does nothing.
pub fn optional_comma<'i, 't>(parser: &mut Parser<'i, 't>) {
    let _ = parser.try_parse(|p| p.expect_comma());
}

/// Parses an `f32` and ensures that it is not an infinity or NaN.
pub fn finite_f32(n: f32) -> Result<f32, ValueErrorKind> {
    if n.is_finite() {
        Ok(n)
    } else {
        Err(ValueErrorKind::Value("expected finite number".to_string()))
    }
}

pub trait ParseValue<T: Parse> {
    /// Parses a `value` string into a type `T`.
    fn parse(&self, value: &str) -> Result<T, ElementError>;

    /// Parses a `value` string into a type `T` with an optional validation function.
    fn parse_and_validate<F: FnOnce(T) -> Result<T, ValueErrorKind>>(
        &self,
        value: &str,
        validate: F,
    ) -> Result<T, ElementError>;
}

impl<T: Parse> ParseValue<T> for QualName {
    fn parse(&self, value: &str) -> Result<T, ElementError> {
        let mut input = ParserInput::new(value);
        let mut parser = Parser::new(&mut input);

        T::parse(&mut parser).attribute(self.clone())
    }

    fn parse_and_validate<F: FnOnce(T) -> Result<T, ValueErrorKind>>(
        &self,
        value: &str,
        validate: F,
    ) -> Result<T, ElementError> {
        let mut input = ParserInput::new(value);
        let mut parser = Parser::new(&mut input);

        let v = T::parse(&mut parser).attribute(self.clone())?;

        validate(v)
            .map_err(|e| parser.new_custom_error(e))
            .attribute(self.clone())
    }
}

impl<T: Parse> Parse for Option<T> {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        T::parse(parser).map(Some)
    }
}

impl Parse for f64 {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let n = parser.expect_number()?;
        if n.is_finite() {
            Ok(f64::from(n))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error("expected finite number")))
        }
    }
}

/// Non-Zero number (for instance useful for "divisor")
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NonZero(pub f64);

impl Parse for NonZero {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let n = Parse::parse(parser)?;
        if n != 0.0 {
            Ok(NonZero(n))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error("expected non zero number")))
        }
    }
}

/// Non-Negative number
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NonNegative(pub f64);

impl Parse for NonNegative {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let n = Parse::parse(parser)?;
        if n >= 0.0 {
            Ok(NonNegative(n))
        } else {
            Err(loc.new_custom_error(ValueErrorKind::value_error("expected non negative number")))
        }
    }
}

/// CSS number-optional-number
///
/// https://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct NumberOptionalNumber<T: Parse>(pub T, pub T);

impl<T: Parse + Copy> Parse for NumberOptionalNumber<T> {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let x = Parse::parse(parser)?;

        if !parser.is_exhausted() {
            optional_comma(parser);
            let y = Parse::parse(parser)?;
            Ok(NumberOptionalNumber(x, y))
        } else {
            Ok(NumberOptionalNumber(x, x))
        }
    }
}

impl Parse for i32 {
    /// CSS integer
    ///
    /// https://www.w3.org/TR/SVG11/types.html#DataTypeInteger
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        Ok(parser.expect_integer()?)
    }
}

/// Parses a list of identifiers from a `cssparser::Parser`
///
/// # Example
///
/// ```
/// # #[macro_use] extern crate librsvg;
/// # use cssparser::{ParserInput, Parser};
/// # fn main() -> Result<(), cssparser::BasicParseError<'static>> {
/// # let mut input = ParserInput::new("true");
/// # let mut parser = Parser::new(&mut input);
/// let my_boolean = parse_identifiers!(
///     parser,
///     "true" => true,
///     "false" => false,
/// )?;
/// # Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! parse_identifiers {
    ($parser:expr,
     $($str:expr => $val:expr,)+) => {
        {
            let loc = $parser.current_source_location();
            let token = $parser.next()?;

            match token {
                $(cssparser::Token::Ident(ref cow) if cow.eq_ignore_ascii_case($str) => Ok($val),)+

                _ => Err(loc.new_basic_unexpected_token_error(token.clone()))
            }
        }
    };
}

/// https://www.w3.org/TR/css-values-4/#custom-idents
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CustomIdent(String);

impl Parse for CustomIdent {
    fn parse<'i>(parser: &mut Parser<'i, '_>) -> Result<Self, ParseError<'i>> {
        let loc = parser.current_source_location();
        let token = parser.next()?;

        match token {
            // CSS-wide keywords and "default" are errors here
            // https://www.w3.org/TR/css-values-4/#css-wide-keywords
            Token::Ident(ref cow) => {
                for s in &["initial", "inherit", "unset", "default"] {
                    if cow.eq_ignore_ascii_case(s) {
                        return Err(loc.new_basic_unexpected_token_error(token.clone()).into());
                    }
                }

                Ok(CustomIdent(cow.as_ref().to_string()))
            }

            _ => Err(loc.new_basic_unexpected_token_error(token.clone()).into()),
        }
    }
}

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

    #[test]
    fn parses_number_optional_number() {
        assert_eq!(
            NumberOptionalNumber::parse_str("1, 2").unwrap(),
            NumberOptionalNumber(1.0, 2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1 2").unwrap(),
            NumberOptionalNumber(1.0, 2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1").unwrap(),
            NumberOptionalNumber(1.0, 1.0)
        );

        assert_eq!(
            NumberOptionalNumber::parse_str("-1, -2").unwrap(),
            NumberOptionalNumber(-1.0, -2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1 -2").unwrap(),
            NumberOptionalNumber(-1.0, -2.0)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1").unwrap(),
            NumberOptionalNumber(-1.0, -1.0)
        );
    }

    #[test]
    fn invalid_number_optional_number() {
        assert!(NumberOptionalNumber::<f64>::parse_str("").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("x1").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 , x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 , 2x").is_err());
        assert!(NumberOptionalNumber::<f64>::parse_str("1 2 x").is_err());
    }

    #[test]
    fn parses_integer() {
        assert_eq!(i32::parse_str("1").unwrap(), 1);
        assert_eq!(i32::parse_str("-1").unwrap(), -1);
    }

    #[test]
    fn invalid_integer() {
        assert!(i32::parse_str("").is_err());
        assert!(i32::parse_str("1x").is_err());
        assert!(i32::parse_str("1.5").is_err());
    }

    #[test]
    fn parses_integer_optional_integer() {
        assert_eq!(
            NumberOptionalNumber::parse_str("1, 2").unwrap(),
            NumberOptionalNumber(1, 2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1 2").unwrap(),
            NumberOptionalNumber(1, 2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("1").unwrap(),
            NumberOptionalNumber(1, 1)
        );

        assert_eq!(
            NumberOptionalNumber::parse_str("-1, -2").unwrap(),
            NumberOptionalNumber(-1, -2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1 -2").unwrap(),
            NumberOptionalNumber(-1, -2)
        );
        assert_eq!(
            NumberOptionalNumber::parse_str("-1").unwrap(),
            NumberOptionalNumber(-1, -1)
        );
    }

    #[test]
    fn invalid_integer_optional_integer() {
        assert!(NumberOptionalNumber::<i32>::parse_str("").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("x1").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 , x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 , 2x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 2 x").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1.5").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1 2.5").is_err());
        assert!(NumberOptionalNumber::<i32>::parse_str("1, 2.5").is_err());
    }

    #[test]
    fn parses_custom_ident() {
        assert_eq!(
            CustomIdent::parse_str("hello").unwrap(),
            CustomIdent("hello".to_string())
        );
    }

    #[test]
    fn invalid_custom_ident_yields_error() {
        assert!(CustomIdent::parse_str("initial").is_err());
        assert!(CustomIdent::parse_str("inherit").is_err());
        assert!(CustomIdent::parse_str("unset").is_err());
        assert!(CustomIdent::parse_str("default").is_err());
        assert!(CustomIdent::parse_str("").is_err());
    }
}
<|endoftext|>


<commit_before>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => {
                            let jump_report = self.handle_jump_forward(vm, index);
                            index = jump_report.0;
                            self.status = jump_report.1;
                        }
                        Command::JumpBackward => index = self.handle_jump_backward(&vm, index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }
                self.instruction_pointer = Some(index);
            }

            (Some(index), ProgramStatus::Seeking(goal_depth)) => {
                let (new_index, new_status) = self.seek_forward(index, goal_depth);
                self.instruction_pointer = Some(new_index);
                self.status = new_status;
                self.execute(vm);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                return starting_index + 1;
            }
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                return index + 1;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {}
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal);
            }
        }
        return (self.instructions.len(), ProgramStatus::Seeking(goal_depth));
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match vm.cells[vm.data_pointer] {
            0 => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            }
            _ => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let actual = program.seek_forward(0, 0);
        let expected = (4, ProgramStatus::Normal);
        assert_eq!(actual, expected);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let actual = program.seek_forward(0, 0);
        let expected = (3, ProgramStatus::Seeking(0));
        assert_eq!(actual, expected);
    }
}
<commit_msg>Modify handle_jump_forward to be more comprehensive<commit_after>use command::Command;
use vm::VM;

pub struct Program {
    instructions: Vec<Command>,
    instruction_pointer: Option<usize>,
    current_depth: u64,
    pub status: ProgramStatus,
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ProgramStatus {
    Normal,
    Seeking(u64),
}

impl Program {
    pub fn new() -> Program {
        Program {
            instructions: Vec::new(),
            instruction_pointer: None,
            current_depth: 0,
            status: ProgramStatus::Normal,
        }
    }

    pub fn append(&mut self, instructions: &[Command]) {
        self.instructions.extend(instructions.iter().cloned());
        if self.instruction_pointer.is_none() {
            self.instruction_pointer = Some(0);
        }
    }

    pub fn execute(&mut self, vm: &mut VM) {
        match (self.instruction_pointer, self.status) {
            (Some(mut index), ProgramStatus::Normal) => {
                while index < self.instructions.len() {
                    match self.instructions[index] {
                        Command::JumpForward => {
                            let jump_report = self.handle_jump_forward(vm, index);
                            index = jump_report.0;
                            self.status = jump_report.1;
                        }
                        Command::JumpBackward => index = self.handle_jump_backward(&vm, index),
                        command => {
                            vm.apply(command);
                            index += 1;
                        }
                    }
                }
                self.instruction_pointer = Some(index);
            }

            (Some(index), ProgramStatus::Seeking(goal_depth)) => {
                let (new_index, new_status) = self.seek_forward(index, goal_depth);
                self.instruction_pointer = Some(new_index);
                self.status = new_status;
                self.execute(vm);
            }

            _ => {}
        }
    }

    fn handle_jump_backward(&mut self, vm: &VM, starting_index: usize) -> usize {
        match vm.cells[vm.data_pointer] {
            0 => {
                self.current_depth -= 1;
                return starting_index + 1;
            }
            _ => {
                let goal_depth = self.current_depth;
                for index in (0..starting_index).rev() {
                    match self.instructions[index] {
                        Command::JumpBackward => self.current_depth += 1,
                        Command::JumpForward => {
                            if self.current_depth == goal_depth {
                                return index + 1;
                            }
                            self.current_depth -= 1;
                        }
                        _ => {}
                    }
                }
                panic!("No starting brace found!");
            }
        }
    }

    fn seek_forward(&mut self, starting_index: usize, goal_depth: u64) -> (usize, ProgramStatus) {
        for index in starting_index..self.instructions.len() {
            match self.instructions[index] {
                Command::JumpForward => self.current_depth += 1,
                Command::JumpBackward => self.current_depth -= 1,
                _ => {}
            }
            if self.current_depth == goal_depth {
                return (index + 1, ProgramStatus::Normal);
            }
        }
        return (self.instructions.len(), ProgramStatus::Seeking(goal_depth));
    }

    fn handle_jump_forward(&mut self, vm: &VM, index: usize) -> (usize, ProgramStatus) {
        match (vm.cells[vm.data_pointer], self.status) {
            (0, ProgramStatus::Normal) => {
                let goal_depth = self.current_depth;
                return self.seek_forward(index, goal_depth);
            }

            (_, ProgramStatus::Normal) => {
                self.current_depth += 1;
                return (index + 1, ProgramStatus::Normal);
            }

            (_, ProgramStatus::Seeking(goal)) => {
                return self.seek_forward(index, goal);
            }

        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    pub fn test_seek_forward_normal() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
                Command::JumpBackward,
            ],
        };
        let actual = program.seek_forward(0, 0);
        let expected = (4, ProgramStatus::Normal);
        assert_eq!(actual, expected);
    }

    #[test]
    pub fn test_seek_forward_seeking() {
        let mut program = Program {
            instruction_pointer: Some(0),
            current_depth: 0,
            status: ProgramStatus::Normal,
            instructions: vec![
                Command::JumpForward,
                Command::JumpForward,
                Command::JumpBackward,
            ],
        };
        let actual = program.seek_forward(0, 0);
        let expected = (3, ProgramStatus::Seeking(0));
        assert_eq!(actual, expected);
    }
}
<|endoftext|>