<commit_before>use std::f32::consts::PI;
use std::sync::{Arc, Mutex, mpsc::{Sender, Receiver, TryRecvError}};

use cgmath::{Point3, Vector3, Vector4, prelude::*};

use glium::Rect;

use rand::{self, prelude::*};

use crate::bvh::BVHNode;
use crate::camera::Camera;
use crate::material::Material;
use crate::pt_renderer::{Intersect, Ray, RenderCoordinator};
use crate::scene::Scene;
use crate::triangle::{Hit, RTTriangle};

const EPSILON: f32 = 1e-5;
const _EB: f32 = 5.0; // Desired expectation value of bounces
// The matching survival probability from negative binomial distribution
const RR_PROB: f32 = _EB / (_EB + 1.0);

pub struct RenderWorker {
    scene: Arc<Scene>,
    camera: Camera,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    message_rx: Receiver<()>,
    result_tx: Sender<(Rect, Vec<f32>)>,
}

impl RenderWorker {
    pub fn new(scene: Arc<Scene>, camera: Camera, coordinator: Arc<Mutex<RenderCoordinator>>,
               message_rx: Receiver<()>, result_tx: Sender<(Rect, Vec<f32>)>) -> RenderWorker {
        RenderWorker {
            scene, camera, coordinator,
            message_rx, result_tx,
        }
    }

    pub fn run(&self) {
        let (width, height) = {
            let coordinator = self.coordinator.lock().unwrap();
            (coordinator.width, coordinator.height)
        };
        let clip_to_world = self.camera.get_world_to_clip().invert().unwrap();
        let mut node_stack: Vec<(&BVHNode, f32)> = Vec::new();
        loop {
            match self.message_rx.try_recv() {
                Err(TryRecvError::Empty) => (),
                Ok(_) => return,
                Err(TryRecvError::Disconnected) => {
                    println!("Threads were not properly stopped before disconnecting channel!");
                    return;
                }
            }
            if let Some(rect) = self.coordinator.lock().unwrap().next_block() {
                let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                for h in 0..rect.height {
                    for w in 0..rect.width {
                        let samples_per_dir = 2u32;
                        let mut c = Vector3::zero();
                        for j in 0..samples_per_dir {
                            for i in 0..samples_per_dir {
                                let dx = (i as f32 + rand::random::<f32>()) / samples_per_dir as f32;
                                let dy = (j as f32 + rand::random::<f32>()) / samples_per_dir as f32;
                                let clip_x = 2.0 * ((rect.left + w) as f32 + dx) / width as f32 - 1.0;
                                let clip_y = 2.0 * ((rect.bottom + h) as f32 + dy) / height as f32 - 1.0;
                                let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                                let world_p = clip_to_world * clip_p;
                                let dir = ((world_p / world_p.w).truncate() - self.camera.pos.to_vec())
                                    .normalize();
                                let ray = Ray::new(self.camera.pos, dir, 100.0);
                                c += self.trace_ray(&ray, &mut node_stack, 0);
                            }
                        }
                        c /= samples_per_dir.pow(2) as f32;
                        let pixel_i = 3 * (h * rect.width + w) as usize;
                        block[pixel_i]     = c.x;
                        block[pixel_i + 1] = c.y;
                        block[pixel_i + 2] = c.z;
                    }
                }
                self.result_tx.send((rect, block)).expect("Receiver closed!");
            } else {
                return;
            }
        }
    }

    fn trace_ray(&'a self, ray: &Ray, node_stack: &mut Vec<(&'a BVHNode, f32)>, bounce: u32) -> Vector3<f32> {
        let mut c = Vector3::zero();
        if let Some(hit) = self.find_hit(&ray, node_stack) {
            let material = &self.scene.materials[hit.tri.material_i];
            let mut normal = hit.normal();
            // Flip the normal if its pointing to the opposite side from the hit
            if normal.dot(ray.dir) > 0.0 {
                normal *= -1.0;
            }
            if bounce == 0 {
                if let Some(emissive) = material.emissive {
                    c += normal.dot(-ray.dir).max(0.0) * emissive;
                }
            }
            let (light, light_pos, light_normal, light_pdf) = self.sample_light();
            let bump_pos = hit.pos() + EPSILON * normal;
            let hit_to_light = light_pos - bump_pos;
            let light_dir = hit_to_light.normalize();
            let shadow_ray = Ray::new(bump_pos, light_dir, hit_to_light.magnitude() - EPSILON);
            if shadow_ray.length > 0.1 && self.find_hit(&shadow_ray, node_stack).is_none() {
                let cos_l = light_normal.dot(-light_dir).max(0.0);
                let cos_t = normal.dot(light_dir).max(0.0);
                let light_material = &self.scene.materials[light.material_i];
                let emissive = light_material.emissive.expect("Light wasn't emissive");
                c += emissive.mul_element_wise(self.brdf(&ray, &shadow_ray, material))
                    * cos_l * cos_t / (hit_to_light.magnitude2() * light_pdf);
            }
            let rr: f32 = rand::random();
            if rr < RR_PROB {
                let (new_dir, mut pdf) = self.sample_dir(normal);
                pdf *= RR_PROB;
                let new_ray = Ray::new(bump_pos, new_dir, 100.0);
                c += normal.dot(new_dir) * self.brdf(&ray, &new_ray, material)
                    .mul_element_wise(self.trace_ray(&new_ray, node_stack, bounce + 1)) / pdf;
            }
        }
        c
    }

    fn brdf(&self, _in_ray: &Ray, _out_ray: &Ray, material: &Material) -> Vector3<f32> {
        material.diffuse / PI
    }

    fn sample_dir(&self, normal: Vector3<f32>) -> (Vector3<f32>, f32) {
        let dir = 2.0 * PI * rand::random::<f32>();
        let length: f32 = rand::random();
        let x = length * dir.cos();
        let y = length * dir.sin();
        let z = (1.0 - length.powi(2)).sqrt();
        let nx = if normal.x.abs() > normal.y.abs() {
            Vector3::new(normal.z, 0.0, -normal.x).normalize()
        } else {
            Vector3::new(0.0, -normal.z, normal.y).normalize()
        };
        let ny = normal.cross(nx);
        (x * nx + y * ny + z * normal, z / PI)
    }

    pub fn sample_light(&self) -> (&RTTriangle, Point3<f32>, Vector3<f32>, f32) {
        if self.scene.lights.is_empty() {
            panic!("Rendered scene has no lights!");
        } else {
            let i = rand::thread_rng().gen_range(0, self.scene.lights.len());
            let light = &self.scene.lights[i];
            let pdf = 1.0 / (self.scene.lights.len() as f32 * light.area());
            let (point, normal) = light.random_point();
            (light, point, normal, pdf)
        }
    }

    fn find_hit(&'a self, ray: &Ray, node_stack: &mut Vec<(&'a BVHNode, f32)>) -> Option<Hit> {
        let bvh = &self.scene.bvh;
        node_stack.push((bvh.root(), 0.0f32));
        let mut closest_hit: Option<Hit> = None;
        while let Some((node, t)) = node_stack.pop() {
            // We've already found closer hit
            if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
            if node.is_leaf() {
                for tri in &self.scene.triangles[node.start_i..node.end_i] {
                    if let Some(hit) = tri.intersect(&ray) {
                        if let Some(closest) = closest_hit.take() {
                            if hit.t < closest.t {
                                closest_hit = Some(hit);
                            } else {
                                closest_hit = Some(closest);
                            }
                        } else {
                            closest_hit = Some(hit);
                        }
                    }
                }
            } else {
                // TODO: put closest hit on top of the stack
                let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
                if let Some(t_left) = left.intersect(&ray) {
                    node_stack.push((left, t_left));
                }
                if let Some(t_right) = right.intersect(&ray) {
                    node_stack.push((right, t_right));
                }
            }
        }
        closest_hit
    }
}
<commit_msg>Release lock properly after getting new block<commit_after>use std::f32::consts::PI;
use std::sync::{Arc, Mutex, mpsc::{Sender, Receiver, TryRecvError}};

use cgmath::{Point3, Vector3, Vector4, prelude::*};

use glium::Rect;

use rand::{self, prelude::*};

use crate::bvh::BVHNode;
use crate::camera::Camera;
use crate::material::Material;
use crate::pt_renderer::{Intersect, Ray, RenderCoordinator};
use crate::scene::Scene;
use crate::triangle::{Hit, RTTriangle};

const EPSILON: f32 = 1e-5;
const _EB: f32 = 5.0; // Desired expectation value of bounces
// The matching survival probability from negative binomial distribution
const RR_PROB: f32 = _EB / (_EB + 1.0);

pub struct RenderWorker {
    scene: Arc<Scene>,
    camera: Camera,
    coordinator: Arc<Mutex<RenderCoordinator>>,
    message_rx: Receiver<()>,
    result_tx: Sender<(Rect, Vec<f32>)>,
}

impl RenderWorker {
    pub fn new(scene: Arc<Scene>, camera: Camera, coordinator: Arc<Mutex<RenderCoordinator>>,
               message_rx: Receiver<()>, result_tx: Sender<(Rect, Vec<f32>)>) -> RenderWorker {
        RenderWorker {
            scene, camera, coordinator,
            message_rx, result_tx,
        }
    }

    pub fn run(&self) {
        let (width, height) = {
            let coordinator = self.coordinator.lock().unwrap();
            (coordinator.width, coordinator.height)
        };
        let clip_to_world = self.camera.get_world_to_clip().invert().unwrap();
        let mut node_stack: Vec<(&BVHNode, f32)> = Vec::new();
        loop {
            match self.message_rx.try_recv() {
                Err(TryRecvError::Empty) => (),
                Ok(_) => return,
                Err(TryRecvError::Disconnected) => {
                    println!("Threads were not properly stopped before disconnecting channel!");
                    return;
                }
            }
            let block = {
                let mut coordinator = self.coordinator.lock().unwrap();
                coordinator.next_block()
            };
            if let Some(rect) = block {
                let mut block = vec![0.0f32; (3 * rect.width * rect.height) as usize];
                for h in 0..rect.height {
                    for w in 0..rect.width {
                        let samples_per_dir = 2u32;
                        let mut c = Vector3::zero();
                        for j in 0..samples_per_dir {
                            for i in 0..samples_per_dir {
                                let dx = (i as f32 + rand::random::<f32>()) / samples_per_dir as f32;
                                let dy = (j as f32 + rand::random::<f32>()) / samples_per_dir as f32;
                                let clip_x = 2.0 * ((rect.left + w) as f32 + dx) / width as f32 - 1.0;
                                let clip_y = 2.0 * ((rect.bottom + h) as f32 + dy) / height as f32 - 1.0;
                                let clip_p = Vector4::new(clip_x, clip_y, 1.0, 1.0);
                                let world_p = clip_to_world * clip_p;
                                let dir = ((world_p / world_p.w).truncate() - self.camera.pos.to_vec())
                                    .normalize();
                                let ray = Ray::new(self.camera.pos, dir, 100.0);
                                c += self.trace_ray(&ray, &mut node_stack, 0);
                            }
                        }
                        c /= samples_per_dir.pow(2) as f32;
                        let pixel_i = 3 * (h * rect.width + w) as usize;
                        block[pixel_i]     = c.x;
                        block[pixel_i + 1] = c.y;
                        block[pixel_i + 2] = c.z;
                    }
                }
                self.result_tx.send((rect, block)).expect("Receiver closed!");
            } else {
                return;
            }
        }
    }

