<commit_before>/// Quaternion math used to represent orientation/rotation in 3D space.
///
/// TODO: Expand on the mathy stuff:
/// - "Quaternion" really means "unit quaternion", since that's the only case we care about.
/// - Multiplication means composing two rotations.
/// - "Grassman product" is technically the type of multiplication used.
/// - Multiplying by a `Vector3` rotates the vector.
/// - Concatenation happens left-to-right, e.g. `v * q1 * q2 * q3` rotates `v` by `q1`, then `q2`,
///   then `q3`. In theory that order shouldn't really matter, right? Rotation is commutative?

use std::ops::{Mul, MulAssign};
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    /// Calculates the quaternion representing the opposite rotation.
    pub fn inverse(self) -> Quaternion {
        Quaternion {
            w: self.w,
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

impl Default for Quaternion {
    fn default() -> Quaternion {
        Quaternion::identity()
    }
}

impl Mul<Quaternion> for Quaternion {
    type Output = Quaternion;

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

impl MulAssign<Quaternion> for Quaternion {
    fn mul_assign(&mut self, rhs: Quaternion) {
        *self = *self * rhs; // TODO: No temp object? We'll have to see if LLVM can optimize it away.
    }
}

impl Mul<Vector3> for Quaternion {
    type Output = Vector3;

    fn mul(self, rhs: Vector3) -> Vector3 {
        let rhs_quat = Quaternion::from_vector3(rhs);
        let result_quat = self * rhs_quat * self.inverse();
        Vector3::new(result_quat.x, result_quat.y, result_quat.z)
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl From<Vector3> for Quaternion {
    fn from(from: Vector3) -> Quaternion {
        Quaternion::from_vector3(from)
    }
}

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<commit_msg>Add quaternion diff<commit_after>/// Quaternion math used to represent orientation/rotation in 3D space.
///
/// TODO: Expand on the mathy stuff:
/// - "Quaternion" really means "unit quaternion", since that's the only case we care about.
/// - Multiplication means composing two rotations.
/// - "Grassman product" is technically the type of multiplication used.
/// - Multiplying by a `Vector3` rotates the vector.
/// - Concatenation happens left-to-right, e.g. `v * q1 * q2 * q3` rotates `v` by `q1`, then `q2`,
///   then `q3`. In theory that order shouldn't really matter, right? Rotation is commutative?

use std::ops::{Mul, MulAssign};
use std::f32::consts::PI;

use vector::Vector3;
use matrix::*;
use super::{IsZero, Clamp, Dot};

#[derive(Debug, PartialEq, Clone, Copy)]
pub struct Quaternion {
    pub w: f32,
    pub x: f32,
    pub y: f32,
    pub z: f32,
}

impl Quaternion {
    /// Creates an identity quaternion.
    ///
    /// The identity quaternion is the quaternion that can be multiplied into any other quaternion
    /// without changing it.
    pub fn identity() -> Quaternion {
        Quaternion {
            w: 1.0,
            x: 0.0,
            y: 0.0,
            z: 0.0,
        }
    }

    /// Creates a quaternion from an axis and a rotation around that axis.
    ///
    /// # Params
    ///
    /// - axis - The axis being used to represent the rotation. This should
    ///   be normalized before being passed into `axis_angle()`.
    pub fn axis_angle(axis: Vector3, angle: f32) -> Quaternion {
        assert!(axis.is_normalized());

        let s = (angle * 0.5).sin();
        Quaternion {
            w: (angle * 0.5).cos(),
            x: s * axis.x,
            y: s * axis.y,
            z: s * axis.z,
        }.normalized()
    }

    /// Creates a quaternion that rotates an object to look in the specified direction.
    pub fn look_rotation(forward: Vector3, up: Vector3) -> Quaternion {
        assert!(!forward.is_zero());
        assert!(!up.is_zero());

        let source = Vector3::forward();
        let forward = forward.normalized();
        let up = up.normalized();

        let dot = source.dot(forward);

        if (dot + 1.0).is_zero() {
            // vector a and b point exactly in the opposite direction,
            // so it is a 180 degrees turn around the up-axis
            return Quaternion::axis_angle(up, PI)
        }

        if (dot - 1.0).is_zero() {
            // Vector a and b point exactly in the same direction
            // so we return the identity quaternion.
            return Quaternion::identity()
        }

        let rot_angle = dot.acos();
        let rot_axis = Vector3::cross(source, forward).normalized();// source.cross(forward).normalized();
        return Quaternion::axis_angle(rot_axis, rot_angle)

        // TODO: Correctly take the up vector into account.
    }

    /// Creates a quaternion from a set of euler angles.
    pub fn from_eulers(x: f32, y: f32, z: f32) -> Quaternion {
        Quaternion::axis_angle(Vector3::new(1.0, 0.0, 0.0), x)
      * Quaternion::axis_angle(Vector3::new(0.0, 1.0, 0.0), y)
      * Quaternion::axis_angle(Vector3::new(0.0, 0.0, 1.0), z)
    }

    pub fn from_vector3(angles: Vector3) -> Quaternion {
        Quaternion::from_eulers(angles.x, angles.y, angles.z)
    }

    /// Converts the quaternion to the corresponding rotation matrix.
    pub fn as_matrix4(self) -> Matrix4 {
        Matrix4::from_quaternion(self)
    }

    pub fn as_matrix3(self) -> Matrix3 {
        Matrix3::from_quaternion(self)
    }

    /// Retrieves the rotation represented by the quaternion as a rotation about an axis.
    ///
    /// The returned axis will always be normalized.
    pub fn as_axis_angle(&self) -> (Vector3, f32) {
        assert!(self.is_normalized());

        let angle = 2.0 * self.w.acos();
        let s = (1.0 - self.w * self.w).sqrt();
        if s.is_zero() {
            // If s is 0, axis is arbitrary.
            (Vector3::new(1.0, 0.0, 0.0), angle)
        } else {
            (Vector3::new(self.x / s, self.y / s, self.z / s).normalized(), angle)
        }
    }

    /// Retrieves the rotation represented by the quaternion as euler angles.
    pub fn as_eulers(&self) -> Vector3 {
        assert!(self.is_normalized());

        let x = f32::atan2(
            2.0 * (self.w * self.x + self.y * self.z),
            1.0 - 2.0 * (self.x * self.x + self.y * self.y));
        let y = (2.0 * (self.w * self.y - self.z * self.x)).asin();
        let z = f32::atan2(
            2.0 * (self.w * self.z + self.x * self.y),
            1.0 - 2.0 * (self.y * self.y + self.z * self.z));

        Vector3::new(x, y, z)
    }

    /// Normalizes the quaternion to unit length.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalize(&mut self) {
        assert!(!self.is_zero());

        let length = (self.w * self.w
                    + self.x * self.x
                    + self.y * self.y
                    + self.z * self.z).sqrt();

        self.w /= length;
        self.x /= length;
        self.y /= length;
        self.z /= length;
    }

    /// Creates a normalized copy of the quaternion.
    ///
    /// The quaternion must not have a length of zero when calling this method.
    pub fn normalized(&self) -> Quaternion {
        let mut temp = *self;
        temp.normalize();
        temp
    }

    /// Determines if the quaternion is normalized (has a length of 1.0).
    pub fn is_normalized(&self) -> bool {
        let mag_sqrd = Quaternion::dot(*self, *self);
        (mag_sqrd - 1.0).is_zero()
    }

    pub fn repeat(&self, repeat: f32) -> Quaternion {
        let (axis, angle) = self.as_axis_angle();
        Quaternion::axis_angle(axis, angle * repeat)
    }

    /// Calculates the dot product of two quaternions.
    pub fn dot(first: Quaternion, second: Quaternion) -> f32 {
        (first.w * second.w
       + first.x * second.x
       + first.y * second.y
       + first.z * second.z)
    }

    /// Interpolates linearly between two quaternions.
    ///
    /// # Remarks
    ///
    /// This method does not necessarily result in a normalized Quaternion, so the result should
    /// not be used directly to represent a rotation. If you would like to lerp two rotation
    /// quaternions use `Quaternion::nlerp()`.
    pub fn lerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        // first + t * (second - first)
        second.sub(first).mul(t).add(first)
    }

    /// Interpolates linearly between two quaternions using a normalized lerp.
    pub fn nlerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        Quaternion::lerp(first, second, t).normalized()
    }

    /// Calculates the spherical linear interpolation between two quaternions.
    ///
    /// # Remarks
    ///
    /// While slerp is generally the go-to method for interpolating quaternions, it's computationaly
    /// expensive and has some undesirable properties. `Quaternion::nlerp()` is often more appropriate unless it's
    /// absolutely necessary that the interpolation have a constant velocity. For a better discussion
    /// of the different methods of interpolating quaternions see [this article by Jonathan Blow]
    /// (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/).
    pub fn slerp(first: Quaternion, second: Quaternion, t: f32) -> Quaternion {
        assert!(first.is_normalized());
        assert!(second.is_normalized());

        // Compute the cosine of the angle between the two vectors.
        let dot = Quaternion::dot(first, second);

        const DOT_THRESHOLD: f32 = 0.9995;
        if dot > DOT_THRESHOLD {
            // If the inputs are too close for comfort, linearly interpolate
            // and normalize the result.
            return Quaternion::nlerp(first, second, t);
        }

        dot.clamp(-1.0, 1.0);     // Robustness: Stay within domain of acos()
        let theta_0 = dot.acos(); // theta_0 = angle between input vectors
        let theta = theta_0 * t;  // theta = angle between first and result

        let normal = (second.sub(first).mul(dot)).normalized(); // { first, normal } is now an orthonormal basis

        // TODO: We shouldn't need to normalize here since both inputs are normalized,
        //       the result was introducing error. Figure out if there's something else we
        //       can do to improve accuracy.
        //      first *   theta.cos()  +   normal *   theta.sin()
        return (first.mul(theta.cos()).add(normal.mul(theta.sin()))).normalized();
    }

    /// Calculates the quaternion representing the opposite rotation.
    pub fn inverse(self) -> Quaternion {
        Quaternion {
            w: self.w,
            x: -self.x,
            y: -self.y,
            z: -self.z,
        }
    }

    pub fn diff(self, rhs: Quaternion) -> Quaternion {
        rhs * self.inverse()
    }

    fn mul(self, rhs: f32) -> Quaternion {
        Quaternion {
            w: self.w * rhs,
            x: self.x * rhs,
            y: self.y * rhs,
            z: self.z * rhs,
        }
    }

    fn sub(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w - rhs.w,
            x: self.x - rhs.x,
            y: self.y - rhs.y,
            z: self.z - rhs.z,
        }
    }

    fn add(self, rhs: Quaternion) -> Quaternion {
        Quaternion {
            w: self.w + rhs.w,
            x: self.x + rhs.x,
            y: self.y + rhs.y,
            z: self.z + rhs.z,
        }
    }
}

impl Default for Quaternion {
    fn default() -> Quaternion {
        Quaternion::identity()
    }
}

impl Mul<Quaternion> for Quaternion {
    type Output = Quaternion;

    fn mul(self, rhs: Quaternion) -> Quaternion {
        assert!(self.is_normalized());
        assert!(rhs.is_normalized());

        Quaternion {
            w: (self.w * rhs.w) - (self.x * rhs.x) - (self.y * rhs.y) - (self.z * rhs.z),
            x: (self.w * rhs.x) + (self.x * rhs.w) + (self.y * rhs.z) - (self.z * rhs.y),
            y: (self.w * rhs.y) - (self.x * rhs.z) + (self.y * rhs.w) + (self.z * rhs.x),
            z: (self.w * rhs.z) + (self.x * rhs.y) - (self.y * rhs.x) + (self.z * rhs.w),
        }.normalized()
    }
}

impl MulAssign<Quaternion> for Quaternion {
    fn mul_assign(&mut self, rhs: Quaternion) {
        *self = *self * rhs; // TODO: No temp object? We'll have to see if LLVM can optimize it away.
    }
}

impl Mul<Vector3> for Quaternion {
    type Output = Vector3;

    fn mul(self, rhs: Vector3) -> Vector3 {
        let rhs_quat = Quaternion::from_vector3(rhs);
        let result_quat = self * rhs_quat * self.inverse();
        Vector3::new(result_quat.x, result_quat.y, result_quat.z)
    }
}

// TODO: impl Mul<Vector3> for Quaternion (or maybe other way around).

impl From<Vector3> for Quaternion {
    fn from(from: Vector3) -> Quaternion {
        Quaternion::from_vector3(from)
    }
}

impl IsZero for Quaternion {
    fn is_zero(self) -> bool {
        (self.w * self.w
       + self.x * self.x
       + self.y * self.y
       + self.z * self.z).is_zero()
    }
}
<|endoftext|>


<commit_before>use super::{
    heap::{Builtin, Closure, Data, Heap, Pointer},
    tracer::{TraceEntry, Tracer},
    use_provider::{DbUseProvider, UseProvider},
};
use crate::{
    compiler::{hir::Id, lir::Instruction},
    database::Database,
    module::Module,
};
use itertools::Itertools;
use std::collections::HashMap;
use tracing::{info, trace};

const TRACE: bool = false;

/// A VM can execute some byte code.
#[derive(Clone)]
pub struct Vm {
    pub status: Status,
    next_instruction: InstructionPointer,
    pub heap: Heap,
    pub data_stack: Vec<Pointer>,
    pub call_stack: Vec<InstructionPointer>,
    pub import_stack: Vec<Module>,
    pub tracer: Tracer,
    pub fuzzable_closures: Vec<(Id, Pointer)>,
    pub num_instructions_executed: usize,
}

#[derive(Clone, Debug)]
pub enum Status {
    Running,
    Done,
    Panicked { reason: String },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InstructionPointer {
    /// Pointer to the closure object that is currently running code.
    closure: Pointer,

    /// Index of the next instruction to run.
    instruction: usize,
}
impl InstructionPointer {
    fn null_pointer() -> Self {
        Self {
            closure: Pointer::null(),
            instruction: 0,
        }
    }
    fn start_of_closure(closure: Pointer) -> Self {
        Self {
            closure,
            instruction: 0,
        }
    }
}

pub struct TearDownResult {
    pub heap: Heap,
    pub result: Result<Pointer, String>,
    pub fuzzable_closures: Vec<(Id, Pointer)>,
    pub tracer: Tracer,
}

impl Vm {
    fn new_with_heap(heap: Heap) -> Self {
        Self {
            status: Status::Done,
            next_instruction: InstructionPointer::null_pointer(),
            heap,
            data_stack: vec![],
            call_stack: vec![],
            import_stack: vec![],
            tracer: Tracer::default(),
            fuzzable_closures: vec![],
            num_instructions_executed: 0,
        }
    }
    pub fn new_for_running_closure<U: UseProvider>(
        heap: Heap,
        use_provider: &U,
        closure: Pointer,
        arguments: &[Pointer],
    ) -> Self {
        let mut vm = Self::new_with_heap(heap);

        vm.data_stack.extend(arguments);
        vm.data_stack.push(closure);

        vm.status = Status::Running;
        vm.run_instruction(
            use_provider,
            Instruction::Call {
                num_args: arguments.len(),
            },
        );
        vm
    }
    pub fn new_for_running_module_closure<U: UseProvider>(
        use_provider: &U,
        closure: Closure,
    ) -> Self {
        assert_eq!(closure.captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
        assert_eq!(closure.num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        let mut heap = Heap::default();
        let closure = heap.create_closure(closure);
        Self::new_for_running_closure(heap, use_provider, closure, &[])
    }
    pub fn tear_down(mut self) -> TearDownResult {
        let result = match self.status {
            Status::Running => panic!("Called `tear_down` on a VM that's still running."),
            Status::Done => Ok(self.data_stack.pop().unwrap()),
            Status::Panicked { reason } => Err(reason),
        };
        TearDownResult {
            heap: self.heap,
            result,
            fuzzable_closures: self.fuzzable_closures,
            tracer: self.tracer,
        }
    }

    pub fn status(&self) -> Status {
        self.status.clone()
    }

    fn get_from_data_stack(&self, offset: usize) -> Pointer {
        self.data_stack[self.data_stack.len() - 1 - offset as usize]
    }

    pub fn run<U: UseProvider>(&mut self, use_provider: &U, mut num_instructions: usize) {
        assert!(
            matches!(self.status, Status::Running),
            "Called Vm::run on a vm that is not ready to run."
        );
        while matches!(self.status, Status::Running) && num_instructions > 0 {
            num_instructions -= 1;

            let current_closure = self.heap.get(self.next_instruction.closure);
            let current_body = if let Data::Closure(Closure { body, .. }) = &current_closure.data {
                body
            } else {
                panic!("The instruction pointer points to a non-closure.");
            };
            let instruction = current_body[self.next_instruction.instruction].clone();

            if TRACE {
                trace!(
                    "Data stack: {}",
                    self.data_stack
                        .iter()
                        .map(|address| format!("{}", self.heap.export_without_dropping(*address)))
                        .join(", ")
                );
                trace!(
                    "Call stack: {}",
                    self.call_stack
                        .iter()
                        .map(|ip| format!("{}:{}", ip.closure, ip.instruction))
                        .join(", ")
                );
                trace!(
                    "Instruction pointer: {}:{}",
                    self.next_instruction.closure,
                    self.next_instruction.instruction
                );
                trace!("Heap: {:?}", self.heap);
                trace!("Running instruction: {instruction:?}");
            }

            self.next_instruction.instruction += 1;
            self.run_instruction(use_provider, instruction);
            self.num_instructions_executed += 1;

            if self.next_instruction == InstructionPointer::null_pointer() {
                self.status = Status::Done;
            }
        }
    }
    pub fn run_instruction<U: UseProvider>(&mut self, use_provider: &U, instruction: Instruction) {
        match instruction {
            Instruction::CreateInt(int) => {
                let address = self.heap.create_int(int.into());
                self.data_stack.push(address);
            }
            Instruction::CreateText(text) => {
                let address = self.heap.create_text(text);
                self.data_stack.push(address);
            }
            Instruction::CreateSymbol(symbol) => {
                let address = self.heap.create_symbol(symbol);
                self.data_stack.push(address);
            }
            Instruction::CreateStruct { num_entries } => {
                let mut key_value_addresses = vec![];
                for _ in 0..(2 * num_entries) {
                    key_value_addresses.push(self.data_stack.pop().unwrap());
                }
                let mut entries = HashMap::new();
                for mut key_and_value in &key_value_addresses.into_iter().rev().chunks(2) {
                    let key = key_and_value.next().unwrap();
                    let value = key_and_value.next().unwrap();
                    assert_eq!(key_and_value.next(), None);
                    entries.insert(key, value);
                }
                let address = self.heap.create_struct(entries);
                self.data_stack.push(address);
            }
            Instruction::CreateClosure {
                num_args,
                body,
                captured,
            } => {
                let captured = captured
                    .iter()
                    .map(|offset| self.get_from_data_stack(*offset))
                    .collect_vec();
                for address in &captured {
                    self.heap.dup(*address);
                }
                let address = self.heap.create_closure(Closure {
                    captured,
                    num_args,
                    body,
                });
                self.data_stack.push(address);
            }
            Instruction::CreateBuiltin(builtin) => {
                let address = self.heap.create_builtin(builtin);
                self.data_stack.push(address);
            }
            Instruction::PushFromStack(offset) => {
                let address = self.get_from_data_stack(offset);
                self.heap.dup(address);
                self.data_stack.push(address);
            }
            Instruction::PopMultipleBelowTop(n) => {
                let top = self.data_stack.pop().unwrap();
                for _ in 0..n {
                    let address = self.data_stack.pop().unwrap();
                    self.heap.drop(address);
                }
                self.data_stack.push(top);
            }
            Instruction::Call { num_args } => {
                let closure_address = self.data_stack.pop().unwrap();
                let mut args = vec![];
                for _ in 0..num_args {
                    args.push(self.data_stack.pop().unwrap());
                }
                args.reverse();

                match self.heap.get(closure_address).data.clone() {
                    Data::Closure(Closure {
                        captured,
                        num_args: expected_num_args,
                        ..
                    }) => {
                        if num_args != expected_num_args {
                            self.panic(format!("Closure expects {expected_num_args} parameters, but you called it with {num_args} arguments."));
                            return;
                        }

                        self.call_stack.push(self.next_instruction);
                        self.data_stack.append(&mut captured.clone());
                        for captured in captured {
                            self.heap.dup(captured);
                        }
                        self.data_stack.append(&mut args);
                        self.next_instruction =
                            InstructionPointer::start_of_closure(closure_address);
                    }
                    Data::Builtin(Builtin { function: builtin }) => {
                        self.heap.drop(closure_address);
                        self.run_builtin_function(use_provider, &builtin, &args);
                    }
                    _ => {
                        self.panic("you can only call closures and builtins".to_string());
                    }
                };
            }
            Instruction::Return => {
                self.heap.drop(self.next_instruction.closure);
                let caller = self.call_stack.pop().unwrap();
                self.next_instruction = caller;
            }
            Instruction::UseModule { current_module } => {
                let relative_path = self.data_stack.pop().unwrap();
                match self.use_module(use_provider, current_module, relative_path) {
                    Ok(()) => {}
                    Err(reason) => {
                        self.panic(reason);
                    }
                }
            }
            Instruction::Needs => {
                let reason = self.data_stack.pop().unwrap();
                let condition = self.data_stack.pop().unwrap();

                let reason = match self.heap.get(reason).data.clone() {
                    Data::Text(reason) => reason.value,
                    _ => {
                        self.panic("you can only use text as the reason of a `needs`".to_string());
                        return;
                    }
                };

                match self.heap.get(condition).data.clone() {
                    Data::Symbol(symbol) => match symbol.value.as_str() {
                        "True" => {
                            self.data_stack.push(self.heap.create_nothing());
                        }
                        "False" => self.status = Status::Panicked { reason },
                        _ => {
                            self.panic("Needs expects True or False as a symbol.".to_string());
                        }
                    },
                    _ => {
                        self.panic("Needs expects a boolean symbol.".to_string());
                    }
                }
            }
            Instruction::RegisterFuzzableClosure(id) => {
                let closure = *self.data_stack.last().unwrap();
                if !matches!(self.heap.get(closure).data, Data::Closure(_)) {
                    panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a closure.");
                }
                self.heap.dup(closure);
                self.fuzzable_closures.push((id, closure));
            }
            Instruction::TraceValueEvaluated(id) => {
                let value = *self.data_stack.last().unwrap();
                self.heap.dup(value);
                self.tracer.push(TraceEntry::ValueEvaluated { id, value });
            }
            Instruction::TraceCallStarts { id, num_args } => {
                let closure = *self.data_stack.last().unwrap();
                self.heap.dup(closure);

                let mut args = vec![];
                let stack_size = self.data_stack.len();
                for i in 0..num_args {
                    let argument = self.data_stack[stack_size - i - 2];
                    self.heap.dup(argument);
                    args.push(argument);
                }
                args.reverse();

                self.tracer
                    .push(TraceEntry::CallStarted { id, closure, args });
            }
            Instruction::TraceCallEnds => {
                let return_value = *self.data_stack.last().unwrap();
                self.heap.dup(return_value);
                self.tracer.push(TraceEntry::CallEnded { return_value });
            }
            Instruction::TraceNeedsStarts { id } => {
                let condition = self.data_stack[self.data_stack.len() - 1];
                let reason = self.data_stack[self.data_stack.len() - 2];
                self.heap.dup(condition);
                self.heap.dup(reason);
                self.tracer.push(TraceEntry::NeedsStarted {
                    id,
                    condition,
                    reason,
                });
            }
            Instruction::TraceNeedsEnds => self.tracer.push(TraceEntry::NeedsEnded),
            Instruction::TraceModuleStarts { module } => {
                if self.import_stack.contains(&module) {
                    self.panic(format!(
                        "there's an import cycle ({})",
                        self.import_stack
                            .iter()
                            .skip_while(|it| **it != module)
                            .chain([&module])
                            .map(|module| format!("{module}"))
                            .join(" → "),
                    ));
                }
                self.import_stack.push(module.clone());
                self.tracer.push(TraceEntry::ModuleStarted { module });
            }
            Instruction::TraceModuleEnds => {
                self.import_stack.pop().unwrap();
                let export_map = *self.data_stack.last().unwrap();
                self.heap.dup(export_map);
                self.tracer.push(TraceEntry::ModuleEnded { export_map })
            }
            Instruction::Error { id, errors } => {
                self.panic(format!(
                    "The VM crashed because there {} at {id}: {errors:?}",
                    if errors.len() == 1 {
                        "was an error"
                    } else {
                        "were errors"
                    }
                ));
            }
        }
    }

    pub fn panic(&mut self, reason: String) {
        self.status = Status::Panicked { reason };
    }

    pub fn run_synchronously_until_completion(mut self, db: &Database) -> TearDownResult {
        let use_provider = DbUseProvider { db };
        loop {
            self.run(&use_provider, 100000);
            match self.status() {
                Status::Running => info!("Code is still running."),
                _ => return self.tear_down(),
            }
        }
    }
}
<commit_msg>Fix VM logging code<commit_after>use super::{
    heap::{Builtin, Closure, Data, Heap, Pointer},
    tracer::{TraceEntry, Tracer},
    use_provider::{DbUseProvider, UseProvider},
};
use crate::{
    compiler::{hir::Id, lir::Instruction},
    database::Database,
    module::Module,
};
use itertools::Itertools;
use std::collections::HashMap;
use tracing::{info, trace};

const TRACE: bool = false;

/// A VM can execute some byte code.
#[derive(Clone)]
pub struct Vm {
    pub status: Status,
    next_instruction: InstructionPointer,
    pub heap: Heap,
    pub data_stack: Vec<Pointer>,
    pub call_stack: Vec<InstructionPointer>,
    pub import_stack: Vec<Module>,
    pub tracer: Tracer,
    pub fuzzable_closures: Vec<(Id, Pointer)>,
    pub num_instructions_executed: usize,
}

#[derive(Clone, Debug)]
pub enum Status {
    Running,
    Done,
    Panicked { reason: String },
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InstructionPointer {
    /// Pointer to the closure object that is currently running code.
    closure: Pointer,

    /// Index of the next instruction to run.
    instruction: usize,
}
impl InstructionPointer {
    fn null_pointer() -> Self {
        Self {
            closure: Pointer::null(),
            instruction: 0,
        }
    }
    fn start_of_closure(closure: Pointer) -> Self {
        Self {
            closure,
            instruction: 0,
        }
    }
}

pub struct TearDownResult {
    pub heap: Heap,
    pub result: Result<Pointer, String>,
    pub fuzzable_closures: Vec<(Id, Pointer)>,
    pub tracer: Tracer,
}

impl Vm {
    fn new_with_heap(heap: Heap) -> Self {
        Self {
            status: Status::Done,
            next_instruction: InstructionPointer::null_pointer(),
            heap,
            data_stack: vec![],
            call_stack: vec![],
            import_stack: vec![],
            tracer: Tracer::default(),
            fuzzable_closures: vec![],
            num_instructions_executed: 0,
        }
    }
    pub fn new_for_running_closure<U: UseProvider>(
        heap: Heap,
        use_provider: &U,
        closure: Pointer,
        arguments: &[Pointer],
    ) -> Self {
        let mut vm = Self::new_with_heap(heap);

        vm.data_stack.extend(arguments);
        vm.data_stack.push(closure);

        vm.status = Status::Running;
        vm.run_instruction(
            use_provider,
            Instruction::Call {
                num_args: arguments.len(),
            },
        );
        vm
    }
    pub fn new_for_running_module_closure<U: UseProvider>(
        use_provider: &U,
        closure: Closure,
    ) -> Self {
        assert_eq!(closure.captured.len(), 0, "Called start_module_closure with a closure that is not a module closure (it captures stuff).");
        assert_eq!(closure.num_args, 0, "Called start_module_closure with a closure that is not a module closure (it has arguments).");
        let mut heap = Heap::default();
        let closure = heap.create_closure(closure);
        Self::new_for_running_closure(heap, use_provider, closure, &[])
    }
    pub fn tear_down(mut self) -> TearDownResult {
        let result = match self.status {
            Status::Running => panic!("Called `tear_down` on a VM that's still running."),
            Status::Done => Ok(self.data_stack.pop().unwrap()),
            Status::Panicked { reason } => Err(reason),
        };
        TearDownResult {
            heap: self.heap,
            result,
            fuzzable_closures: self.fuzzable_closures,
            tracer: self.tracer,
        }
    }

    pub fn status(&self) -> Status {
        self.status.clone()
    }

    fn get_from_data_stack(&self, offset: usize) -> Pointer {
        self.data_stack[self.data_stack.len() - 1 - offset as usize]
    }

    pub fn run<U: UseProvider>(&mut self, use_provider: &U, mut num_instructions: usize) {
        assert!(
            matches!(self.status, Status::Running),
            "Called Vm::run on a vm that is not ready to run."
        );
        while matches!(self.status, Status::Running) && num_instructions > 0 {
            num_instructions -= 1;

            let current_closure = self.heap.get(self.next_instruction.closure);
            let current_body = if let Data::Closure(Closure { body, .. }) = &current_closure.data {
                body
            } else {
                panic!("The instruction pointer points to a non-closure.");
            };
            let instruction = current_body[self.next_instruction.instruction].clone();

            if TRACE {
                trace!(
                    "Data stack: {}",
                    self.data_stack
                        .iter()
                        .map(|it| it.format(&self.heap))
                        .join(", ")
                );
                trace!(
                    "Call stack: {}",
                    self.call_stack
                        .iter()
                        .map(|ip| format!("{}:{}", ip.closure, ip.instruction))
                        .join(", ")
                );
                trace!(
                    "Instruction pointer: {}:{}",
                    self.next_instruction.closure,
                    self.next_instruction.instruction
                );
                trace!("Heap: {:?}", self.heap);
                trace!("Running instruction: {instruction:?}");
            }

            self.next_instruction.instruction += 1;
            self.run_instruction(use_provider, instruction);
            self.num_instructions_executed += 1;

            if self.next_instruction == InstructionPointer::null_pointer() {
                self.status = Status::Done;
            }
        }
    }
    pub fn run_instruction<U: UseProvider>(&mut self, use_provider: &U, instruction: Instruction) {
        match instruction {
            Instruction::CreateInt(int) => {
                let address = self.heap.create_int(int.into());
                self.data_stack.push(address);
            }
            Instruction::CreateText(text) => {
                let address = self.heap.create_text(text);
                self.data_stack.push(address);
            }
            Instruction::CreateSymbol(symbol) => {
                let address = self.heap.create_symbol(symbol);
                self.data_stack.push(address);
            }
            Instruction::CreateStruct { num_entries } => {
                let mut key_value_addresses = vec![];
                for _ in 0..(2 * num_entries) {
                    key_value_addresses.push(self.data_stack.pop().unwrap());
                }
                let mut entries = HashMap::new();
                for mut key_and_value in &key_value_addresses.into_iter().rev().chunks(2) {
                    let key = key_and_value.next().unwrap();
                    let value = key_and_value.next().unwrap();
                    assert_eq!(key_and_value.next(), None);
                    entries.insert(key, value);
                }
                let address = self.heap.create_struct(entries);
                self.data_stack.push(address);
            }
            Instruction::CreateClosure {
                num_args,
                body,
                captured,
            } => {
                let captured = captured
                    .iter()
                    .map(|offset| self.get_from_data_stack(*offset))
                    .collect_vec();
                for address in &captured {
                    self.heap.dup(*address);
                }
                let address = self.heap.create_closure(Closure {
                    captured,
                    num_args,
                    body,
                });
                self.data_stack.push(address);
            }
            Instruction::CreateBuiltin(builtin) => {
                let address = self.heap.create_builtin(builtin);
                self.data_stack.push(address);
            }
            Instruction::PushFromStack(offset) => {
                let address = self.get_from_data_stack(offset);
                self.heap.dup(address);
                self.data_stack.push(address);
            }
            Instruction::PopMultipleBelowTop(n) => {
                let top = self.data_stack.pop().unwrap();
                for _ in 0..n {
                    let address = self.data_stack.pop().unwrap();
                    self.heap.drop(address);
                }
                self.data_stack.push(top);
            }
            Instruction::Call { num_args } => {
                let closure_address = self.data_stack.pop().unwrap();
                let mut args = vec![];
                for _ in 0..num_args {
                    args.push(self.data_stack.pop().unwrap());
                }
                args.reverse();

                match self.heap.get(closure_address).data.clone() {
                    Data::Closure(Closure {
                        captured,
                        num_args: expected_num_args,
                        ..
                    }) => {
                        if num_args != expected_num_args {
                            self.panic(format!("Closure expects {expected_num_args} parameters, but you called it with {num_args} arguments."));
                            return;
                        }

                        self.call_stack.push(self.next_instruction);
                        self.data_stack.append(&mut captured.clone());
                        for captured in captured {
                            self.heap.dup(captured);
                        }
                        self.data_stack.append(&mut args);
                        self.next_instruction =
                            InstructionPointer::start_of_closure(closure_address);
                    }
                    Data::Builtin(Builtin { function: builtin }) => {
                        self.heap.drop(closure_address);
                        self.run_builtin_function(use_provider, &builtin, &args);
                    }
                    _ => {
                        self.panic("you can only call closures and builtins".to_string());
                    }
                };
            }
            Instruction::Return => {
                self.heap.drop(self.next_instruction.closure);
                let caller = self.call_stack.pop().unwrap();
                self.next_instruction = caller;
            }
            Instruction::UseModule { current_module } => {
                let relative_path = self.data_stack.pop().unwrap();
                match self.use_module(use_provider, current_module, relative_path) {
                    Ok(()) => {}
                    Err(reason) => {
                        self.panic(reason);
                    }
                }
            }
            Instruction::Needs => {
                let reason = self.data_stack.pop().unwrap();
                let condition = self.data_stack.pop().unwrap();

                let reason = match self.heap.get(reason).data.clone() {
                    Data::Text(reason) => reason.value,
                    _ => {
                        self.panic("you can only use text as the reason of a `needs`".to_string());
                        return;
                    }
                };

                match self.heap.get(condition).data.clone() {
                    Data::Symbol(symbol) => match symbol.value.as_str() {
                        "True" => {
                            self.data_stack.push(self.heap.create_nothing());
                        }
                        "False" => self.status = Status::Panicked { reason },
                        _ => {
                            self.panic("Needs expects True or False as a symbol.".to_string());
                        }
                    },
                    _ => {
                        self.panic("Needs expects a boolean symbol.".to_string());
                    }
                }
            }
            Instruction::RegisterFuzzableClosure(id) => {
                let closure = *self.data_stack.last().unwrap();
                if !matches!(self.heap.get(closure).data, Data::Closure(_)) {
                    panic!("Instruction RegisterFuzzableClosure executed, but stack top is not a closure.");
                }
                self.heap.dup(closure);
                self.fuzzable_closures.push((id, closure));
            }
            Instruction::TraceValueEvaluated(id) => {
                let value = *self.data_stack.last().unwrap();
                self.heap.dup(value);
                self.tracer.push(TraceEntry::ValueEvaluated { id, value });
            }
            Instruction::TraceCallStarts { id, num_args } => {
                let closure = *self.data_stack.last().unwrap();
                self.heap.dup(closure);

                let mut args = vec![];
                let stack_size = self.data_stack.len();
                for i in 0..num_args {
                    let argument = self.data_stack[stack_size - i - 2];
                    self.heap.dup(argument);
                    args.push(argument);
                }
                args.reverse();

                self.tracer
                    .push(TraceEntry::CallStarted { id, closure, args });
            }
            Instruction::TraceCallEnds => {
                let return_value = *self.data_stack.last().unwrap();
                self.heap.dup(return_value);
                self.tracer.push(TraceEntry::CallEnded { return_value });
            }
            Instruction::TraceNeedsStarts { id } => {
                let condition = self.data_stack[self.data_stack.len() - 1];
                let reason = self.data_stack[self.data_stack.len() - 2];
                self.heap.dup(condition);
                self.heap.dup(reason);
                self.tracer.push(TraceEntry::NeedsStarted {
                    id,
                    condition,
                    reason,
                });
            }
            Instruction::TraceNeedsEnds => self.tracer.push(TraceEntry::NeedsEnded),
            Instruction::TraceModuleStarts { module } => {
                if self.import_stack.contains(&module) {
                    self.panic(format!(
                        "there's an import cycle ({})",
                        self.import_stack
                            .iter()
                            .skip_while(|it| **it != module)
                            .chain([&module])
                            .map(|module| format!("{module}"))
                            .join(" → "),
                    ));
                }
                self.import_stack.push(module.clone());
                self.tracer.push(TraceEntry::ModuleStarted { module });
            }
            Instruction::TraceModuleEnds => {
                self.import_stack.pop().unwrap();
                let export_map = *self.data_stack.last().unwrap();
                self.heap.dup(export_map);
                self.tracer.push(TraceEntry::ModuleEnded { export_map })
            }
            Instruction::Error { id, errors } => {
                self.panic(format!(
                    "The VM crashed because there {} at {id}: {errors:?}",
                    if errors.len() == 1 {
                        "was an error"
                    } else {
                        "were errors"
                    }
                ));
            }
        }
    }

    pub fn panic(&mut self, reason: String) {
        self.status = Status::Panicked { reason };
    }

    pub fn run_synchronously_until_completion(mut self, db: &Database) -> TearDownResult {
        let use_provider = DbUseProvider { db };
        loop {
            self.run(&use_provider, 100000);
            match self.status() {
                Status::Running => info!("Code is still running."),
                _ => return self.tear_down(),
            }
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Update main.rs<commit_after><|endoftext|>


<commit_before>#[derive(Eq, PartialEq)]
enum Direction { North, East, South, West, Unplaced, }

use Direction::*;

struct Table {
    w: i32,
    h: i32,
}

struct Robot {
    x: i32,
    y: i32,
    d: Direction,
    t: Table,
}

trait FirstChar {
    fn first_char(&self) -> Option<char>;
}

impl FirstChar for str {
    fn first_char(&self) -> Option<char> {
        let chars = self.chars().collect::<Vec<char>>();

        match chars.first() {
            Some(c) => Some(*c),
            _ => None,
        }
    }
}

impl Direction {
    fn from_string(d: &str) -> Option<Direction> {
        match d {
            "NORTH" => Some(North),
            "EAST" => Some(East),
            "SOUTH" => Some(South),
            "WEST" => Some(West),
            _ => None,
        }
    }

    fn to_string(&self) -> String {
        let s = match *self {
            North => "NORTH",
            East => "EAST",
            South => "SOUTH",
            West => "WEST",
            _ => "UNPLACED",
        };

        s.to_string()
    }
}

impl Default for Robot {
    fn default() -> Robot {
        let table = Table{w: 5, h: 5};

        Robot{x: 0, y: 0, d: Unplaced, t: table}
    }
}

impl Table {
    fn valid_pos(&self, x: i32, y: i32) -> bool {
        x >= 0 && x < self.w && y >= 0 && y < self.h
    }
}

impl Robot {
    fn place(&mut self, x: i32, y: i32, d: Direction) {
        if self.t.valid_pos(x, y) && d != Unplaced {
            self.x = x;
            self.y = y;
            self.d = d;
        }
    }

    fn right(&mut self) {
        let d = match self.d {
            North => East,
            East => South,
            South => West,
            West => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn left(&mut self) {
        let d = match self.d {
            North => West,
            West => South,
            South => East,
            East => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn step(&mut self) {
        match self.d {
            North => if self.t.valid_pos(self.x, self.y + 1) {self.y += 1;},
            East => if self.t.valid_pos(self.x + 1, self.y) {self.x += 1;},
            South => if self.t.valid_pos(self.x, self.y - 1) {self.y -= 1;},
            West => if self.t.valid_pos(self.x - 1, self.y) {self.y -= 1;},
            _ => (),
        }
    }

    fn report(&self) {
        println!("{}, {}, {}", self.x, self.y, self.d.to_string());
    }
}

fn parse_place(args: &[&str]) -> (i32, i32, Direction) {
    let (x, y, d) = (args[0].first_char().expect("Invalid place"),
                     args[1].first_char().expect("Invalid place"),
                     Direction::from_string(args[2]));

    match (x.to_digit(10), y.to_digit(10), d) {
        (Some(xpos), Some(ypos), Some(dir)) => (xpos as i32, ypos as i32, dir),
        _ => (0, 0, Unplaced),
    }
}

fn main() {
    let programs = ["PLACE 0 0 NORTH\nMOVE\nREPORT",
                    "PLACE 0 0 NORTH\nLEFT\nREPORT",
                    "MOVE\nLEFT\nPLACE 1 2 EAST\nEAST\nMOVE\nMOVE\nLEFT\nMOVE\nREPORT",
                    "PLACE 0 0 EAST\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nREPORT\nLEFT\nMOVE\nREPORT"];

    for p in programs.iter() {
        let mut robot: Robot = Default::default();
        let parsed: Vec<&str> = p.split("\n").map(|c| c.trim()).collect();

        for c in parsed {
            let args: Vec<&str> = c.split(" ").collect();

            if let Some(arg) = args.first() {
                match *arg {
                    "PLACE" if args.len() == 4 => {
                        let (x, y, d) = parse_place(&args[1..]);
                        robot.place(x, y, d);
                    },
                    "MOVE" => robot.step(),
                    "LEFT" => robot.left(),
                    "RIGHT" => robot.right(),
                    "REPORT" => robot.report(),
                    _ => (),
                }
            }
        }
    }
}
<commit_msg>Change to first_char_or<commit_after>#[derive(Eq, PartialEq)]
enum Direction { North, East, South, West, Unplaced, }

use Direction::*;

struct Table {
    w: i32,
    h: i32,
}

struct Robot {
    x: i32,
    y: i32,
    d: Direction,
    t: Table,
}

trait FirstChar {
    fn first_char_or(&self, default: char) -> char;
}

impl FirstChar for str {
    fn first_char_or(&self, default: char) -> char {
        match self.chars().nth(0) {
            Some(c) => c,
            None => default,
        }
    }
}

impl Direction {
    fn from_string(d: &str) -> Option<Direction> {
        match d {
            "NORTH" => Some(North),
            "EAST" => Some(East),
            "SOUTH" => Some(South),
            "WEST" => Some(West),
            _ => None,
        }
    }

    fn to_string(&self) -> String {
        let s = match *self {
            North => "NORTH",
            East => "EAST",
            South => "SOUTH",
            West => "WEST",
            _ => "UNPLACED",
        };

        s.to_string()
    }
}

impl Default for Robot {
    fn default() -> Robot {
        let table = Table{w: 5, h: 5};

        Robot{x: 0, y: 0, d: Unplaced, t: table}
    }
}

impl Table {
    fn valid_pos(&self, x: i32, y: i32) -> bool {
        x >= 0 && x < self.w && y >= 0 && y < self.h
    }
}

impl Robot {
    fn place(&mut self, x: i32, y: i32, d: Direction) {
        if self.t.valid_pos(x, y) && d != Unplaced {
            self.x = x;
            self.y = y;
            self.d = d;
        }
    }

    fn right(&mut self) {
        let d = match self.d {
            North => East,
            East => South,
            South => West,
            West => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn left(&mut self) {
        let d = match self.d {
            North => West,
            West => South,
            South => East,
            East => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn step(&mut self) {
        match self.d {
            North => if self.t.valid_pos(self.x, self.y + 1) {self.y += 1;},
            East => if self.t.valid_pos(self.x + 1, self.y) {self.x += 1;},
            South => if self.t.valid_pos(self.x, self.y - 1) {self.y -= 1;},
            West => if self.t.valid_pos(self.x - 1, self.y) {self.y -= 1;},
            _ => (),
        }
    }

    fn report(&self) {
        println!("{}, {}, {}", self.x, self.y, self.d.to_string());
    }
}

fn parse_place(args: &[&str]) -> (i32, i32, Direction) {
    let (x, y, d) = (args[0].first_char_or('0'),
                     args[1].first_char_or('0'),
                     Direction::from_string(args[2]));

    match (x.to_digit(10), y.to_digit(10), d) {
        (Some(xpos), Some(ypos), Some(dir)) => (xpos as i32, ypos as i32, dir),
        _ => (0, 0, Unplaced),
    }
}

fn main() {
    let programs = ["PLACE 0 0 NORTH\nMOVE\nREPORT",
                    "PLACE 0 0 NORTH\nLEFT\nREPORT",
                    "MOVE\nLEFT\nPLACE 1 2 EAST\nEAST\nMOVE\nMOVE\nLEFT\nMOVE\nREPORT",
                    "PLACE 0 0 EAST\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nMOVE\nREPORT\nLEFT\nMOVE\nREPORT"];

    for p in programs.iter() {
        let mut robot: Robot = Default::default();
        let parsed: Vec<&str> = p.split("\n").map(|c| c.trim()).collect();

        for c in parsed {
            let args: Vec<&str> = c.split(" ").collect();

            if let Some(arg) = args.first() {
                match *arg {
                    "PLACE" if args.len() == 4 => {
                        let (x, y, d) = parse_place(&args[1..]);
                        robot.place(x, y, d);
                    },
                    "MOVE" => robot.step(),
                    "LEFT" => robot.left(),
                    "RIGHT" => robot.right(),
                    "REPORT" => robot.report(),
                    _ => (),
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#[derive(Eq, PartialEq)]
enum Direction { North, East, South, West, Unplaced, }

use Direction::*;

struct Table {
    w: i32,
    h: i32,
}

struct Robot {
    x: i32,
    y: i32,
    d: Direction,
    t: Table,
}

impl Direction {
    fn from_string(d: String) -> Direction {
        match &d[..] {
            "NORTH" => North,
            "EAST" => East,
            "SOUTH" => South,
            "WEST" => West,
            _ => Unplaced,
        }
    }

    fn to_string(&self) -> String {
        let s = match *self {
            North => "NORTH",
            East => "EAST",
            South => "SOUTH",
            West => "WEST",
            _ => "UNPLACED",
        };

        s.to_string()
    }
}

impl Default for Robot {
    fn default() -> Robot {
        let table = Table{w: 5, h: 5};

        Robot{x: 0, y: 0, d: Unplaced, t: table}
    }
}

impl Table {
    fn valid_pos(&self, x: i32, y: i32) -> bool {
        x >= 0 && x < self.w && y >= 0 && y < self.h
    }
}

impl Robot {
    fn place(&mut self, x: i32, y: i32, d: Direction) {
        if self.t.valid_pos(x, y) && d != Unplaced {
            self.x = x;
            self.y = y;
            self.d = d;
        }
    }

    fn right(&mut self) {
        let d = match self.d {
            North => East,
            East => South,
            South => West,
            West => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn left(&mut self) {
        let d = match self.d {
            North => West,
            West => South,
            South => East,
            East => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn step(&mut self) {
        match self.d {
            North => if self.t.valid_pos(self.x, self.y + 1) {self.y += 1;},
            East => if self.t.valid_pos(self.x + 1, self.y) {self.x += 1;},
            South => if self.t.valid_pos(self.x, self.y - 1) {self.y -= 1;},
            West => if self.t.valid_pos(self.x - 1, self.y) {self.y -= 1;},
            _ => (),
        }
    }

    fn report(&self) {
        println!("{}, {}, {}", self.x, self.y, self.d.to_string());
    }
}

fn parse_place(args: &[&str]) -> (i32, i32, Direction) {
    (1, 2, East)
}

fn main() {
    let mut robot: Robot = Default::default();
    let commands = "MOVE
                    MOVE
                    LEFT
                    PLACE 1 2 EAST
                    MOVE
                    MOVE
                    LEFT
                    MOVE
                    REPORT";

    let parsed: Vec<&str> = commands.split("\n").map(|c| c.trim()).collect();

    for c in parsed {
        let args: Vec<&str> = c.split(" ").collect();

        if let Some(arg) = args.first() {
            match *arg {
                "PLACE" if args.len() == 4 => {
                    let (x, y, d) = parse_place(&args[1..]);
                    robot.place(x, y, d);
                },
                "MOVE" => robot.step(),
                "LEFT" => robot.left(),
                "RIGHT" => robot.right(),
                "REPORT" => robot.report(),
                _ => (),
            }
        }
    }
}
<commit_msg>Added parse_place function<commit_after>#[derive(Eq, PartialEq)]
enum Direction { North, East, South, West, Unplaced, }

use Direction::*;

struct Table {
    w: i32,
    h: i32,
}

struct Robot {
    x: i32,
    y: i32,
    d: Direction,
    t: Table,
}

impl Direction {
    fn from_string(d: &str) -> Option<Direction> {
        match d {
            "NORTH" => Some(North),
            "EAST" => Some(East),
            "SOUTH" => Some(South),
            "WEST" => Some(West),
            _ => None,
        }
    }

    fn to_string(&self) -> String {
        let s = match *self {
            North => "NORTH",
            East => "EAST",
            South => "SOUTH",
            West => "WEST",
            _ => "UNPLACED",
        };

        s.to_string()
    }
}

impl Default for Robot {
    fn default() -> Robot {
        let table = Table{w: 5, h: 5};

        Robot{x: 0, y: 0, d: Unplaced, t: table}
    }
}

impl Table {
    fn valid_pos(&self, x: i32, y: i32) -> bool {
        x >= 0 && x < self.w && y >= 0 && y < self.h
    }
}

impl Robot {
    fn place(&mut self, x: i32, y: i32, d: Direction) {
        if self.t.valid_pos(x, y) && d != Unplaced {
            self.x = x;
            self.y = y;
            self.d = d;
        }
    }

    fn right(&mut self) {
        let d = match self.d {
            North => East,
            East => South,
            South => West,
            West => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn left(&mut self) {
        let d = match self.d {
            North => West,
            West => South,
            South => East,
            East => North,
            _ => Unplaced,
        };

        self.d = d;
    }

    fn step(&mut self) {
        match self.d {
            North => if self.t.valid_pos(self.x, self.y + 1) {self.y += 1;},
            East => if self.t.valid_pos(self.x + 1, self.y) {self.x += 1;},
            South => if self.t.valid_pos(self.x, self.y - 1) {self.y -= 1;},
            West => if self.t.valid_pos(self.x - 1, self.y) {self.y -= 1;},
            _ => (),
        }
    }

    fn report(&self) {
        println!("{}, {}, {}", self.x, self.y, self.d.to_string());
    }
}

fn parse_place(args: &[&str]) -> (i32, i32, Direction) {
    // TODO: Implement trait for str with first_char():
    //*args[0].first_char().expect("Invalid X pos");
    let (x, y, d) = (*args[0].chars().collect::<Vec<char>>().first().expect("Invalid place"),
                     *args[1].chars().collect::<Vec<char>>().first().expect("Invalid place"),
                     Direction::from_string(args[2]));

    match (x.to_digit(10), y.to_digit(10), d) {
        (Some(xpos), Some(ypos), Some(dir)) => (xpos as i32, ypos as i32, dir),
        _ => (0, 0, Unplaced),
    }
}

fn main() {
    let mut robot: Robot = Default::default();
    let commands = "MOVE
                    LEFT
                    PLACE 1 2 EAST
                    MOVE
                    MOVE
                    LEFT
                    MOVE
                    REPORT";

    let parsed: Vec<&str> = commands.split("\n").map(|c| c.trim()).collect();

    for c in parsed {
        let args: Vec<&str> = c.split(" ").collect();

        if let Some(arg) = args.first() {
            match *arg {
                "PLACE" if args.len() == 4 => {
                    let (x, y, d) = parse_place(&args[1..]);
                    robot.place(x, y, d);
                },
                "MOVE" => robot.step(),
                "LEFT" => robot.left(),
                "RIGHT" => robot.right(),
                "REPORT" => robot.report(),
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

use std::io::fs::PathExtensions;
use std::io::fs;
use std::io::File;
use std::io::BufferedReader;

#[deriving(Clone,Show)]
struct ProcessRecord {
    name: String,
    pid: int,
    ppid: int
}

#[deriving(Clone,Show)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[deriving(Clone,Show)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<int> = None;
    let mut ppid : Option<int> = None;
    let mut name : Option<String> = None;

    let mut status_file = BufferedReader::new(File::open(status_path));
    for line in status_file.lines() {
        let unwrapped = line.unwrap(); // need a new lifeline
        let parts : Vec<&str> = unwrapped.as_slice().splitn(2, ':').collect();
        if parts.len() == 2 {
            let key = parts[0].trim();
            let value = parts[1].trim();
            match key {
                "Name" => name = Some(value.to_string()),
                "Pid" => pid = from_str(value),
                "PPid" => ppid = from_str(value),
                _ => (),
            }
        }
    }

    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let mut records : Vec<ProcessRecord> = Vec::new();
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = match fs::readdir(&proc_directory) {
        Err(why) => fail!("{}", why.desc),
        Ok(res) => res
    };

    for entry in proc_directory_contents.iter().filter(|entry| entry.is_dir()) {
        let status_path = entry.join("status");
        if status_path.exists() {
            match get_process_record(&status_path) {
                Some(record) => records.push(record),
                None => (),
            }
        }
    }
    records
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // populate the node by finding its children... recursively
    let pid = node.record.pid; // avoid binding node as immutable in closure
    for record in records.iter().filter(|record| record.ppid == pid) {
        let mut child = ProcessTreeNode::new(record);
        populate_node(&mut child, records);
        node.children.push(child);
    }
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord { name: "/".to_string(), pid: 0, ppid: -1 })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : int) {
    // print indentation
    for _ in range(0, indent_level * 2) {
        print!(" ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<commit_msg>nightlies: Update code to build/run with latest 1.0.0 compiler<commit_after>// A version of pstree targetting linux written in rust!
//
// This is based on the following exercise from the excellent
// book "The Linux Programming Interface" by Michael Kerridsk.
//
//----------------------------------------------------------------------
//
// Write a program that draws a tree showing the hierarchical
// parent-child relationships of all processes on the system, going all
// the way back to init.  For each process, the program should display
// the process ID and the command being executed.  The output of the
// program should be similar to that produced by pstree(1), although it
// does need not to be as sophisticated.  The parent of each process on
// the system can be found by inspecing the PPid: line of all of the
// /proc/PID/status files on the system.  Be careful to handle the
// possibilty that a process's parent (and thus its /proc/PID directory)
// disappears during the scan of all /proc/PID directories.

// Implementation Notes
// --------------------
// The linux /proc filesystem is a virtual filesystem that provides information
// about processes running on a linux system among other things.  The /proc
// filesystem contains a directory, /proc/<pid>, for each running process in
// the system.
//
// Each process directory has a status file with contents including a bunch
// of different items, notably the process name and its parent process id (ppid).
// And with that information, we can build the process tree.

#![feature(old_io)]
#![feature(old_path)]

use std::old_io::fs::PathExtensions;
use std::old_io::fs;
use std::old_io::File;
use std::old_io::BufferedReader;

#[derive(Clone,Debug)]
struct ProcessRecord {
    name: String,
    pid: isize,
    ppid: isize,
}

#[derive(Clone,Debug)]
struct ProcessTreeNode {
    record: ProcessRecord,  // the node owns the associated record
    children: Vec<ProcessTreeNode>, // nodes own their children
}

#[derive(Clone,Debug)]
struct ProcessTree {
    root: ProcessTreeNode, // tree owns ref to root node
}

impl ProcessTreeNode {
    // constructor
    fn new(record : &ProcessRecord) -> ProcessTreeNode {
        ProcessTreeNode { record: (*record).clone(), children: Vec::new() }
    }
}

// Given a status file path, return a hashmap with the following form:
// pid -> ProcessRecord
fn get_process_record(status_path: &Path) -> Option<ProcessRecord> {
    let mut pid : Option<isize> = None;
    let mut ppid : Option<isize> = None;
    let mut name : Option<String> = None;

    let mut status_file = BufferedReader::new(File::open(status_path));
    for line in status_file.lines() {
        let unwrapped = line.unwrap(); // need a new lifeline
        let parts : Vec<&str> = unwrapped[..].splitn(2, ':').collect();
        if parts.len() == 2 {
            let key = parts[0].trim();
            let value = parts[1].trim();
            match key {
                "Name" => name = Some(value.to_string()),
                "Pid" => pid = value.parse().ok(),
                "PPid" => ppid = value.parse().ok(),
                _ => (),
            }
        }
    }

    return if pid.is_some() && ppid.is_some() && name.is_some() {
        Some(ProcessRecord { name: name.unwrap(), pid: pid.unwrap(), ppid: ppid.unwrap() })
    } else {
        None
    }
}

// build a simple struct (ProcessRecord) for each process
fn get_process_records() -> Vec<ProcessRecord> {
    let mut records : Vec<ProcessRecord> = Vec::new();
    let proc_directory = Path::new("/proc");

    // find potential process directories under /proc
    let proc_directory_contents = match fs::readdir(&proc_directory) {
        Err(why) => panic!("{}", why.desc),
        Ok(res) => res
    };

    for entry in proc_directory_contents.iter().filter(|entry| entry.is_dir()) {
        let status_path = entry.join("status");
        if status_path.exists() {
            match get_process_record(&status_path) {
                Some(record) => {
                    records.push(record)
                },
                None => (),
            }
        }
    }
    records
}

fn populate_node(node : &mut ProcessTreeNode, records: &Vec<ProcessRecord>) {
    // populate the node by finding its children... recursively
    let pid = node.record.pid; // avoid binding node as immutable in closure
    node.children.extend(
        records.iter()
            .filter(|record| record.ppid == pid)
            .map(|record| {
                let mut child = ProcessTreeNode::new(record);
                populate_node(&mut child, records);
                child
            })
    );
}

fn build_process_tree() -> ProcessTree {
    let records = get_process_records();
    let mut tree = ProcessTree {
        root : ProcessTreeNode::new(
            &ProcessRecord {
                name: "/".to_string(),
                pid: 0,
                ppid: -1
            })
    };

    // recursively populate all nodes in the tree starting from root (pid 0)
    {
        let root = &mut tree.root;
        populate_node(root, &records);
    }
    tree
}

fn print_node(node : &ProcessTreeNode, indent_level : i32) {
    // print indentation
    for _ in (0..indent_level) {
        print!("  ");
    }
    println!("- {} #{}", node.record.name, node.record.pid);
    for child in node.children.iter() {
        print_node(child, indent_level + 1);  // recurse
    }
}

fn main() {
    let ptree = build_process_tree();
    print_node(&(ptree.root), 0)
}
<|endoftext|>


<commit_before>use core::fmt::{self, Write};
use core::result;

use system::syscall::{sys_write, sys_exit};

pub struct DebugStream;

impl Write for DebugStream {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let _ = sys_write(2, s.as_bytes());

        result::Result::Ok(())
    }
}

#[lang="panic_fmt"]
#[allow(unused_must_use)]
pub extern "C" fn panic_impl(args: &fmt::Arguments, file: &'static str, line: u32) -> ! {
    let mut stream = DebugStream;
    stream.write_str(file);
    stream.write_fmt(format_args!(":{}: ", line));
    stream.write_fmt(*args);
    stream.write_str("\n");

    loop {
        let _ = sys_exit(128);
    }
}
<commit_msg>Error checking in panic<commit_after>use core::fmt::{self, Write};
use core::result;

use system::syscall::{sys_write, sys_exit};

pub struct DebugStream;

impl Write for DebugStream {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        if let Err(_err) = sys_write(2, s.as_bytes()) {
            result::Result::Err(fmt::Error)
        } else {
            result::Result::Ok(())
        }
    }
}

#[lang="panic_fmt"]
#[allow(unused_must_use)]
pub extern "C" fn panic_impl(args: &fmt::Arguments, file: &'static str, line: u32) -> ! {
    let mut stream = DebugStream;
    stream.write_fmt(format_args!("Panic in {}:{}: {}\n", file, line, *args));

    loop {
        let _ = sys_exit(128);
    }
}
<|endoftext|>


<commit_before>use crate::std::fmt;

/// A general error that can occur when working with UUIDs.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error(pub(crate) ErrorKind);

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(crate) enum ErrorKind {
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    Char { character: char, index: usize },
    /// A simple [`Uuid`] didn't contain 32 characters.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    SimpleLength { len: usize },
    /// A hyphenated [`Uuid`] didn't contain 5 groups
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupCount { count: usize },
    /// A hyphenated [`Uuid`] had a group that wasn't the right length
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupLength {
        group: usize,
        len: usize,
        index: usize,
    },
}

/// A string that is guaranteed to fail to parse to a [`Uuid`].
///
/// This type acts as a lightweight error indicator, suggesting
/// that the string cannot be parsed but offering no error
/// details. To get details, use `InvalidUuid::into_err`.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct InvalidUuid<'a>(pub(crate) &'a str);

impl<'a> InvalidUuid<'a> {
    /// Converts the lightweight error type into detailed diagnostics.
    pub fn into_err(self) -> Error {
        let (s, offset, simple) = match self.0.as_bytes() {
            [b'{', s @ .., b'}'] => (s, 1, false),
            [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..] => {
                (s, "urn:uuid:".len(), false)
            }
            s => (s, 0, true),
        };

        let mut hyphen_count = 0;
        let mut group_bounds = [0; 4];

        // SAFETY: the byte array came from a valid utf8 string,
        // and is aligned along char boundries.
        let string = unsafe { std::str::from_utf8_unchecked(s) };

        for (index, character) in string.char_indices() {
            let byte = character as u8;
            if character as u32 - byte as u32 > 0 {
                // Multibyte char
                return Error(ErrorKind::Char {
                    character,
                    index: index + offset + 1,
                });
            } else if byte == b'-' {
                // While we search, also count group breaks
                if hyphen_count < 4 {
                    group_bounds[hyphen_count] = index;
                }
                hyphen_count += 1;
            } else if !matches!(byte, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F') {
                // Non-hex char
                return Error(ErrorKind::Char {
                    character: byte as char,
                    index: index + offset + 1,
                });
            }
        }

        if hyphen_count == 0 && simple {
            // This means that we tried and failed to parse a simple uuid.
            // Since we verified that all the characters are valid, this means
            // that it MUST have an invalid length.
            Error(ErrorKind::SimpleLength { len: s.len() })
        } else if hyphen_count != 4 {
            // We tried to parse a hyphenated variant, but there weren't
            // 5 groups (4 hyphen splits).
            Error(ErrorKind::GroupCount {
                count: hyphen_count + 1,
            })
        } else {
            // There are 5 groups, one of them has an incorrect length
            const BLOCK_STARTS: [usize; 5] = [0, 9, 14, 19, 24];
            for i in 0..4 {
                if group_bounds[i] != BLOCK_STARTS[i + 1] - 1 {
                    return Error(ErrorKind::GroupLength {
                        group: i,
                        len: group_bounds[i] - BLOCK_STARTS[i],
                        index: offset + BLOCK_STARTS[i] + 1,
                    });
                }
            }

            // The last group must be too long
            Error(ErrorKind::GroupLength {
                group: 4,
                len: s.len() - BLOCK_STARTS[4],
                index: offset + BLOCK_STARTS[4] + 1,
            })
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            ErrorKind::Char {
                character, index, ..
            } => {
                write!(f, "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `{}` at {}", character, index)
            }
            ErrorKind::SimpleLength { len } => {
                write!(
                    f,
                    "invalid length: expected length 32 for simple format, found {}",
                    len
                )
            }
            ErrorKind::GroupCount { count } => {
                write!(f, "invalid group count: expected 5, found {}", count)
            }
            ErrorKind::GroupLength { group, len, .. } => {
                let expected = [8, 4, 4, 4, 12][group];
                write!(
                    f,
                    "invalid group length in group {}: expected {}, found {}",
                    group, expected, len
                )
            }
        }
    }
}
<commit_msg>fix up import<commit_after>use std::fmt;

/// A general error that can occur when working with UUIDs.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Error(pub(crate) ErrorKind);

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(crate) enum ErrorKind {
    /// Invalid character in the [`Uuid`] string.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    Char { character: char, index: usize },
    /// A simple [`Uuid`] didn't contain 32 characters.
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    SimpleLength { len: usize },
    /// A hyphenated [`Uuid`] didn't contain 5 groups
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupCount { count: usize },
    /// A hyphenated [`Uuid`] had a group that wasn't the right length
    ///
    /// [`Uuid`]: ../struct.Uuid.html
    GroupLength {
        group: usize,
        len: usize,
        index: usize,
    },
}

/// A string that is guaranteed to fail to parse to a [`Uuid`].
///
/// This type acts as a lightweight error indicator, suggesting
/// that the string cannot be parsed but offering no error
/// details. To get details, use `InvalidUuid::into_err`.
///
/// [`Uuid`]: ../struct.Uuid.html
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct InvalidUuid<'a>(pub(crate) &'a str);

impl<'a> InvalidUuid<'a> {
    /// Converts the lightweight error type into detailed diagnostics.
    pub fn into_err(self) -> Error {
        let (s, offset, simple) = match self.0.as_bytes() {
            [b'{', s @ .., b'}'] => (s, 1, false),
            [b'u', b'r', b'n', b':', b'u', b'u', b'i', b'd', b':', s @ ..] => {
                (s, "urn:uuid:".len(), false)
            }
            s => (s, 0, true),
        };

        let mut hyphen_count = 0;
        let mut group_bounds = [0; 4];

        // SAFETY: the byte array came from a valid utf8 string,
        // and is aligned along char boundries.
        let string = unsafe { std::str::from_utf8_unchecked(s) };

        for (index, character) in string.char_indices() {
            let byte = character as u8;
            if character as u32 - byte as u32 > 0 {
                // Multibyte char
                return Error(ErrorKind::Char {
                    character,
                    index: index + offset + 1,
                });
            } else if byte == b'-' {
                // While we search, also count group breaks
                if hyphen_count < 4 {
                    group_bounds[hyphen_count] = index;
                }
                hyphen_count += 1;
            } else if !matches!(byte, b'0'..=b'9' | b'a'..=b'f' | b'A'..=b'F') {
                // Non-hex char
                return Error(ErrorKind::Char {
                    character: byte as char,
                    index: index + offset + 1,
                });
            }
        }

        if hyphen_count == 0 && simple {
            // This means that we tried and failed to parse a simple uuid.
            // Since we verified that all the characters are valid, this means
            // that it MUST have an invalid length.
            Error(ErrorKind::SimpleLength { len: s.len() })
        } else if hyphen_count != 4 {
            // We tried to parse a hyphenated variant, but there weren't
            // 5 groups (4 hyphen splits).
            Error(ErrorKind::GroupCount {
                count: hyphen_count + 1,
            })
        } else {
            // There are 5 groups, one of them has an incorrect length
            const BLOCK_STARTS: [usize; 5] = [0, 9, 14, 19, 24];
            for i in 0..4 {
                if group_bounds[i] != BLOCK_STARTS[i + 1] - 1 {
                    return Error(ErrorKind::GroupLength {
                        group: i,
                        len: group_bounds[i] - BLOCK_STARTS[i],
                        index: offset + BLOCK_STARTS[i] + 1,
                    });
                }
            }

            // The last group must be too long
            Error(ErrorKind::GroupLength {
                group: 4,
                len: s.len() - BLOCK_STARTS[4],
                index: offset + BLOCK_STARTS[4] + 1,
            })
        }
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            ErrorKind::Char {
                character, index, ..
            } => {
                write!(f, "invalid character: expected an optional prefix of `urn:uuid:` followed by [0-9a-zA-Z], found `{}` at {}", character, index)
            }
            ErrorKind::SimpleLength { len } => {
                write!(
                    f,
                    "invalid length: expected length 32 for simple format, found {}",
                    len
                )
            }
            ErrorKind::GroupCount { count } => {
                write!(f, "invalid group count: expected 5, found {}", count)
            }
            ErrorKind::GroupLength { group, len, .. } => {
                let expected = [8, 4, 4, 4, 12][group];
                write!(
                    f,
                    "invalid group length in group {}: expected {}, found {}",
                    group, expected, len
                )
            }
        }
    }
}
<|endoftext|>