    fn trace_ray(&'a self, ray: &Ray, node_stack: &mut Vec<(&'a BVHNode, f32)>, bounce: u32) -> Vector3<f32> {
        let mut c = Vector3::zero();
        if let Some(hit) = self.find_hit(&ray, node_stack) {
            let material = &self.scene.materials[hit.tri.material_i];
            let mut normal = hit.normal();
            // Flip the normal if its pointing to the opposite side from the hit
            if normal.dot(ray.dir) > 0.0 {
                normal *= -1.0;
            }
            if bounce == 0 {
                if let Some(emissive) = material.emissive {
                    c += normal.dot(-ray.dir).max(0.0) * emissive;
                }
            }
            let (light, light_pos, light_normal, light_pdf) = self.sample_light();
            let bump_pos = hit.pos() + EPSILON * normal;
            let hit_to_light = light_pos - bump_pos;
            let light_dir = hit_to_light.normalize();
            let shadow_ray = Ray::new(bump_pos, light_dir, hit_to_light.magnitude() - EPSILON);
            if shadow_ray.length > 0.1 && self.find_hit(&shadow_ray, node_stack).is_none() {
                let cos_l = light_normal.dot(-light_dir).max(0.0);
                let cos_t = normal.dot(light_dir).max(0.0);
                let light_material = &self.scene.materials[light.material_i];
                let emissive = light_material.emissive.expect("Light wasn't emissive");
                c += emissive.mul_element_wise(self.brdf(&ray, &shadow_ray, material))
                    * cos_l * cos_t / (hit_to_light.magnitude2() * light_pdf);
            }
            let rr: f32 = rand::random();
            if rr < RR_PROB {
                let (new_dir, mut pdf) = self.sample_dir(normal);
                pdf *= RR_PROB;
                let new_ray = Ray::new(bump_pos, new_dir, 100.0);
                c += normal.dot(new_dir) * self.brdf(&ray, &new_ray, material)
                    .mul_element_wise(self.trace_ray(&new_ray, node_stack, bounce + 1)) / pdf;
            }
        }
        c
    }

    fn brdf(&self, _in_ray: &Ray, _out_ray: &Ray, material: &Material) -> Vector3<f32> {
        material.diffuse / PI
    }

    fn sample_dir(&self, normal: Vector3<f32>) -> (Vector3<f32>, f32) {
        let dir = 2.0 * PI * rand::random::<f32>();
        let length: f32 = rand::random();
        let x = length * dir.cos();
        let y = length * dir.sin();
        let z = (1.0 - length.powi(2)).sqrt();
        let nx = if normal.x.abs() > normal.y.abs() {
            Vector3::new(normal.z, 0.0, -normal.x).normalize()
        } else {
            Vector3::new(0.0, -normal.z, normal.y).normalize()
        };
        let ny = normal.cross(nx);
        (x * nx + y * ny + z * normal, z / PI)
    }

    pub fn sample_light(&self) -> (&RTTriangle, Point3<f32>, Vector3<f32>, f32) {
        if self.scene.lights.is_empty() {
            panic!("Rendered scene has no lights!");
        } else {
            let i = rand::thread_rng().gen_range(0, self.scene.lights.len());
            let light = &self.scene.lights[i];
            let pdf = 1.0 / (self.scene.lights.len() as f32 * light.area());
            let (point, normal) = light.random_point();
            (light, point, normal, pdf)
        }
    }

    fn find_hit(&'a self, ray: &Ray, node_stack: &mut Vec<(&'a BVHNode, f32)>) -> Option<Hit> {
        let bvh = &self.scene.bvh;
        node_stack.push((bvh.root(), 0.0f32));
        let mut closest_hit: Option<Hit> = None;
        while let Some((node, t)) = node_stack.pop() {
            // We've already found closer hit
            if closest_hit.as_ref().map_or(false, |hit| hit.t <= t) { continue }
            if node.is_leaf() {
                for tri in &self.scene.triangles[node.start_i..node.end_i] {
                    if let Some(hit) = tri.intersect(&ray) {
                        if let Some(closest) = closest_hit.take() {
                            if hit.t < closest.t {
                                closest_hit = Some(hit);
                            } else {
                                closest_hit = Some(closest);
                            }
                        } else {
                            closest_hit = Some(hit);
                        }
                    }
                }
            } else {
                // TODO: put closest hit on top of the stack
                let (left, right) = bvh.get_children(node).expect("Non leaf node had no child nodes!");
                if let Some(t_left) = left.intersect(&ray) {
                    node_stack.push((left, t_left));
                }
                if let Some(t_right) = right.intersect(&ray) {
                    node_stack.push((right, t_right));
                }
            }
        }
        closest_hit
    }
}
<|endoftext|>


<commit_before>// xfail-boot
// based on:
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java

fn main() {

    let vec[int] inputs = vec(
        50000
        //these segfault :(
        //500000,
        //5000000,
        //50000000
        );

    let vec[Body.props] bodies = NBodySystem.MakeNBodySystem();

    for (int n in inputs) {
        log NBodySystem.energy(bodies);

        let int i = 0;
        while (i < n) {
            NBodySystem.advance(bodies, 0.01);
            i += 1;
        }
        log NBodySystem.energy(bodies);
    }
}

// making a native call to sqrt
native "rust" mod rustrt {
    fn squareroot(&float input, &mutable float output);
}

// Body.props is a record of floats, so
// vec[Body.props] is a vector of records of floats

mod NBodySystem {

    fn MakeNBodySystem() -> vec[Body.props] {
        let vec[Body.props] bodies = vec(
            // these each return a Body.props
            Body.sun(),
            Body.jupiter(),
            Body.saturn(),
            Body.uranus(),
            Body.neptune());

        let float px = 0.0;
        let float py = 0.0;
        let float pz = 0.0;

        let int i = 0;
        while (i < 5) {
            px += bodies.(i).vx * bodies.(i).mass;
            py += bodies.(i).vy * bodies.(i).mass;
            pz += bodies.(i).vz * bodies.(i).mass;

            i += 1;
        }

        // side-effecting
        Body.offsetMomentum(bodies.(0), px, py, pz);

        ret bodies;
    }

    fn advance(vec[Body.props] bodies, float dt) -> () {

        let int i = 0;
        while (i < 5) {
            let int j = i+1;
            while (j < 5) {
                advance_one(bodies.(i), bodies.(j), dt);
                j += 1;
            }

            i += 1;
        }

        i = 0;
        while (i < 5) {

            bodies.(i).x += dt * bodies.(i).vx;
            bodies.(i).y += dt * bodies.(i).vy;
            bodies.(i).z += dt * bodies.(i).vz;

            i += 1;
        }
    }

    fn advance_one(&Body.props bi, &Body.props bj, float dt) {
        let float dx = bi.x - bj.x;
        let float dy = bi.y - bj.y;
        let float dz = bi.z - bj.z;

        let float dSquared = dx * dx + dy * dy + dz * dz;

        let float distance;
        rustrt.squareroot(dSquared, distance);
        let float mag = dt / (dSquared * distance);

        bi.vx -= dx * bj.mass * mag;
        bi.vy -= dy * bj.mass * mag;
        bi.vz -= dz * bj.mass * mag;

        bj.vx += dx * bi.mass * mag;
        bj.vy += dy * bi.mass * mag;
        bj.vz += dz * bi.mass * mag;
    }

    fn energy(vec[Body.props] bodies) -> float {
        let float dx;
        let float dy;
        let float dz;
        let float distance;
        let float e = 0.0;

        let int i = 0;
        while (i < 5) {
            e += 0.5 * bodies.(i).mass *
                (  bodies.(i).vx * bodies.(i).vx
                 + bodies.(i).vy * bodies.(i).vy
                 + bodies.(i).vz * bodies.(i).vz );

            let int j = i+1;
            while (j < 5) {
                dx = bodies.(i).x - bodies.(j).x;
                dy = bodies.(i).y - bodies.(j).y;
                dz = bodies.(i).z - bodies.(j).z;

                rustrt.squareroot(dx*dx + dy*dy + dz*dz, distance);
                e -= (bodies.(i).mass * bodies.(j).mass) / distance;

                j += 1;
            }

            i += 1;
        }
        ret e;

    }
}

mod Body {

    const float PI = 3.141592653589793;
    const float SOLAR_MASS = 39.478417604357432; // was 4 * PI * PI originally
    const float DAYS_PER_YEAR = 365.24;

    type props = rec(mutable float x,
                     mutable float y,
                     mutable float z,
                     mutable float vx,
                     mutable float vy,
                     mutable float vz,
                     float mass);

    fn jupiter() -> Body.props {
        ret rec(
            mutable x  =  4.84143144246472090e+00,
            mutable y  = -1.16032004402742839e+00,
            mutable z  = -1.03622044471123109e-01,
            mutable vx =  1.66007664274403694e-03 * DAYS_PER_YEAR,
            mutable vy =  7.69901118419740425e-03 * DAYS_PER_YEAR,
            mutable vz = -6.90460016972063023e-05 * DAYS_PER_YEAR,
            mass       =  9.54791938424326609e-04 * SOLAR_MASS
            );
    }

    fn saturn() -> Body.props {
        ret rec(
            mutable x  =  8.34336671824457987e+00,
            mutable y  =  4.12479856412430479e+00,
            mutable z  = -4.03523417114321381e-01,
            mutable vx = -2.76742510726862411e-03 * DAYS_PER_YEAR,
            mutable vy =  4.99852801234917238e-03 * DAYS_PER_YEAR,
            mutable vz =  2.30417297573763929e-05 * DAYS_PER_YEAR,
            mass       =  2.85885980666130812e-04 * SOLAR_MASS
            );
   }

    fn uranus() -> Body.props {
        ret rec(
            mutable x  =  1.28943695621391310e+01,
            mutable y  = -1.51111514016986312e+01,
            mutable z  = -2.23307578892655734e-01,
            mutable vx =  2.96460137564761618e-03 * DAYS_PER_YEAR,
            mutable vy =  2.37847173959480950e-03 * DAYS_PER_YEAR,
            mutable vz = -2.96589568540237556e-05 * DAYS_PER_YEAR,
            mass       =  4.36624404335156298e-05 * SOLAR_MASS
            );
    }

    fn neptune() -> Body.props {
        ret rec(
            mutable x  =  1.53796971148509165e+01,
            mutable y  = -2.59193146099879641e+01,
            mutable z  =  1.79258772950371181e-01,
            mutable vx =  2.68067772490389322e-03 * DAYS_PER_YEAR,
            mutable vy =  1.62824170038242295e-03 * DAYS_PER_YEAR,
            mutable vz = -9.51592254519715870e-05 * DAYS_PER_YEAR,
            mass       =  5.15138902046611451e-05 * SOLAR_MASS
            );
   }

   fn sun() -> Body.props {
       ret rec(
           mutable x  =  0.0,
           mutable y  =  0.0,
           mutable z  =  0.0,
           mutable vx =  0.0,
           mutable vy =  0.0,
           mutable vz =  0.0,
           mass       =  SOLAR_MASS
           );
   }

   impure fn offsetMomentum(&Body.props props,
                            float px,
                            float py,
                            float pz) -> () {
       props.vx = -px / SOLAR_MASS;
       props.vy = -py / SOLAR_MASS;
       props.vz = -pz / SOLAR_MASS;
   }

}
<commit_msg>shootout: Hoist out the movement too; switch square root to an LLVM intrinsic<commit_after>// xfail-boot
// based on:
// http://shootout.alioth.debian.org/u32/benchmark.php?test=nbody&lang=java

native "llvm" mod llvm {
    fn sqrt(float n) -> float = "sqrt.f64";
}

fn main() {

    let vec[int] inputs = vec(
        50000
        //these segfault :(
        //500000,
        //5000000,
        //50000000
        );

    let vec[Body.props] bodies = NBodySystem.MakeNBodySystem();

    for (int n in inputs) {
        log NBodySystem.energy(bodies);

        let int i = 0;
        while (i < n) {
            NBodySystem.advance(bodies, 0.01);
            i += 1;
        }
        log NBodySystem.energy(bodies);
    }
}

// Body.props is a record of floats, so
// vec[Body.props] is a vector of records of floats

mod NBodySystem {

    fn MakeNBodySystem() -> vec[Body.props] {
        let vec[Body.props] bodies = vec(
            // these each return a Body.props
            Body.sun(),
            Body.jupiter(),
            Body.saturn(),
            Body.uranus(),
            Body.neptune());

        let float px = 0.0;
        let float py = 0.0;
        let float pz = 0.0;

        let int i = 0;
        while (i < 5) {
            px += bodies.(i).vx * bodies.(i).mass;
            py += bodies.(i).vy * bodies.(i).mass;
            pz += bodies.(i).vz * bodies.(i).mass;

            i += 1;
        }

        // side-effecting
        Body.offsetMomentum(bodies.(0), px, py, pz);

        ret bodies;
    }

    fn advance(vec[Body.props] bodies, float dt) -> () {

        let int i = 0;
        while (i < 5) {
            let int j = i+1;
            while (j < 5) {
                advance_one(bodies.(i), bodies.(j), dt);
                j += 1;
            }

            i += 1;
        }

        i = 0;
        while (i < 5) {
            move(bodies.(i), dt);
            i += 1;
        }
    }

    fn advance_one(&Body.props bi, &Body.props bj, float dt) {
        let float dx = bi.x - bj.x;
        let float dy = bi.y - bj.y;
        let float dz = bi.z - bj.z;

        let float dSquared = dx * dx + dy * dy + dz * dz;

        let float distance = llvm.sqrt(dSquared);
        let float mag = dt / (dSquared * distance);

        bi.vx -= dx * bj.mass * mag;
        bi.vy -= dy * bj.mass * mag;
        bi.vz -= dz * bj.mass * mag;

        bj.vx += dx * bi.mass * mag;
        bj.vy += dy * bi.mass * mag;
        bj.vz += dz * bi.mass * mag;
    }

    fn move(&Body.props b, float dt) {
        b.x += dt * b.vx;
        b.y += dt * b.vy;
        b.z += dt * b.vz;
    }

    fn energy(vec[Body.props] bodies) -> float {
        let float dx;
        let float dy;
        let float dz;
        let float distance;
        let float e = 0.0;

        let int i = 0;
        while (i < 5) {
            e += 0.5 * bodies.(i).mass *
                (  bodies.(i).vx * bodies.(i).vx
                 + bodies.(i).vy * bodies.(i).vy
                 + bodies.(i).vz * bodies.(i).vz );

            let int j = i+1;
            while (j < 5) {
                dx = bodies.(i).x - bodies.(j).x;
                dy = bodies.(i).y - bodies.(j).y;
                dz = bodies.(i).z - bodies.(j).z;

                distance = llvm.sqrt(dx*dx + dy*dy + dz*dz);
                e -= (bodies.(i).mass * bodies.(j).mass) / distance;

                j += 1;
            }

            i += 1;
        }
        ret e;

    }
}

mod Body {

    const float PI = 3.141592653589793;
    const float SOLAR_MASS = 39.478417604357432; // was 4 * PI * PI originally
    const float DAYS_PER_YEAR = 365.24;

    type props = rec(mutable float x,
                     mutable float y,
                     mutable float z,
                     mutable float vx,
                     mutable float vy,
                     mutable float vz,
                     float mass);

    fn jupiter() -> Body.props {
        ret rec(
            mutable x  =  4.84143144246472090e+00,
            mutable y  = -1.16032004402742839e+00,
            mutable z  = -1.03622044471123109e-01,
            mutable vx =  1.66007664274403694e-03 * DAYS_PER_YEAR,
            mutable vy =  7.69901118419740425e-03 * DAYS_PER_YEAR,
            mutable vz = -6.90460016972063023e-05 * DAYS_PER_YEAR,
            mass       =  9.54791938424326609e-04 * SOLAR_MASS
            );
    }

    fn saturn() -> Body.props {
        ret rec(
            mutable x  =  8.34336671824457987e+00,
            mutable y  =  4.12479856412430479e+00,
            mutable z  = -4.03523417114321381e-01,
            mutable vx = -2.76742510726862411e-03 * DAYS_PER_YEAR,
            mutable vy =  4.99852801234917238e-03 * DAYS_PER_YEAR,
            mutable vz =  2.30417297573763929e-05 * DAYS_PER_YEAR,
            mass       =  2.85885980666130812e-04 * SOLAR_MASS
            );
   }

    fn uranus() -> Body.props {
        ret rec(
            mutable x  =  1.28943695621391310e+01,
            mutable y  = -1.51111514016986312e+01,
            mutable z  = -2.23307578892655734e-01,
            mutable vx =  2.96460137564761618e-03 * DAYS_PER_YEAR,
            mutable vy =  2.37847173959480950e-03 * DAYS_PER_YEAR,
            mutable vz = -2.96589568540237556e-05 * DAYS_PER_YEAR,
            mass       =  4.36624404335156298e-05 * SOLAR_MASS
            );
    }

    fn neptune() -> Body.props {
        ret rec(
            mutable x  =  1.53796971148509165e+01,
            mutable y  = -2.59193146099879641e+01,
            mutable z  =  1.79258772950371181e-01,
            mutable vx =  2.68067772490389322e-03 * DAYS_PER_YEAR,
            mutable vy =  1.62824170038242295e-03 * DAYS_PER_YEAR,
            mutable vz = -9.51592254519715870e-05 * DAYS_PER_YEAR,
            mass       =  5.15138902046611451e-05 * SOLAR_MASS
            );
   }

   fn sun() -> Body.props {
       ret rec(
           mutable x  =  0.0,
           mutable y  =  0.0,
           mutable z  =  0.0,
           mutable vx =  0.0,
           mutable vy =  0.0,
           mutable vz =  0.0,
           mass       =  SOLAR_MASS
           );
   }

   impure fn offsetMomentum(&Body.props props,
                            float px,
                            float py,
                            float pz) -> () {
       props.vx = -px / SOLAR_MASS;
       props.vy = -py / SOLAR_MASS;
       props.vz = -pz / SOLAR_MASS;
   }

}
<|endoftext|>


<commit_before>// xfail-test
// xfail-pretty
// xfail-win32

use std;
import std::timer::sleep;
import std::uv;

import pipes::{recv, select};

proto! oneshot {
    waiting:send {
        signal -> signaled
    }

    signaled:send { }
}

proto! stream {
    stream:send<T:send> {
        send(T) -> stream<T>
    }
}

fn main() {
    import oneshot::client::*;
    import stream::client::*;

    let iotask = uv::global_loop::get();

    let c = pipes::spawn_service(stream::init, |p| {
        #error("waiting for pipes");
        let stream::send(x, p) = recv(p);
        #error("got pipes");
        let (left, right) : (oneshot::server::waiting,
                             oneshot::server::waiting)
            = x;
        #error("selecting");
        let (i, _, _) = select(~[left, right]);
        #error("selected");
        assert i == 0;

        #error("waiting for pipes");
        let stream::send(x, _) = recv(p);
        #error("got pipes");
        let (left, right) : (oneshot::server::waiting,
                             oneshot::server::waiting)
            = x;
        #error("selecting");
        let (i, _, _) = select(~[left, right]);
        #error("selected");
        assert i == 1;
    });

    let (c1, p1) = oneshot::init();
    let (_c2, p2) = oneshot::init();

    let c = send(c, (p1, p2));

    sleep(iotask, 1000);

    signal(c1);

    let (_c1, p1) = oneshot::init();
    let (c2, p2) = oneshot::init();

    send(c, (p1, p2));

    sleep(iotask, 1000);

    signal(c2);

    test_select2();
}

fn test_select2() {
    let (ac, ap) = stream::init();
    let (bc, bp) = stream::init();

    stream::client::send(ac, 42);

    alt pipes::select2(ap, bp) {
      either::left(*) { }
      either::right(*) { fail }
    }

    stream::client::send(bc, "abc");

    #error("done with first select2");

    let (ac, ap) = stream::init();
    let (bc, bp) = stream::init();

    stream::client::send(bc, "abc");

    alt pipes::select2(ap, bp) {
      either::left(*) { fail }
      either::right(*) { }
    }

    stream::client::send(ac, 42);
}
<commit_msg>Fix hang in pipe-select when RUST_THREADS=1<commit_after>// xfail-test
// xfail-pretty
// xfail-win32

use std;
import std::timer::sleep;
import std::uv;

import pipes::{recv, select};

proto! oneshot {
    waiting:send {
        signal -> signaled
    }

    signaled:send { }
}

proto! stream {
    stream:send<T:send> {
        send(T) -> stream<T>
    }
}

fn main() {
    import oneshot::client::*;
    import stream::client::*;

    let iotask = uv::global_loop::get();

    let c = pipes::spawn_service(stream::init, |p| {
        #error("waiting for pipes");
        let stream::send(x, p) = recv(p);
        #error("got pipes");
        let (left, right) : (oneshot::server::waiting,
                             oneshot::server::waiting)
            = x;
        #error("selecting");
        let (i, _, _) = select(~[left, right]);
        #error("selected");
        assert i == 0;

        #error("waiting for pipes");
        let stream::send(x, _) = recv(p);
        #error("got pipes");
        let (left, right) : (oneshot::server::waiting,
                             oneshot::server::waiting)
            = x;
        #error("selecting");
        let (i, m, _) = select(~[left, right]);
        #error("selected %?", i);
        if m != none {
            assert i == 1;
        }
    });

    let (c1, p1) = oneshot::init();
    let (_c2, p2) = oneshot::init();

    let c = send(c, (p1, p2));

    sleep(iotask, 100);

    signal(c1);

    let (_c1, p1) = oneshot::init();
    let (c2, p2) = oneshot::init();

    send(c, (p1, p2));

    sleep(iotask, 100);

    signal(c2);

    test_select2();
}

fn test_select2() {
    let (ac, ap) = stream::init();
    let (bc, bp) = stream::init();

    stream::client::send(ac, 42);

    alt pipes::select2(ap, bp) {
      either::left(*) { }
      either::right(*) { fail }
    }

    stream::client::send(bc, "abc");

    #error("done with first select2");

    let (ac, ap) = stream::init();
    let (bc, bp) = stream::init();

    stream::client::send(bc, "abc");

    alt pipes::select2(ap, bp) {
      either::left(*) { fail }
      either::right(*) { }
    }

    stream::client::send(ac, 42);
}
<|endoftext|>


<commit_before>use std::iter::FromIterator;

pub struct SimpleLinkedList<T> {
    // Delete this field
    // dummy is needed to avoid unused parameter error during compilation
    dummy: ::std::marker::PhantomData<T>,
}

impl<T> SimpleLinkedList<T> {
    pub fn new() -> Self {
        unimplemented!()
    }

    pub fn len(&self) -> usize {
        unimplemented!()
    }

    pub fn push(&mut self, _element: T) {
        unimplemented!()
    }

    pub fn pop(&mut self) -> Option<T> {
        unimplemented!()
    }

    pub fn peek(&self) -> Option<&T> {
        unimplemented!()
    }

    pub fn rev(self) -> SimpleLinkedList<T> {
        unimplemented!()
    }
}

impl<T> FromIterator<T> for SimpleLinkedList<T> {
    fn from_iter<I: IntoIterator<Item = T>>(_iter: I) -> Self {
        unimplemented!()
    }
}

impl<T> Into<Vec<T>> for SimpleLinkedList<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }
}
<commit_msg>add note explaining the difference between an ideal API and the exercise's<commit_after>use std::iter::FromIterator;

pub struct SimpleLinkedList<T> {
    // Delete this field
    // dummy is needed to avoid unused parameter error during compilation
    dummy: ::std::marker::PhantomData<T>,
}

impl<T> SimpleLinkedList<T> {
    pub fn new() -> Self {
        unimplemented!()
    }

    pub fn len(&self) -> usize {
        unimplemented!()
    }

    pub fn push(&mut self, _element: T) {
        unimplemented!()
    }

    pub fn pop(&mut self) -> Option<T> {
        unimplemented!()
    }

    pub fn peek(&self) -> Option<&T> {
        unimplemented!()
    }

    pub fn rev(self) -> SimpleLinkedList<T> {
        unimplemented!()
    }
}

impl<T> FromIterator<T> for SimpleLinkedList<T> {
    fn from_iter<I: IntoIterator<Item = T>>(_iter: I) -> Self {
        unimplemented!()
    }
}

// In general, it would be preferable to implement IntoIterator for SimpleLinkedList<T>
// instead of implementing an explicit conversion to a vector. This is because, together,
// FromIterator and IntoIterator enable conversion between arbitrary collections.
// Given that implementation, converting to a vector is trivial:
//
// let vec: Vec<_> = simple_linked_list.into_iter().collect();
//
// The reason this exercise's API includes an explicit conversion to Vec<T> instead
// of IntoIterator is that implementing that interface is fairly complicated, and
// demands more of the student than we expect at this point in the track.

impl<T> Into<Vec<T>> for SimpleLinkedList<T> {
    fn into(self) -> Vec<T> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>extern crate multiaddr;

use multiaddr::*;

#[test]
fn protocols_to_u16() {
    assert_eq!(ProtocolTypes::TCP.to_code(), 6u16);
}

#[test]
fn protocols_from_u16() {
    assert_eq!(ProtocolTypes::from_code(6u16), Some(ProtocolTypes::TCP));
    assert_eq!(ProtocolTypes::from_code(455u16), None);
}

#[test]
fn protocols_to_size() {
    assert_eq!(ProtocolTypes::TCP.to_size(), 16);
}

#[test]
fn protocols_to_name() {
    assert_eq!(ProtocolTypes::TCP.to_name(), "tcp");
}

#[test]
fn multiaddr_eq() {
    assert!(
        Multiaddr::new("/ip4/127.0.0.1").unwrap() == Multiaddr::new("/ip4/127.0.0.1").unwrap()
    );
    assert!(
        Multiaddr::new("/ip4/127.0.0.1").unwrap() != Multiaddr::new("/ip4/128.0.0.1").unwrap()
    );
}

fn assert_bytes(source: &str, target: &[u8], protocols: Vec<ProtocolTypes>) -> () {
    let address = Multiaddr::new(source).unwrap();
    println!("source {:?}, target {:?}", source, target);
    assert_eq!(address.to_bytes(), target);
    assert_eq!(address.protocols(), protocols);
}

#[test]
fn byte_formats() {
    assert_bytes("/ip4/1.2.3.4", &[0, 4, 1, 2, 3, 4], vec![ProtocolTypes::IP4]);
    assert_bytes("/ip4/0.0.0.0", &[0, 4, 0, 0, 0, 0], vec![ProtocolTypes::IP4]);
    assert_bytes("/ip6/::1", &[
        0, 41,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
    ], vec![ProtocolTypes::IP6]);
    assert_bytes("/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", &[
        0, 41,
        38, 1, 0, 9, 79, 129, 151, 0, 128, 62, 202, 101, 102, 232, 12, 33
    ], vec![ProtocolTypes::IP6]);
    // assert_bytes("/onion/timaq4ygg2iegci7:1234", &[], vec![ProtocolTypes::Onion]);
    // assert_bytes("/onion/timaq4ygg2iegci7:80/http", &[], vec![ProtocolTypes::Onion]);
    assert_bytes("/udp/0", &[0, 17, 0, 0], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/0", &[0, 6, 0, 0], vec![ProtocolTypes::TCP]);
    assert_bytes("/sctp/0", &[0, 132, 0, 0], vec![ProtocolTypes::SCTP]);
    assert_bytes("/udp/1234", &[0, 17, 4, 210], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/1234", &[0, 6, 4, 210], vec![ProtocolTypes::TCP]);
    assert_bytes("/sctp/1234", &[0, 132, 4, 210], vec![ProtocolTypes::SCTP]);
    assert_bytes("/udp/65535", &[0, 17, 255, 255], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/65535", &[0, 6, 255, 255], vec![ProtocolTypes::TCP]);
    // assert_bytes("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", &[], vec![ProtocolTypes::IPFS]);
    assert_bytes("/udp/1234/sctp/1234", &[
        0, 17, 4, 210,
        0, 132, 4, 210
    ], vec![ProtocolTypes::UDP, ProtocolTypes::SCTP]);
    assert_bytes("/udp/1234/udt", &[
        0, 17, 4, 210,
        1, 46
    ], vec![ProtocolTypes::UDP, ProtocolTypes::UDT]);
    assert_bytes("/udp/1234/utp", &[
        0, 17, 4, 210,
        1, 45
    ], vec![ProtocolTypes::UDP, ProtocolTypes::UTP]);
    assert_bytes("/tcp/1234/http", &[
        0, 6, 4, 210,
        1, 224
    ], vec![ProtocolTypes::TCP, ProtocolTypes::HTTP]);
    assert_bytes("/tcp/1234/https", &[
        0, 6, 4, 210,
        1, 187
    ], vec![ProtocolTypes::TCP, ProtocolTypes::HTTPS]);
    // assert_bytes("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", &[
    // ], vec![ProtocolTypes::IPFS, ProtocolTypes::TCP]);
    assert_bytes("/ip4/127.0.0.1/udp/1234", &[
        0, 4, 127, 0, 0, 1,
        0, 17, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::UDP]);
    assert_bytes("/ip4/127.0.0.1/udp/0", &[
        0, 4, 127, 0, 0, 1,
        0, 17, 0, 0
    ], vec![ProtocolTypes::IP4, ProtocolTypes::UDP]);
    assert_bytes("/ip4/127.0.0.1/tcp/1234", &[
        0, 4, 127, 0, 0, 1,
        0, 6, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::TCP]);
    assert_bytes("/ip4/127.0.0.1/tcp/1234/", &[
        0, 4, 127, 0, 0, 1,
        0, 6, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::TCP]);
    // assert_bytes("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", &[], vec![]);
    // assert_bytes("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", &[], vec![]);
}
<commit_msg>Add failure tests<commit_after>extern crate multiaddr;

use multiaddr::*;

#[test]
fn protocols_to_u16() {
    assert_eq!(ProtocolTypes::TCP.to_code(), 6u16);
}

#[test]
fn protocols_from_u16() {
    assert_eq!(ProtocolTypes::from_code(6u16), Some(ProtocolTypes::TCP));
    assert_eq!(ProtocolTypes::from_code(455u16), None);
}

#[test]
fn protocols_to_size() {
    assert_eq!(ProtocolTypes::TCP.to_size(), 16);
}

#[test]
fn protocols_to_name() {
    assert_eq!(ProtocolTypes::TCP.to_name(), "tcp");
}

#[test]
fn multiaddr_eq() {
    assert!(
        Multiaddr::new("/ip4/127.0.0.1").unwrap() == Multiaddr::new("/ip4/127.0.0.1").unwrap()
    );
    assert!(
        Multiaddr::new("/ip4/127.0.0.1").unwrap() != Multiaddr::new("/ip4/128.0.0.1").unwrap()
    );
}

fn assert_bytes(source: &str, target: &[u8], protocols: Vec<ProtocolTypes>) -> () {
    let address = Multiaddr::new(source).unwrap();
    println!("source {:?}, target {:?}", source, target);
    assert_eq!(address.to_bytes(), target);
    assert_eq!(address.protocols(), protocols);
}

#[test]
fn byte_formats() {
    assert_bytes("/ip4/1.2.3.4", &[0, 4, 1, 2, 3, 4], vec![ProtocolTypes::IP4]);
    assert_bytes("/ip4/0.0.0.0", &[0, 4, 0, 0, 0, 0], vec![ProtocolTypes::IP4]);
    assert_bytes("/ip6/::1", &[
        0, 41,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
    ], vec![ProtocolTypes::IP6]);
    assert_bytes("/ip6/2601:9:4f81:9700:803e:ca65:66e8:c21", &[
        0, 41,
        38, 1, 0, 9, 79, 129, 151, 0, 128, 62, 202, 101, 102, 232, 12, 33
    ], vec![ProtocolTypes::IP6]);
    // assert_bytes("/onion/timaq4ygg2iegci7:1234", &[], vec![ProtocolTypes::Onion]);
    // assert_bytes("/onion/timaq4ygg2iegci7:80/http", &[], vec![ProtocolTypes::Onion]);
    assert_bytes("/udp/0", &[0, 17, 0, 0], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/0", &[0, 6, 0, 0], vec![ProtocolTypes::TCP]);
    assert_bytes("/sctp/0", &[0, 132, 0, 0], vec![ProtocolTypes::SCTP]);
    assert_bytes("/udp/1234", &[0, 17, 4, 210], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/1234", &[0, 6, 4, 210], vec![ProtocolTypes::TCP]);
    assert_bytes("/sctp/1234", &[0, 132, 4, 210], vec![ProtocolTypes::SCTP]);
    assert_bytes("/udp/65535", &[0, 17, 255, 255], vec![ProtocolTypes::UDP]);
    assert_bytes("/tcp/65535", &[0, 6, 255, 255], vec![ProtocolTypes::TCP]);
    // assert_bytes("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", &[], vec![ProtocolTypes::IPFS]);
    assert_bytes("/udp/1234/sctp/1234", &[
        0, 17, 4, 210,
        0, 132, 4, 210
    ], vec![ProtocolTypes::UDP, ProtocolTypes::SCTP]);
    assert_bytes("/udp/1234/udt", &[
        0, 17, 4, 210,
        1, 46
    ], vec![ProtocolTypes::UDP, ProtocolTypes::UDT]);
    assert_bytes("/udp/1234/utp", &[
        0, 17, 4, 210,
        1, 45
    ], vec![ProtocolTypes::UDP, ProtocolTypes::UTP]);
    assert_bytes("/tcp/1234/http", &[
        0, 6, 4, 210,
        1, 224
    ], vec![ProtocolTypes::TCP, ProtocolTypes::HTTP]);
    assert_bytes("/tcp/1234/https", &[
        0, 6, 4, 210,
        1, 187
    ], vec![ProtocolTypes::TCP, ProtocolTypes::HTTPS]);
    // assert_bytes("/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", &[
    // ], vec![ProtocolTypes::IPFS, ProtocolTypes::TCP]);
    assert_bytes("/ip4/127.0.0.1/udp/1234", &[
        0, 4, 127, 0, 0, 1,
        0, 17, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::UDP]);
    assert_bytes("/ip4/127.0.0.1/udp/0", &[
        0, 4, 127, 0, 0, 1,
        0, 17, 0, 0
    ], vec![ProtocolTypes::IP4, ProtocolTypes::UDP]);
    assert_bytes("/ip4/127.0.0.1/tcp/1234", &[
        0, 4, 127, 0, 0, 1,
        0, 6, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::TCP]);
    assert_bytes("/ip4/127.0.0.1/tcp/1234/", &[
        0, 4, 127, 0, 0, 1,
        0, 6, 4, 210
    ], vec![ProtocolTypes::IP4, ProtocolTypes::TCP]);
    // assert_bytes("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC", &[], vec![]);
    // assert_bytes("/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234", &[], vec![]);
}

#[test]
fn multiaddr_new_fail() {
    let addresses = [
        "/ip4",
	"/ip4/::1",
	"/ip4/fdpsofodsajfdoisa",
	"/ip6",
	"/udp",
	"/tcp",
	"/sctp",
	"/udp/65536",
	"/tcp/65536",
	"/onion/9imaq4ygg2iegci7:80",
	"/onion/aaimaq4ygg2iegci7:80",
	"/onion/timaq4ygg2iegci7:0",
	"/onion/timaq4ygg2iegci7:-1",
	"/onion/timaq4ygg2iegci7",
	"/onion/timaq4ygg2iegci@:666",
	"/udp/1234/sctp",
	"/udp/1234/udt/1234",
	"/udp/1234/utp/1234",
	"/ip4/127.0.0.1/udp/jfodsajfidosajfoidsa",
	"/ip4/127.0.0.1/udp",
	"/ip4/127.0.0.1/tcp/jfodsajfidosajfoidsa",
	"/ip4/127.0.0.1/tcp",
	"/ip4/127.0.0.1/ipfs",
	"/ip4/127.0.0.1/ipfs/tcp",
    ];

    for address in &addresses {
        assert!(Multiaddr::new(address).is_err());
    }
}
<|endoftext|>


<commit_before>extern crate rdb;
use rdb::*;
use std::io::MemReader;

#[test]
fn test_read_length() {
    assert_eq!(
        (0, false),
        read_length_with_encoding(&mut MemReader::new(vec!(0x0)))
        );

    assert_eq!(
        (16383, false),
        read_length_with_encoding(&mut MemReader::new(vec!(0x7f, 0xff)))
        );

    assert_eq!(
        (4294967295, false),
        read_length_with_encoding(&mut MemReader::new(
                vec!(0x80, 0xff, 0xff, 0xff, 0xff)))
        );

    assert_eq!(
        (0, true),
        read_length_with_encoding(&mut MemReader::new(vec!(0xC0))));

    assert_eq!(
        16383,
        read_length(&mut MemReader::new(vec!(0x7f, 0xff)))
        );
}

#[test]
fn test_read_blob() {
    assert_eq!(
        vec!(0x61, 0x62, 0x63, 0x64),
        read_blob(&mut MemReader::new(vec!(4, 0x61, 0x62, 0x63, 0x64))));
}

#[test]
fn test_verify_version() {
    let mut parser = RdbParser::new(MemReader::new(vec![0x30, 0x30, 0x30, 0x33]), NilFormatter);
    assert_eq!(
        true,
        parser.verify_version());

    let mut parser = RdbParser::new(MemReader::new(vec![0x30, 0x30, 0x30, 0x3a]), NilFormatter);
    assert_eq!(
        false,
        parser.verify_version());
}

#[test]
fn test_verify_magic() {
    let mut parser = RdbParser::new(MemReader::new(vec![0x52, 0x45, 0x44, 0x49, 0x53]), NilFormatter);
    assert_eq!(
        true,
        parser.verify_magic());

    let mut parser = RdbParser::new(MemReader::new(vec![0x51, 0x0, 0x0, 0x0, 0x0]), NilFormatter);
    assert_eq!(
        false,
        parser.verify_magic());
}
<commit_msg>Adjust tests to new API<commit_after>#![allow(unstable)]
extern crate rdb;
use std::io::MemReader;
use rdb::{
    read_length,
    read_length_with_encoding,
    verify_magic,
    verify_version,
    read_blob
};

#[test]
fn test_read_length() {
    assert_eq!(
        (0, false),
        read_length_with_encoding(&mut MemReader::new(vec!(0x0)))
        );

    assert_eq!(
        (16383, false),
        read_length_with_encoding(&mut MemReader::new(vec!(0x7f, 0xff)))
        );

    assert_eq!(
        (4294967295, false),
        read_length_with_encoding(&mut MemReader::new(
                vec!(0x80, 0xff, 0xff, 0xff, 0xff)))
        );

    assert_eq!(
        (0, true),
        read_length_with_encoding(&mut MemReader::new(vec!(0xC0))));

    assert_eq!(
        16383,
        read_length(&mut MemReader::new(vec!(0x7f, 0xff)))
        );
}

#[test]
fn test_read_blob() {
    assert_eq!(
        vec!(0x61, 0x62, 0x63, 0x64),
        read_blob(&mut MemReader::new(vec!(4, 0x61, 0x62, 0x63, 0x64))));
}

#[test]
fn test_verify_version() {
    assert_eq!(
        true,
        verify_version(&mut MemReader::new(vec![0x30, 0x30, 0x30, 0x33])));

    assert_eq!(
        false,
        verify_version(&mut MemReader::new(vec![0x30, 0x30, 0x30, 0x3a])));
}

#[test]
fn test_verify_magic() {
    assert_eq!(
        true,
        verify_magic(&mut MemReader::new(vec![0x52, 0x45, 0x44, 0x49, 0x53])));

    assert_eq!(
        false,
        verify_magic(&mut MemReader::new(vec![0x51, 0x0, 0x0, 0x0, 0x0])));
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Alibaba Cloud Computing. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use super::connection::Endpoint;
use super::message::*;
use super::{Error, HandlerResult, Result, VhostUserMasterReqHandler};
use std::io;
use std::mem;
use std::os::unix::io::RawFd;
use std::os::unix::net::UnixStream;
use std::sync::{Arc, Mutex};

struct SlaveFsCacheReqInternal {
    sock: Endpoint<SlaveReq>,
}

/// A vhost-user slave endpoint which sends fs cache requests to the master
#[derive(Clone)]
pub struct SlaveFsCacheReq {
    // underlying Unix domain socket for communication
    node: Arc<Mutex<SlaveFsCacheReqInternal>>,

    // whether the endpoint has encountered any failure
    error: Option<i32>,
}

impl SlaveFsCacheReq {
    fn new(ep: Endpoint<SlaveReq>) -> Self {
        SlaveFsCacheReq {
            node: Arc::new(Mutex::new(SlaveFsCacheReqInternal { sock: ep })),
            error: None,
        }
    }

    /// Create a new instance.
    pub fn from_stream(sock: UnixStream) -> Self {
        Self::new(Endpoint::<SlaveReq>::from_stream(sock))
    }

    fn send_message(
        &mut self,
        flags: SlaveReq,
        fs: &VhostUserFSSlaveMsg,
        fds: Option<&[RawFd]>,
    ) -> Result<u64> {
        self.check_state()?;

        let len = mem::size_of::<VhostUserFSSlaveMsg>();
        let mut hdr = VhostUserMsgHeader::new(flags, 0, len as u32);
        hdr.set_need_reply(true);
        self.node.lock().unwrap().sock.send_message(&hdr, fs, fds)?;

        self.wait_for_ack(&hdr)
    }

    fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
        self.check_state()?;
        let (reply, body, rfds) = self.node.lock().unwrap().sock.recv_body::<VhostUserU64>()?;
        if !reply.is_reply_for(&hdr) || rfds.is_some() || !body.is_valid() {
            Endpoint::<SlaveReq>::close_rfds(rfds);
            return Err(Error::InvalidMessage);
        }
        if body.value != 0 {
            return Err(Error::MasterInternalError);
        }
        Ok(0)
    }

    fn check_state(&self) -> Result<u64> {
        match self.error {
            Some(e) => Err(Error::SocketBroken(std::io::Error::from_raw_os_error(e))),
            None => Ok(0),
        }
    }

    /// Mark endpoint as failed with specified error code.
    pub fn set_failed(&mut self, error: i32) {
        self.error = Some(error);
    }
}

impl VhostUserMasterReqHandler for SlaveFsCacheReq {
    /// Handle virtio-fs map file requests from the slave.
    fn fs_slave_map(&mut self, fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<u64> {
        self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd]))
            .or_else(|e| Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
    }

    /// Handle virtio-fs unmap file requests from the slave.
    fn fs_slave_unmap(&mut self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<u64> {
        self.send_message(SlaveReq::FS_UNMAP, fs, None)
            .or_else(|e| Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
    }
}
<commit_msg>vhost_user: refine the SlaveFsCacheReq struct<commit_after>// Copyright (C) 2020 Alibaba Cloud. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use std::io;
use std::mem;
use std::os::unix::io::RawFd;
use std::os::unix::net::UnixStream;
use std::sync::{Arc, Mutex};

use super::connection::Endpoint;
use super::message::*;
use super::{Error, HandlerResult, Result, VhostUserMasterReqHandler};

struct SlaveFsCacheReqInternal {
    sock: Endpoint<SlaveReq>,

    // Protocol feature VHOST_USER_PROTOCOL_F_REPLY_ACK has been negotiated.
    reply_ack_negotiated: bool,

    // whether the endpoint has encountered any failure
    error: Option<i32>,
}

impl SlaveFsCacheReqInternal {
    fn check_state(&self) -> Result<u64> {
        match self.error {
            Some(e) => Err(Error::SocketBroken(std::io::Error::from_raw_os_error(e))),
            None => Ok(0),
        }
    }

    fn send_message(
        &mut self,
        request: SlaveReq,
        fs: &VhostUserFSSlaveMsg,
        fds: Option<&[RawFd]>,
    ) -> Result<u64> {
        self.check_state()?;

        let len = mem::size_of::<VhostUserFSSlaveMsg>();
        let mut hdr = VhostUserMsgHeader::new(request, 0, len as u32);
        if self.reply_ack_negotiated {
            hdr.set_need_reply(true);
        }
        self.sock.send_message(&hdr, fs, fds)?;

        self.wait_for_ack(&hdr)
    }

    fn wait_for_ack(&mut self, hdr: &VhostUserMsgHeader<SlaveReq>) -> Result<u64> {
        self.check_state()?;
        if !self.reply_ack_negotiated {
            return Ok(0);
        }

        let (reply, body, rfds) = self.sock.recv_body::<VhostUserU64>()?;
        if !reply.is_reply_for(&hdr) || rfds.is_some() || !body.is_valid() {
            Endpoint::<SlaveReq>::close_rfds(rfds);
            return Err(Error::InvalidMessage);
        }
        if body.value != 0 {
            return Err(Error::MasterInternalError);
        }

        Ok(body.value)
    }
}

/// Request proxy to send vhost-user-fs slave requests to the master through the slave
/// communication channel.
///
/// The [SlaveFsCacheReq] acts as a message proxy to forward vhost-user-fs slave requests to the
/// master through the vhost-user slave communication channel. The forwarded messages will be
/// handled by the [MasterReqHandler] server.
///
/// [SlaveFsCacheReq]: struct.SlaveFsCacheReq.html
/// [MasterReqHandler]: struct.MasterReqHandler.html
#[derive(Clone)]
pub struct SlaveFsCacheReq {
    // underlying Unix domain socket for communication
    node: Arc<Mutex<SlaveFsCacheReqInternal>>,
}

impl SlaveFsCacheReq {
    fn new(ep: Endpoint<SlaveReq>) -> Self {
        SlaveFsCacheReq {
            node: Arc::new(Mutex::new(SlaveFsCacheReqInternal {
                sock: ep,
                reply_ack_negotiated: false,
                error: None,
            })),
        }
    }

    fn send_message(
        &self,
        request: SlaveReq,
        fs: &VhostUserFSSlaveMsg,
        fds: Option<&[RawFd]>,
    ) -> io::Result<u64> {
        self.node
            .lock()
            .unwrap()
            .send_message(request, fs, fds)
            .or_else(|e| Err(io::Error::new(io::ErrorKind::Other, format!("{}", e))))
    }

    /// Create a new instance from a `UnixStream` object.
    pub fn from_stream(sock: UnixStream) -> Self {
        Self::new(Endpoint::<SlaveReq>::from_stream(sock))
    }

    /// Set the negotiation state of the `VHOST_USER_PROTOCOL_F_REPLY_ACK` protocol feature.
    ///
    /// When the `VHOST_USER_PROTOCOL_F_REPLY_ACK` protocol feature has been negotiated,
    /// the "REPLY_ACK" flag will be set in the message header for every slave to master request
    /// message.
    pub fn set_reply_ack_flag(&self, enable: bool) {
        self.node.lock().unwrap().reply_ack_negotiated = enable;
    }

    /// Mark endpoint as failed with specified error code.
    pub fn set_failed(&self, error: i32) {
        self.node.lock().unwrap().error = Some(error);
    }
}

impl VhostUserMasterReqHandler for SlaveFsCacheReq {
    /// Forward vhost-user-fs map file requests to the slave.
    fn fs_slave_map(&self, fs: &VhostUserFSSlaveMsg, fd: RawFd) -> HandlerResult<u64> {
        self.send_message(SlaveReq::FS_MAP, fs, Some(&[fd]))
    }

    /// Forward vhost-user-fs unmap file requests to the master.
    fn fs_slave_unmap(&self, fs: &VhostUserFSSlaveMsg) -> HandlerResult<u64> {
        self.send_message(SlaveReq::FS_UNMAP, fs, None)
    }
}

#[cfg(test)]
mod tests {
    use std::os::unix::io::AsRawFd;

    use super::*;

    #[test]
    fn test_slave_fs_cache_req_set_failed() {
        let (p1, _p2) = UnixStream::pair().unwrap();
        let fs_cache = SlaveFsCacheReq::from_stream(p1);

        assert!(fs_cache.node.lock().unwrap().error.is_none());
        fs_cache.set_failed(libc::EAGAIN);
        assert_eq!(fs_cache.node.lock().unwrap().error, Some(libc::EAGAIN));
    }

    #[test]
    fn test_slave_fs_cache_send_failure() {
        let (p1, p2) = UnixStream::pair().unwrap();
        let fd = p2.as_raw_fd();
        let fs_cache = SlaveFsCacheReq::from_stream(p1);

        fs_cache.set_failed(libc::ECONNRESET);
        fs_cache
            .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
            .unwrap_err();
        fs_cache
            .fs_slave_unmap(&VhostUserFSSlaveMsg::default())
            .unwrap_err();
        fs_cache.node.lock().unwrap().error = None;

        drop(p2);
        fs_cache
            .fs_slave_map(&VhostUserFSSlaveMsg::default(), fd)
            .unwrap_err();
        fs_cache
            .fs_slave_unmap(&VhostUserFSSlaveMsg::default())
            .unwrap_err();
    }
}
<|endoftext|>


<commit_before>use base64;
use r2pipe::{R2Pipe, R2};
use radeco_lib;
use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::inst_combine;
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::analysis::sccp;
use radeco_lib::backend::lang_c::c_cfg::ctrl_flow_struct;
use radeco_lib::backend::lang_c::c_cfg::CCFGVerifier;
use radeco_lib::backend::lang_c::c_cfg_builder;
use radeco_lib::frontend::radeco_containers::*;
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::regfile::SubRegisterFile;
use radeco_lib::middle::ssa::ssastorage::SSAStorage;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::middle::{dce, dot};
use std::cell::RefCell;
use std::collections::HashMap;
use std::panic;
use std::rc::Rc;
use std::str;
use std::sync::Arc;

thread_local!(pub static PROJ: RefCell<Option<RadecoProject>> = RefCell::new(None););

pub fn fn_list(proj: &RadecoProject) -> Vec<String> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .map(|s| s.name.to_string())
        .collect()
}

pub fn get_function<'a>(name: &str, proj: &'a RadecoProject) -> Option<&'a RadecoFunction> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .filter(|rfn| rfn.name == name)
        .next()
}

pub fn get_function_mut<'a>(
    name: &str,
    proj: &'a mut RadecoProject,
) -> Option<&'a mut RadecoFunction> {
    proj.iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut())
        .filter(|rfn| rfn.name == name)
        .next()
}

pub fn fn_rename(old_f: &str, new_f: &str, proj: &mut RadecoProject) {
    if let Some(_) = get_function(new_f, proj) {
        println!("there is already a function called: {}", new_f);
        return;
    }

    let mut found = false;

    for module in proj.iter_mut() {
        let module = module.module;
        let off = module.iter()
            .find(|rfn| rfn.function.1.name == old_f)
            .map(|rfn| rfn.function.1.offset);

        if let Some(off) = off {
            module.function_rename(off, new_f);
            found = true;
        }
    }

    if !found {
        println!("function not found: {}", old_f);
    }
}

pub fn analyze_mod(regfile: Arc<SubRegisterFile>, rmod: &mut RadecoModule) {
    // Analyze preserved for all functions.
    {
        eprintln!("[*] Fixing Callee Information");
        let bp_name = regfile.get_name_by_alias(&"BP".to_string());
        let bp_name = bp_name.map(|s| s.to_owned());
        let sp_name = regfile.get_name_by_alias(&"SP".to_string());
        let sp_name = sp_name.map(|s| s.to_owned());
        let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
        callfixer.rounded_analysis();
    }

    // Fix call sites
    radeco_lib::analysis::functions::fix_ssa_opcalls::go(rmod);

    // Infer calling conventions
    radeco_lib::analysis::functions::infer_regusage::run(rmod, &*regfile);
}

pub fn analyze(rfn: &mut RadecoFunction) {
    eprintln!("[+] Analyzing: {} @ {:#x}", rfn.name, rfn.offset);
    {
        eprintln!("  [*] Eliminating Dead Code");
        dce::collect(rfn.ssa_mut());
    }
    let mut ssa = {
        // Constant Propagation (sccp)
        eprintln!("  [*] Propagating Constants");
        let mut analyzer = sccp::Analyzer::new(rfn.ssa_mut());
        analyzer.analyze();
        analyzer.emit_ssa()
    };
    {
        eprintln!("  [*] Eliminating More DeadCode");
        dce::collect(&mut ssa);
    }
    *rfn.ssa_mut() = ssa;
    inst_combine::run(rfn.ssa_mut());
    {
        // Common SubExpression Elimination (cse)
        eprintln!("  [*] Eliminating Common SubExpressions");
        let mut cse = CSE::new(rfn.ssa_mut());
        cse.run();
    }
    {
        // Verify SSA
        eprintln!("  [*] Verifying SSA's Validity");
        match verifier::verify(rfn.ssa()) {
            Err(e) => {
                eprintln!("  [*] Found Error: {}", e);
            }
            Ok(_) => {}
        }
    }
}

pub fn analyze_all_functions<'a>(proj: &'a mut RadecoProject) {
    let rfns = proj
        .iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut());
    for rfn in rfns {
        analyze(rfn);
    }
}

pub fn emit_ir(rfn: &RadecoFunction) -> String {
    eprintln!("  [*] Writing out IR");
    let mut res = String::new();
    ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
    res
}

pub fn emit_dot(ssa: &SSAStorage) -> String {
    dot::emit_dot(ssa)
}

pub fn decompile_all_functions<'a>(proj: &'a RadecoProject) -> String {
    let mut decompiled_funcs = Vec::new();
    let funcs = fn_list(&proj);
    for f in &funcs {
        match decompile(f, &proj) {
            Ok(res) => {
                decompiled_funcs.push(res);
            }
            Err(err) => {
                eprintln!("{}", err);
            }
        };
    }
    decompiled_funcs.join("\n")
}

pub fn decompile<'a>(name: &str, proj: &'a RadecoProject) -> Result<String, String> {
    if let Some(rfn) = get_function(name, &proj) {
        let rmod = proj.iter().map(|i| i.module).next().unwrap();
        let func_name_map = func_names(&rmod);
        let strings = strings(&rmod);
        decompile_priv(rfn, &func_name_map, &strings)
    } else {
        Err(format!("{} is not found.", name))
    }
}

fn decompile_priv(
    rfn: &RadecoFunction,
    func_name_map: &HashMap<u64, String>,
    strings: &HashMap<u64, String>,
) -> Result<String, String> {
    let c_cfg_result =
        panic::catch_unwind(|| c_cfg_builder::recover_c_cfg(rfn, func_name_map, strings));

    if c_cfg_result.is_err() {
        return Err("Failed to recover C control flow graph".to_string());
    };

    let c_cfg = c_cfg_result.unwrap();

    if let Err(err) = CCFGVerifier::verify(&c_cfg) {
        eprintln!("CCFG verification failed {}", err);
    }

    let result = panic::catch_unwind(|| {
        ctrl_flow_struct::structure_and_convert(c_cfg.clone())
            .map(|s| s.print())
            .map_err(|e| e.to_string())
    });
    match result {
        Ok(code) => code,
        Err(_) => {
            println!("Control flow structuring failed");
            Ok(c_cfg.to_c_ast().print())
        }
    }
}

pub fn load_proj_by_path(path: &str) -> RadecoProject {
    let mut p = ProjectLoader::new().path(path).load();
    let regfile = p.regfile().clone();
    for mut xy in p.iter_mut() {
        analyze_mod(regfile.clone(), xy.module);
    }
    p
}

pub fn load_proj_tcp(url: &str) -> Result<RadecoProject, &'static str> {
    let r2p = R2Pipe::tcp(url)?;
    Ok(load_project_by_r2pipe(r2p))
}

pub fn load_proj_http(url: &str) -> Result<RadecoProject, &'static str> {
    let r2p = R2Pipe::http(url)?;
    Ok(load_project_by_r2pipe(r2p))
}

pub fn load_project_by_r2pipe(r2p: R2Pipe) -> RadecoProject {
    let r2 = R2::from(r2p);
    let r2w = Rc::new(RefCell::new(r2));
    let mut p = ProjectLoader::new().source(Rc::new(r2w)).load();
    let regfile = p.regfile().clone();
    for mut xy in p.iter_mut() {
        analyze_mod(regfile.clone(), xy.module);
    }
    p
}

pub fn func_names(rmod: &RadecoModule) -> HashMap<u64, String> {
    rmod.functions
        .iter()
        .map(|(&addr, f)| (addr, f.name.to_string()))
        .collect()
}

pub fn strings(rmod: &RadecoModule) -> HashMap<u64, String> {
    rmod.strings()
        .iter()
        .filter(|ref s| s.paddr.is_some() && s.string.is_some())
        .cloned()
        .map(|s| {
            let (addr, _s) = (s.vaddr.unwrap(), s.string.unwrap());
            let bytes = base64::decode(&_s).unwrap_or(Vec::new());
            let ret_string = match str::from_utf8(bytes.as_slice()) {
                Ok(v) => v.to_string(),
                Err(_e) => _s,
            };
            (addr, ret_string)
        })
        .collect()
}
<commit_msg>Use the new analyzer's API<commit_after>use base64;
use r2pipe::{R2Pipe, R2};
use radeco_lib::analysis::analyzer::{FuncAnalyzer, ModuleAnalyzer};
use radeco_lib::analysis::cse::cse::CSE;
use radeco_lib::analysis::inst_combine::Combiner;
use radeco_lib::analysis::functions::infer_regusage::Inferer;
use radeco_lib::analysis::functions::fix_ssa_opcalls::CallSiteFixer;
use radeco_lib::analysis::interproc::fixcall::CallFixer;
use radeco_lib::analysis::dce::DCE;
use radeco_lib::analysis::sccp::SCCP;
use radeco_lib::backend::lang_c::c_cfg::ctrl_flow_struct;
use radeco_lib::backend::lang_c::c_cfg::CCFGVerifier;
use radeco_lib::backend::lang_c::c_cfg_builder;
use radeco_lib::frontend::radeco_containers::*;
use radeco_lib::middle::ir_writer;
use radeco_lib::middle::regfile::SubRegisterFile;
use radeco_lib::middle::ssa::ssastorage::SSAStorage;
use radeco_lib::middle::ssa::verifier;
use radeco_lib::middle::dot;
use std::cell::RefCell;
use std::collections::HashMap;
use std::panic;
use std::rc::Rc;
use std::str;
use std::sync::Arc;

thread_local!(pub static PROJ: RefCell<Option<RadecoProject>> = RefCell::new(None););

pub fn fn_list(proj: &RadecoProject) -> Vec<String> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .map(|s| s.name.to_string())
        .collect()
}

pub fn get_function<'a>(name: &str, proj: &'a RadecoProject) -> Option<&'a RadecoFunction> {
    proj.iter()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values())
        .filter(|rfn| rfn.name == name)
        .next()
}

pub fn get_function_mut<'a>(
    name: &str,
    proj: &'a mut RadecoProject,
) -> Option<&'a mut RadecoFunction> {
    proj.iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut())
        .filter(|rfn| rfn.name == name)
        .next()
}

pub fn fn_rename(old_f: &str, new_f: &str, proj: &mut RadecoProject) {
    if let Some(_) = get_function(new_f, proj) {
        println!("there is already a function called: {}", new_f);
        return;
    }

    let mut found = false;

    for module in proj.iter_mut() {
        let module = module.module;
        let off = module.iter()
            .find(|rfn| rfn.function.1.name == old_f)
            .map(|rfn| rfn.function.1.offset);

        if let Some(off) = off {
            module.function_rename(off, new_f);
            found = true;
        }
    }

    if !found {
        println!("function not found: {}", old_f);
    }
}

pub fn analyze_mod(regfile: Arc<SubRegisterFile>, rmod: &mut RadecoModule) {
    // Analyze preserved for all functions.
    {
        eprintln!("[*] Fixing Callee Information");
        let bp_name = regfile.get_name_by_alias(&"BP".to_string());
        let bp_name = bp_name.map(|s| s.to_owned());
        let sp_name = regfile.get_name_by_alias(&"SP".to_string());
        let sp_name = sp_name.map(|s| s.to_owned());
        let mut callfixer = CallFixer::new(rmod, bp_name, sp_name);
        callfixer.rounded_analysis();
    }

    // Fix call sites
    let mut call_site_fixer = CallSiteFixer::new();
    call_site_fixer.analyze(rmod);

    // Infer calling conventions
    let mut inferer = Inferer::new((*regfile).clone());
    inferer.analyze(rmod);
}

pub fn analyze(rfn: &mut RadecoFunction) {
    eprintln!("[+] Analyzing: {} @ {:#x}", rfn.name, rfn.offset);
    {
        eprintln!("  [*] Eliminating Dead Code");
        let mut dce = DCE::new();
        dce.analyze(rfn);
    }
    {
        // Constant Propagation (sccp)
        eprintln!("  [*] Propagating Constants");
        let mut sccp = SCCP::new();
        sccp.analyze(rfn);
    }
    {
        eprintln!("  [*] Eliminating More DeadCode");
        let mut dce = DCE::new();
        dce.analyze(rfn);
    }
    {
        // Instruction combiner
        let mut combiner = Combiner::new();
        combiner.analyze(rfn);
    }
    {
        // Common SubExpression Elimination (cse)
        eprintln!("  [*] Eliminating Common SubExpressions");
        let mut cse = CSE::new();
        cse.analyze(rfn);
    }
    {
        // Verify SSA
        eprintln!("  [*] Verifying SSA's Validity");
        match verifier::verify(rfn.ssa()) {
            Err(e) => {
                eprintln!("  [*] Found Error: {}", e);
            }
            Ok(_) => {}
        }
    }
}

pub fn analyze_all_functions<'a>(proj: &'a mut RadecoProject) {
    let rfns = proj
        .iter_mut()
        .map(|i| i.module)
        .flat_map(|rmod| rmod.functions.values_mut());
    for rfn in rfns {
        analyze(rfn);
    }
}

pub fn emit_ir(rfn: &RadecoFunction) -> String {
    eprintln!("  [*] Writing out IR");
    let mut res = String::new();
    ir_writer::emit_il(&mut res, Some(rfn.name.to_string()), rfn.ssa()).unwrap();
    res
}

pub fn emit_dot(ssa: &SSAStorage) -> String {
    dot::emit_dot(ssa)
}

pub fn decompile_all_functions<'a>(proj: &'a RadecoProject) -> String {
    let mut decompiled_funcs = Vec::new();
    let funcs = fn_list(&proj);
    for f in &funcs {
        match decompile(f, &proj) {
            Ok(res) => {
                decompiled_funcs.push(res);
            }
            Err(err) => {
                eprintln!("{}", err);
            }
        };
    }
    decompiled_funcs.join("\n")
}

pub fn decompile<'a>(name: &str, proj: &'a RadecoProject) -> Result<String, String> {
    if let Some(rfn) = get_function(name, &proj) {
        let rmod = proj.iter().map(|i| i.module).next().unwrap();
        let func_name_map = func_names(&rmod);
        let strings = strings(&rmod);
        decompile_priv(rfn, &func_name_map, &strings)
    } else {
        Err(format!("{} is not found.", name))
    }
}

fn decompile_priv(
    rfn: &RadecoFunction,
    func_name_map: &HashMap<u64, String>,
    strings: &HashMap<u64, String>,
) -> Result<String, String> {
    let c_cfg_result =
        panic::catch_unwind(|| c_cfg_builder::recover_c_cfg(rfn, func_name_map, strings));

    if c_cfg_result.is_err() {
        return Err("Failed to recover C control flow graph".to_string());
    };

    let c_cfg = c_cfg_result.unwrap();

    if let Err(err) = CCFGVerifier::verify(&c_cfg) {
        eprintln!("CCFG verification failed {}", err);
    }

    let result = panic::catch_unwind(|| {
        ctrl_flow_struct::structure_and_convert(c_cfg.clone())
            .map(|s| s.print())
            .map_err(|e| e.to_string())
    });
    match result {
        Ok(code) => code,
        Err(_) => {
            println!("Control flow structuring failed");
            Ok(c_cfg.to_c_ast().print())
        }
    }
}

pub fn load_proj_by_path(path: &str) -> RadecoProject {
    let mut p = ProjectLoader::new().path(path).load();
    let regfile = p.regfile().clone();
    for mut xy in p.iter_mut() {
        analyze_mod(regfile.clone(), xy.module);
    }
    p
}

pub fn load_proj_tcp(url: &str) -> Result<RadecoProject, &'static str> {
    let r2p = R2Pipe::tcp(url)?;
    Ok(load_project_by_r2pipe(r2p))
}

pub fn load_proj_http(url: &str) -> Result<RadecoProject, &'static str> {
    let r2p = R2Pipe::http(url)?;
    Ok(load_project_by_r2pipe(r2p))
}

pub fn load_project_by_r2pipe(r2p: R2Pipe) -> RadecoProject {
    let r2 = R2::from(r2p);
    let r2w = Rc::new(RefCell::new(r2));
    let mut p = ProjectLoader::new().source(Rc::new(r2w)).load();
    let regfile = p.regfile().clone();
    for mut xy in p.iter_mut() {
        analyze_mod(regfile.clone(), xy.module);
    }
    p
}

pub fn func_names(rmod: &RadecoModule) -> HashMap<u64, String> {
    rmod.functions
        .iter()
        .map(|(&addr, f)| (addr, f.name.to_string()))
        .collect()
}

pub fn strings(rmod: &RadecoModule) -> HashMap<u64, String> {
    rmod.strings()
        .iter()
        .filter(|ref s| s.paddr.is_some() && s.string.is_some())
        .cloned()
        .map(|s| {
            let (addr, _s) = (s.vaddr.unwrap(), s.string.unwrap());
            let bytes = base64::decode(&_s).unwrap_or(Vec::new());
            let ret_string = match str::from_utf8(bytes.as_slice()) {
                Ok(v) => v.to_string(),
                Err(_e) => _s,
            };
            (addr, ret_string)
        })
        .collect()
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::path::Path;
use std::rc::Rc;

use globset;
use walkdir;

use crate::version::Version;
use crate::version_source::{self, VersionSource};

use super::{config, VutConfig, VutError};

pub fn update_version_sources(
    config: &VutConfig,
    root_path: &Path,
    version: &Version,
    dir_entries: &[walkdir::DirEntry],
) -> Result<(), VutError> {
    let version_source_finder = VersionSourceFinder::from_config(config)?;

    let mut version_sources: Vec<Box<dyn VersionSource>> = Vec::new();

    let dirs_iter = dir_entries
        .iter()
        .map(|entry| entry.path())
        // Only include directories
        .filter(|path| path.is_dir());

    for path in dirs_iter {
        // Make path relative, as we only want to match on the path
        // relative to the root.
        let rel_path = path.strip_prefix(root_path).unwrap();

        version_sources.append(&mut version_source_finder.find_version_sources(path, rel_path));
    }

    for mut vs in version_sources {
        vs.set_version(&version)?;
    }

    Ok(())
}

pub struct CustomSourceTypes {
    regex_source_types: HashMap<String, version_source::CustomRegexSourceTemplate>,
}

impl CustomSourceTypes {
    pub fn from_config(config: &VutConfig) -> Result<Self, VutError> {
        let mut regex_source_types: HashMap<String, version_source::CustomRegexSourceTemplate> = HashMap::new();

        // Construct custom source type templates
        for (k, v) in config.custom_source_types.iter() {
            // Extract regex custom source type information from the enum.
            // Currently regex is the only type implemented.
            let regex_custom_source_type = match v {
                config::CustomSourceType::Regex(v) => v,
            };

            // Try to parse regex string
            let regex = {
                let mut builder = regex::RegexBuilder::new(&regex_custom_source_type.regex);
                builder.multi_line(true);

                match builder.build() {
                    Ok(v) => v,
                    Err(err) => {
                        return Err(VutError::Other(Cow::Owned(format!(
                            "Invalid regex '{}': {}",
                            &regex_custom_source_type.regex,
                            err.to_string()
                        ))))
                    }
                }
            };

            // Construct source type template
            let source = version_source::CustomRegexSourceTemplate::new(&regex_custom_source_type.file_name, regex);

            // Add source to hashmap for later use
            regex_source_types.insert(k.clone(), source);
        }

        Ok(Self { regex_source_types })
    }

    pub fn version_sources_from_path(
        &self,
        path: &Path,
        source_types: &HashSet<String>,
    ) -> Vec<Box<dyn VersionSource>> {
        let mut version_sources: Vec<Box<dyn VersionSource>> = Vec::new();

        for source_type in source_types {
            if let Some(custom_source_type_template) = self.regex_source_types.get(source_type.as_str()) {
                if let Some(source) = custom_source_type_template.instance_from_path(&path) {
                    version_sources.push(Box::new(source));
                }
            }
        }

        version_sources
    }
}

struct VersionSourceSpec {
    include_globset: globset::GlobSet,
    exclude_globset: Option<globset::GlobSet>,
    source_types: Option<HashSet<String>>,
    custom_source_types: Rc<CustomSourceTypes>,
}

impl VersionSourceSpec {
    pub fn from_config_vs(
        cfg_vs: &config::VersionSource,
        custom_source_types: Rc<CustomSourceTypes>,
    ) -> Result<Self, VutError> {
        let (pattern, exclude_pattern, source_types) = match cfg_vs {
            config::VersionSource::Simple(pattern) => (pattern, None, None),
            config::VersionSource::Detailed(vs) => (&vs.pattern, vs.exclude_pattern.as_ref(), vs.types.as_ref()),
        };

        let mut include_globset = globset::GlobSetBuilder::new();

        let patterns = match pattern {
            config::Patterns::Single(v) => vec![v],
            config::Patterns::Multiple(v) => v.iter().collect(),
        };

        for pattern in patterns {
            let glob = globset::Glob::new(&pattern).map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

            include_globset.add(glob);
        }

        let include_globset = include_globset
            .build()
            .map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

        let exclude_globset = if let Some(pattern) = exclude_pattern {
            let patterns = match &pattern {
                config::Patterns::Single(v) => vec![v],
                config::Patterns::Multiple(v) => v.iter().collect(),
            };

            let mut exclude_globset = globset::GlobSetBuilder::new();

            for pattern in patterns {
                let glob = globset::Glob::new(&pattern).map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

                exclude_globset.add(glob);
            }

            let exclude_globset = exclude_globset
                .build()
                .map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

            Some(exclude_globset)
        } else {
            None
        };

        let source_types = source_types.map(|v| match v {
            config::VersionSourceTypes::Single(name) => {
                let mut set = HashSet::new();
                set.insert(name.clone());

                set
            }
            config::VersionSourceTypes::Multiple(set) => set.clone(),
        });

        Ok(Self {
            include_globset,
            exclude_globset,
            source_types: source_types.map(|v| v.clone()),
            custom_source_types,
        })
    }

    pub fn find_version_sources(&self, path: &Path, rel_path: &Path) -> Vec<Box<dyn VersionSource>> {
        let mut version_sources = Vec::new();

        if self.include_globset.is_match(&rel_path) {
            if let Some(exclude_globset) = &self.exclude_globset {
                if exclude_globset.is_match(&rel_path) {
                    // If path is matched by the exclude globset, immediately return the empty list.
                    return version_sources;
                }
            }

            // Check for built-in version sources at this path
            let mut new_sources = if let Some(source_types) = &self.source_types {
                // Find built-in sources
                let mut new_sources = version_source::specific_version_sources_from_path(path, source_types);

                // Find custom sources
                new_sources.append(&mut self.custom_source_types.version_sources_from_path(path, source_types));

                new_sources
            } else {
                version_source::version_sources_from_path(&path)
            };

            // Append all found sources to the main list of sources
            version_sources.append(&mut new_sources);
        }

        version_sources
    }
}

pub struct VersionSourceFinder {
    specs: Vec<VersionSourceSpec>,
}

impl VersionSourceFinder {
    pub fn from_config(config: &VutConfig) -> Result<Self, VutError> {
        let custom_source_types = Rc::new(CustomSourceTypes::from_config(config)?);

        let mut specs: Vec<VersionSourceSpec> = Vec::new();

        for cfg_vs in config.version_source.iter() {
            let spec = VersionSourceSpec::from_config_vs(cfg_vs, custom_source_types.clone())?;

            specs.push(spec);
        }

        Ok(Self { specs })
    }

    pub fn find_version_sources(&self, path: &Path, rel_path: &Path) -> Vec<Box<dyn VersionSource>> {
        let mut version_sources = Vec::new();

        for spec in self.specs.iter() {
            version_sources.append(&mut spec.find_version_sources(path, rel_path));
        }

        version_sources
    }
}
<commit_msg>refactor: Use iterator instead of for loop in VersionSourceFinder::find_version_sources<commit_after>use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::path::Path;
use std::rc::Rc;

use globset;
use walkdir;

use crate::version::Version;
use crate::version_source::{self, VersionSource};

use super::{config, VutConfig, VutError};

pub fn update_version_sources(
    config: &VutConfig,
    root_path: &Path,
    version: &Version,
    dir_entries: &[walkdir::DirEntry],
) -> Result<(), VutError> {
    let version_source_finder = VersionSourceFinder::from_config(config)?;

    let mut version_sources: Vec<Box<dyn VersionSource>> = Vec::new();

    let dirs_iter = dir_entries
        .iter()
        .map(|entry| entry.path())
        // Only include directories
        .filter(|path| path.is_dir());

    for path in dirs_iter {
        // Make path relative, as we only want to match on the path
        // relative to the root.
        let rel_path = path.strip_prefix(root_path).unwrap();

        version_sources.append(&mut version_source_finder.find_version_sources(path, rel_path));
    }

    for mut vs in version_sources {
        vs.set_version(&version)?;
    }

    Ok(())
}

pub struct CustomSourceTypes {
    regex_source_types: HashMap<String, version_source::CustomRegexSourceTemplate>,
}

impl CustomSourceTypes {
    pub fn from_config(config: &VutConfig) -> Result<Self, VutError> {
        let mut regex_source_types: HashMap<String, version_source::CustomRegexSourceTemplate> = HashMap::new();

        // Construct custom source type templates
        for (k, v) in config.custom_source_types.iter() {
            // Extract regex custom source type information from the enum.
            // Currently regex is the only type implemented.
            let regex_custom_source_type = match v {
                config::CustomSourceType::Regex(v) => v,
            };

            // Try to parse regex string
            let regex = {
                let mut builder = regex::RegexBuilder::new(&regex_custom_source_type.regex);
                builder.multi_line(true);

                match builder.build() {
                    Ok(v) => v,
                    Err(err) => {
                        return Err(VutError::Other(Cow::Owned(format!(
                            "Invalid regex '{}': {}",
                            &regex_custom_source_type.regex,
                            err.to_string()
                        ))))
                    }
                }
            };

            // Construct source type template
            let source = version_source::CustomRegexSourceTemplate::new(&regex_custom_source_type.file_name, regex);

            // Add source to hashmap for later use
            regex_source_types.insert(k.clone(), source);
        }

        Ok(Self { regex_source_types })
    }

    pub fn version_sources_from_path(
        &self,
        path: &Path,
        source_types: &HashSet<String>,
    ) -> Vec<Box<dyn VersionSource>> {
        let mut version_sources: Vec<Box<dyn VersionSource>> = Vec::new();

        for source_type in source_types {
            if let Some(custom_source_type_template) = self.regex_source_types.get(source_type.as_str()) {
                if let Some(source) = custom_source_type_template.instance_from_path(&path) {
                    version_sources.push(Box::new(source));
                }
            }
        }

        version_sources
    }
}

struct VersionSourceSpec {
    include_globset: globset::GlobSet,
    exclude_globset: Option<globset::GlobSet>,
    source_types: Option<HashSet<String>>,
    custom_source_types: Rc<CustomSourceTypes>,
}

impl VersionSourceSpec {
    pub fn from_config_vs(
        cfg_vs: &config::VersionSource,
        custom_source_types: Rc<CustomSourceTypes>,
    ) -> Result<Self, VutError> {
        let (pattern, exclude_pattern, source_types) = match cfg_vs {
            config::VersionSource::Simple(pattern) => (pattern, None, None),
            config::VersionSource::Detailed(vs) => (&vs.pattern, vs.exclude_pattern.as_ref(), vs.types.as_ref()),
        };

        let mut include_globset = globset::GlobSetBuilder::new();

        let patterns = match pattern {
            config::Patterns::Single(v) => vec![v],
            config::Patterns::Multiple(v) => v.iter().collect(),
        };

        for pattern in patterns {
            let glob = globset::Glob::new(&pattern).map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

            include_globset.add(glob);
        }

        let include_globset = include_globset
            .build()
            .map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

        let exclude_globset = if let Some(pattern) = exclude_pattern {
            let patterns = match &pattern {
                config::Patterns::Single(v) => vec![v],
                config::Patterns::Multiple(v) => v.iter().collect(),
            };

            let mut exclude_globset = globset::GlobSetBuilder::new();

            for pattern in patterns {
                let glob = globset::Glob::new(&pattern).map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

                exclude_globset.add(glob);
            }

            let exclude_globset = exclude_globset
                .build()
                .map_err(|err| VutError::Other(Cow::Owned(err.to_string())))?;

            Some(exclude_globset)
        } else {
            None
        };

        let source_types = source_types.map(|v| match v {
            config::VersionSourceTypes::Single(name) => {
                let mut set = HashSet::new();
                set.insert(name.clone());

                set
            }
            config::VersionSourceTypes::Multiple(set) => set.clone(),
        });

        Ok(Self {
            include_globset,
            exclude_globset,
            source_types: source_types.map(|v| v.clone()),
            custom_source_types,
        })
    }

    pub fn find_version_sources(&self, path: &Path, rel_path: &Path) -> Vec<Box<dyn VersionSource>> {
        let mut version_sources = Vec::new();

        if self.include_globset.is_match(&rel_path) {
            if let Some(exclude_globset) = &self.exclude_globset {
                if exclude_globset.is_match(&rel_path) {
                    // If path is matched by the exclude globset, immediately return the empty list.
                    return version_sources;
                }
            }

            // Check for built-in version sources at this path
            let mut new_sources = if let Some(source_types) = &self.source_types {
                // Find built-in sources
                let mut new_sources = version_source::specific_version_sources_from_path(path, source_types);

                // Find custom sources
                new_sources.append(&mut self.custom_source_types.version_sources_from_path(path, source_types));

                new_sources
            } else {
                version_source::version_sources_from_path(&path)
            };

            // Append all found sources to the main list of sources
            version_sources.append(&mut new_sources);
        }

        version_sources
    }
}

pub struct VersionSourceFinder {
    specs: Vec<VersionSourceSpec>,
}

impl VersionSourceFinder {
    pub fn from_config(config: &VutConfig) -> Result<Self, VutError> {
        let custom_source_types = Rc::new(CustomSourceTypes::from_config(config)?);

        let mut specs: Vec<VersionSourceSpec> = Vec::new();

        for cfg_vs in config.version_source.iter() {
            let spec = VersionSourceSpec::from_config_vs(cfg_vs, custom_source_types.clone())?;

            specs.push(spec);
        }

        Ok(Self { specs })
    }

    pub fn find_version_sources(&self, path: &Path, rel_path: &Path) -> Vec<Box<dyn VersionSource>> {
        let version_sources = self
            .specs
            .iter()
            .flat_map(|spec| spec.find_version_sources(path, rel_path).into_iter())
            .collect();

        version_sources
    }
}
<|endoftext|>


<commit_before>pub mod value;
pub mod types;

use self::value::*;
use self::types::*;
use parser::ast::*;

pub fn eval(program: Program) -> Result<Value> {
    Ok(Value::Null)
}

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

    fn eval_to(code: &str, expected: Value) {
        let tokens = lexer::tokenize(String::from(code).chars()).unwrap();
        let program = parser::parse(tokens).unwrap();
        let actual = eval(program).unwrap();
        assert_eq!(actual, expected);
    }

    fn fail_with(code: &str, error: &str) {
        let tokens = lexer::tokenize(String::from(code).chars()).unwrap();
        let program = parser::parse(tokens).unwrap();
        let actual = eval(program);
        assert_eq!(actual, Err(EvalError(String::from(error))));
    }

    #[test]
    fn empty_program() {
        eval_to("", Value::Null);
    }
}
<commit_msg>Add example codes for evaluator tests<commit_after>pub mod value;
pub mod types;

use self::value::*;
use self::types::*;
use parser::ast::*;

pub fn eval(program: Program) -> Result<Value> {
    Ok(Value::Null)
}

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

    fn eval_to(code: &str, expected: Value) {
        let tokens = lexer::tokenize(String::from(code).chars()).unwrap();
        let program = parser::parse(tokens).unwrap();
        let actual = eval(program).unwrap();
        assert_eq!(actual, expected);
    }

    fn fail_with(code: &str, error: &str) {
        let tokens = lexer::tokenize(String::from(code).chars()).unwrap();
        let program = parser::parse(tokens).unwrap();
        let actual = eval(program);
        assert_eq!(actual, Err(EvalError(String::from(error))));
    }

    #[test]
    fn empty_program() {
        eval_to("", Value::Null);
    }

    static RETURN1: &str = "
if (10 > 1) {
  if (10 > 1) {
    return 10;
  }
  return 1;
}
";

    static FN1: &str = "
let add = fn(a, b, c, d) { return a + b + c + d; };
add(1, 2, 3, 4);
";

    static FN2: &str = "
let addThree = fn(x) { return x + 3 };
addThree(3);
";

    static FN3: &str = "
let max = fn(x, y) { if (x > y) { x } else { y } };
max(5, 10)
";

    static FN4: &str = "
let factorial = fn(n) {
  if (n == 0) {
    1
  } else {
    n * factorial(n - 1)
  }
}
factorial(5)
";

    static FN5: &str = "
let addThree = fn(x) { return x + 3 };
let callTwoTimes = fn(x, f) { f(f(x)) }
callTwoTimes(3, addThree);
";

    static FN6: &str = "
let callTwoTimes = fn(x, f) { f(f(x)) }
callTwoTimes(3, fn(x) { x + 1 });
";

    static FN7: &str = "
let newAdder = fn(x) { fn(n) { x + n } };
let addTwo = newAdder(2);
addTwo(2);
";

    static MAP_DECL: &str = "
let map = fn(f, arr) {
  if (len(arr) == 0) {
    []
  } else {
    let h = head(arr);
    cons(f(h), map(f, tail(arr)));
  }
};
";

    static REDUCE_DECL: &str = "
let reduce = fn(f, init, arr) {
  if (len(arr) == 0) {
    init
  } else {
    let newInit = f(init, head(arr));
    reduce(f, newInit, tail(arr));
  }
};
";

    static HASH1: &str = "
let double = fn(x) {
  x * 2;
};
let arr = [1, 2, 3, 4];
let h = {
  \"one\": 10 - 9,
  \"two\": 8 / 4,
  3: arr[2],
  4: double(2),
  true: if (10 > 8) { true } else { false },
  false: \"hello\" == \"world\"
};
";
}
<|endoftext|>