<commit_before>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Generic values — A polymorphic type that can hold values of any other type

use std::mem;
use libc::c_char;
use gobject_ffi;
use super::{to_bool, to_gboolean};
use types::Type;
use translate::*;

pub trait ValuePublic {
    fn get(gvalue: &Value) -> Self;
    fn set(&self, gvalue: &mut Value);
}

/// Possible improvement : store a function pointer inside the struct and make the struct
/// templated
pub struct Value {
    inner: gobject_ffi::GValue,
}

impl Value {
    pub fn new() -> Value {
        unsafe { Value { inner: mem::zeroed() } }
    }

    /// Initializes value with the default value of type .
    pub fn init(&mut self, _type: Type) {
        unsafe { gobject_ffi::g_value_init(&mut self.inner, _type.to_glib()); }
    }

    /// Clears the current value in value and resets it to the default value (as if the
    /// value had just been initialized).
    pub fn reset(&mut self) {
        unsafe { gobject_ffi::g_value_reset(&mut self.inner); }
    }

    /// Clears the current value in value and "unsets" the type, this releases all resources
    /// associated with this GValue. An unset value is the same as an uninitialized (zero-filled)
    /// GValue structure.
    pub fn unset(&mut self) {
        unsafe { gobject_ffi::g_value_unset(&mut self.inner) }
    }

    /// Return a newly allocated string, which describes the contents of a GValue. The main
    /// purpose of this function is to describe GValue contents for debugging output, the way
    /// in which the contents are described may change between different GLib versions.
    pub fn strdup_value_contents(&mut self) -> Option<String> {
        unsafe {
            from_glib_full(gobject_ffi::g_strdup_value_contents(&mut self.inner) as *const c_char)
        }
    }

    /// Set the contents of a G_TYPE_BOOLEAN GValue to v_boolean.
    fn set_boolean(&mut self, v_boolean: bool) {
        unsafe { gobject_ffi::g_value_set_boolean(&mut self.inner, to_gboolean(v_boolean)) }
    }

    /// Get the contents of a G_TYPE_BOOLEAN GValue.
    fn get_boolean(&self) -> bool {
        unsafe { to_bool(gobject_ffi::g_value_get_boolean(&self.inner)) }
    }

    /// Set the contents of a G_TYPE_CHAR GValue to v_char .
    fn set_schar(&mut self, v_char: i8) {
        unsafe { gobject_ffi::g_value_set_schar(&mut self.inner, v_char) }
    }

    /// Get the contents of a G_TYPE_CHAR GValue.
    fn get_schar(&self) -> i8 {
        unsafe { gobject_ffi::g_value_get_schar(&self.inner) }
    }

    /// Set the contents of a G_TYPE_UCHAR GValue to v_uchar .
    fn set_uchar(&mut self, v_uchar: u8) {
        unsafe { gobject_ffi::g_value_set_uchar(&mut self.inner, v_uchar) }
    }

    /// Get the contents of a G_TYPE_UCHAR GValue.
    fn get_uchar(&self) -> u8 {
        unsafe { gobject_ffi::g_value_get_uchar(&self.inner) }
    }

    /// Set the contents of a G_TYPE_INT GValue to v_int.
    fn set_int(&mut self, v_int: i32) {
        unsafe { gobject_ffi::g_value_set_int(&mut self.inner, v_int) }
    }

    /// Get the contents of a G_TYPE_INT GValue.
    fn get_int(&self) -> i32 {
        unsafe { gobject_ffi::g_value_get_int(&self.inner) }
    }

    /// Set the contents of a G_TYPE_UINT GValue to v_uint .
    fn set_uint(&mut self, v_uint: u32) {
        unsafe { gobject_ffi::g_value_set_uint(&mut self.inner, v_uint) }
    }

    /// Get the contents of a G_TYPE_UINT GValue.
    fn get_uint(&self) -> u32 {
        unsafe { gobject_ffi::g_value_get_uint(&self.inner) }
    }

    /// Set the contents of a G_TYPE_LONG GValue to v_long .
    pub fn set_long(&mut self, v_long: i64) {
        unsafe { gobject_ffi::g_value_set_long(&mut self.inner, v_long as ::libc::c_long) }
    }

    /// Get the contents of a G_TYPE_LONG GValue.
    pub fn get_long(&self) -> i64 {
        unsafe { gobject_ffi::g_value_get_long(&self.inner) as i64 }
    }

    /// Set the contents of a G_TYPE_ULONG GValue to v_ulong .
    pub fn set_ulong(&mut self, v_ulong: u64) {
        unsafe { gobject_ffi::g_value_set_ulong(&mut self.inner, v_ulong as ::libc::c_ulong) }
    }

    /// Get the contents of a G_TYPE_ULONG GValue.
    pub fn get_ulong(&self) -> u64 {
        unsafe { gobject_ffi::g_value_get_ulong(&self.inner) as u64 }
    }

    /// Set the contents of a G_TYPE_INT64 GValue to v_int64 .
    fn set_int64(&mut self, v_int64: i64) {
        unsafe { gobject_ffi::g_value_set_int64(&mut self.inner, v_int64) }
    }

    /// Get the contents of a G_TYPE_INT64 GValue.
    fn get_int64(&self) -> i64 {
        unsafe { gobject_ffi::g_value_get_int64(&self.inner) }
    }

    /// Set the contents of a G_TYPE_UINT64 GValue to v_uint64 .
    fn set_uint64(&mut self, v_uint64: u64) {
        unsafe { gobject_ffi::g_value_set_uint64(&mut self.inner, v_uint64) }
    }

    /// Get the contents of a G_TYPE_UINT64 GValue.
    fn get_uint64(&self) -> u64 {
        unsafe { gobject_ffi::g_value_get_uint64(&self.inner) }
    }

    /// Set the contents of a G_TYPE_FLOAT GValue to v_float .
    fn set_float(&mut self, v_float: f32) {
        unsafe { gobject_ffi::g_value_set_float(&mut self.inner, v_float) }
    }

    /// Get the contents of a G_TYPE_FLOAT GValue.
    fn get_float(&self) -> f32 {
        unsafe { gobject_ffi::g_value_get_float(&self.inner) }
    }

    /// Set the contents of a G_TYPE_DOUBLE GValue to v_double .
    fn set_double(&mut self, v_double: f64) {
        unsafe { gobject_ffi::g_value_set_double(&mut self.inner, v_double) }
    }

    /// Get the contents of a G_TYPE_DOUBLE GValue.
    fn get_double(&self) -> f64 {
        unsafe { gobject_ffi::g_value_get_double(&self.inner) }
    }

    /// Set the contents of a G_TYPE_STRING GValue to v_string .
    fn set_string(&mut self, v_string: &str) {
        unsafe {
            gobject_ffi::g_value_set_string(&mut self.inner, v_string.to_glib_none().0);
        }
    }

    /// Get the contents of a G_TYPE_STRING GValue.
    pub fn get_string(&self) -> Option<String> {
        unsafe {
            from_glib_none(gobject_ffi::g_value_get_string(&self.inner))
        }
    }

    /// Set the contents of a G_TYPE_BOXED derived GValue to v_boxed .
    pub fn set_boxed<T>(&mut self, v_box: &T) {
        unsafe { gobject_ffi::g_value_set_boxed(&mut self.inner, ::std::mem::transmute(v_box)) }
    }

    /*pub fn take_boxed<T>(&self, v_box: &T) {
        unsafe { gobject_ffi::g_value_take_boxed(&mut self.inner, ::std::mem::transmute(v_box)) }
    }*/

    /// Get the contents of a G_TYPE_BOXED derived GValue.
    pub fn get_boxed<'r, T>(&'r self) -> &'r T {
        unsafe { ::std::mem::transmute(gobject_ffi::g_value_get_boxed(&self.inner)) }
    }

    /*pub fn dup_boxed<'r, T>(&'r self) -> &'r T {
        unsafe { ::std::mem::transmute(gobject_ffi::g_value_dup_boxed(&mut self.inner)) }
    }*/

    /// Set the contents of a pointer GValue to v_pointer .
    pub fn set_pointer<T>(&mut self, v_pointer: &T) {
        unsafe { gobject_ffi::g_value_set_pointer(&mut self.inner, ::std::mem::transmute(v_pointer)) }
    }

    /// Get the contents of a pointer GValue.
    pub fn get_pointer<'r, T>(&'r self) -> &'r T {
        unsafe { ::std::mem::transmute(gobject_ffi::g_value_get_pointer(&self.inner)) }
    }

    /// Set the contents of a G_TYPE_OBJECT derived GValue to v_object .
    ///
    /// g_value_set_object() increases the reference count of v_object (the GValue holds a reference
    /// to v_object ). If you do not wish to increase the reference count of the object (i.e. you
    /// wish to pass your current reference to the GValue because you no longer need it), use
    /// g_value_take_object() instead.
    ///
    /// It is important that your GValue holds a reference to v_object (either its own, or one it
    /// has taken) to ensure that the object won't be destroyed while the GValue still exists).
    pub fn set_object<T>(&mut self, v_object: &T) {
        unsafe { gobject_ffi::g_value_set_object(&mut self.inner, ::std::mem::transmute(v_object)) }
    }

    /// Get the contents of a G_TYPE_OBJECT derived GValue.
    pub fn get_object<'r, T>(&'r self) -> &'r T {
        unsafe { ::std::mem::transmute(gobject_ffi::g_value_get_object(&self.inner)) }
    }

    /// Set the contents of a G_TYPE_GTYPE GValue to v_gtype .
    // FIXME shouldn't be like that
    fn set_gtype(&mut self, v_gtype: Type) {
        unsafe { gobject_ffi::g_value_set_gtype(&mut self.inner, v_gtype.to_glib()) }
    }

    /// Get the contents of a G_TYPE_GTYPE GValue.
    // FIXME shouldn't be like that
    fn get_gtype(&self) -> Type {
        unsafe { from_glib(gobject_ffi::g_value_get_gtype(&self.inner)) }
    }

    pub fn set<T: ValuePublic>(&mut self, val: &T) {
        val.set(self);
    }

    pub fn get<T: ValuePublic>(&self) -> T {
        ValuePublic::get(self)
    }

    /// Returns whether a GValue of type src_type can be copied into a GValue of type dest_type .
    pub fn compatible(src_type: Type, dest_type: Type) -> bool {
        unsafe { to_bool(gobject_ffi::g_value_type_compatible(src_type.to_glib(), dest_type.to_glib())) }
    }

    /// Check whether g_value_transform() is able to transform values of type src_type into
    /// values of type dest_type . Note that for the types to be transformable, they must be
    /// compatible and a transform function must be registered.
    pub fn transformable(src_type: Type, dest_type: Type) -> bool {
        unsafe { to_bool(gobject_ffi::g_value_type_transformable(src_type.to_glib(), dest_type.to_glib())) }
    }

    pub fn as_ptr(&self) -> *const gobject_ffi::GValue {
        &self.inner
    }

    pub fn as_mut_ptr(&mut self) -> *mut gobject_ffi::GValue {
        &mut self.inner
    }
}

impl Drop for Value {
    fn drop(&mut self) {
        self.unset();
    }
}

impl ValuePublic for i32 {
    fn get(gvalue: &Value) -> i32 {
        gvalue.get_int()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_int(*self)
    }
}

impl ValuePublic for u32 {
    fn get(gvalue: &Value) -> u32 {
        gvalue.get_uint()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_uint(*self)
    }
}

impl ValuePublic for i64 {
    fn get(gvalue: &Value) -> i64 {
        gvalue.get_int64()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_int64(*self)
    }
}

impl ValuePublic for u64 {
    fn get(gvalue: &Value) -> u64 {
        gvalue.get_uint64()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_uint64(*self)
    }
}

impl ValuePublic for bool {
    fn get(gvalue: &Value) -> bool {
        gvalue.get_boolean()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_boolean(*self)
    }
}

impl ValuePublic for i8 {
    fn get(gvalue: &Value) -> i8 {
        gvalue.get_schar()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_schar(*self)
    }
}

impl ValuePublic for u8 {
    fn get(gvalue: &Value) -> u8 {
        gvalue.get_uchar()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_uchar(*self)
    }
}

impl ValuePublic for f32 {
    fn get(gvalue: &Value) -> f32 {
        gvalue.get_float()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_float(*self)
    }
}

impl ValuePublic for f64 {
    fn get(gvalue: &Value) -> f64 {
        gvalue.get_double()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_double(*self)
    }
}

impl ValuePublic for Type {
    fn get(gvalue: &Value) -> Type {
        gvalue.get_gtype()
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_gtype(*self)
    }
}

impl ValuePublic for String {
    fn get(gvalue: &Value) -> String {
        match gvalue.get_string() {
            Some(s) => s,
            None => String::new()
        }
    }

    fn set(&self, gvalue: &mut Value) {
        gvalue.set_string(self.as_ref())
    }
}
<commit_msg>Mark Value bindings as unsafe<commit_after>// Copyright 2013-2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Generic values — A polymorphic type that can hold values of any other type

use std::mem;
use libc::c_char;
use gobject_ffi;
use super::{to_bool, to_gboolean};
use types::Type;
use translate::*;

pub trait ValuePublic {
    unsafe fn get(gvalue: &Value) -> Self;
    unsafe fn set(&self, gvalue: &mut Value);
}

/// Possible improvement : store a function pointer inside the struct and make the struct
/// templated
pub struct Value {
    inner: gobject_ffi::GValue,
}

impl Value {
    pub unsafe fn new() -> Value {
        Value { inner: mem::zeroed() }
    }

    /// Initializes value with the default value of type .
    pub fn init(&mut self, _type: Type) {
        unsafe { gobject_ffi::g_value_init(&mut self.inner, _type.to_glib()); }
    }

    /// Clears the current value in value and resets it to the default value (as if the
    /// value had just been initialized).
    pub fn reset(&mut self) {
        unsafe { gobject_ffi::g_value_reset(&mut self.inner); }
    }

    /// Clears the current value in value and "unsets" the type, this releases all resources
    /// associated with this GValue. An unset value is the same as an uninitialized (zero-filled)
    /// GValue structure.
    pub unsafe fn unset(&mut self) {
        gobject_ffi::g_value_unset(&mut self.inner)
    }

    /// Return a newly allocated string, which describes the contents of a GValue. The main
    /// purpose of this function is to describe GValue contents for debugging output, the way
    /// in which the contents are described may change between different GLib versions.
    pub fn strdup_value_contents(&mut self) -> Option<String> {
        unsafe {
            from_glib_full(gobject_ffi::g_strdup_value_contents(&mut self.inner) as *const c_char)
        }
    }

    /// Set the contents of a G_TYPE_BOOLEAN GValue to v_boolean.
    pub unsafe fn set_boolean(&mut self, v_boolean: bool) {
        gobject_ffi::g_value_set_boolean(&mut self.inner, to_gboolean(v_boolean))
    }

    /// Get the contents of a G_TYPE_BOOLEAN GValue.
    pub unsafe fn get_boolean(&self) -> bool {
        to_bool(gobject_ffi::g_value_get_boolean(&self.inner))
    }

    /// Set the contents of a G_TYPE_CHAR GValue to v_char .
    pub unsafe fn set_schar(&mut self, v_char: i8) {
        gobject_ffi::g_value_set_schar(&mut self.inner, v_char)
    }

    /// Get the contents of a G_TYPE_CHAR GValue.
    pub unsafe fn get_schar(&self) -> i8 {
        gobject_ffi::g_value_get_schar(&self.inner)
    }

    /// Set the contents of a G_TYPE_UCHAR GValue to v_uchar .
    pub unsafe fn set_uchar(&mut self, v_uchar: u8) {
        gobject_ffi::g_value_set_uchar(&mut self.inner, v_uchar)
    }

    /// Get the contents of a G_TYPE_UCHAR GValue.
    pub unsafe fn get_uchar(&self) -> u8 {
        gobject_ffi::g_value_get_uchar(&self.inner)
    }

    /// Set the contents of a G_TYPE_INT GValue to v_int.
    pub unsafe fn set_int(&mut self, v_int: i32) {
        gobject_ffi::g_value_set_int(&mut self.inner, v_int)
    }

    /// Get the contents of a G_TYPE_INT GValue.
    pub unsafe fn get_int(&self) -> i32 {
        gobject_ffi::g_value_get_int(&self.inner)
    }

    /// Set the contents of a G_TYPE_UINT GValue to v_uint .
    pub unsafe fn set_uint(&mut self, v_uint: u32) {
        gobject_ffi::g_value_set_uint(&mut self.inner, v_uint)
    }

    /// Get the contents of a G_TYPE_UINT GValue.
    pub unsafe fn get_uint(&self) -> u32 {
        gobject_ffi::g_value_get_uint(&self.inner)
    }

    /// Set the contents of a G_TYPE_LONG GValue to v_long .
    pub unsafe fn set_long(&mut self, v_long: i64) {
        gobject_ffi::g_value_set_long(&mut self.inner, v_long as ::libc::c_long)
    }

    /// Get the contents of a G_TYPE_LONG GValue.
    pub unsafe fn get_long(&self) -> i64 {
        gobject_ffi::g_value_get_long(&self.inner) as i64
    }

    /// Set the contents of a G_TYPE_ULONG GValue to v_ulong .
    pub unsafe fn set_ulong(&mut self, v_ulong: u64) {
        gobject_ffi::g_value_set_ulong(&mut self.inner, v_ulong as ::libc::c_ulong)
    }

    /// Get the contents of a G_TYPE_ULONG GValue.
    pub unsafe fn get_ulong(&self) -> u64 {
        gobject_ffi::g_value_get_ulong(&self.inner) as u64
    }

    /// Set the contents of a G_TYPE_INT64 GValue to v_int64 .
    pub unsafe fn set_int64(&mut self, v_int64: i64) {
        gobject_ffi::g_value_set_int64(&mut self.inner, v_int64)
    }

    /// Get the contents of a G_TYPE_INT64 GValue.
    pub unsafe fn get_int64(&self) -> i64 {
        gobject_ffi::g_value_get_int64(&self.inner)
    }

    /// Set the contents of a G_TYPE_UINT64 GValue to v_uint64 .
    pub unsafe fn set_uint64(&mut self, v_uint64: u64) {
        gobject_ffi::g_value_set_uint64(&mut self.inner, v_uint64)
    }

    /// Get the contents of a G_TYPE_UINT64 GValue.
    pub unsafe fn get_uint64(&self) -> u64 {
        gobject_ffi::g_value_get_uint64(&self.inner)
    }

    /// Set the contents of a G_TYPE_FLOAT GValue to v_float .
    pub unsafe fn set_float(&mut self, v_float: f32) {
        gobject_ffi::g_value_set_float(&mut self.inner, v_float)
    }

    /// Get the contents of a G_TYPE_FLOAT GValue.
    pub unsafe fn get_float(&self) -> f32 {
        gobject_ffi::g_value_get_float(&self.inner)
    }

    /// Set the contents of a G_TYPE_DOUBLE GValue to v_double .
    pub unsafe fn set_double(&mut self, v_double: f64) {
        gobject_ffi::g_value_set_double(&mut self.inner, v_double)
    }

    /// Get the contents of a G_TYPE_DOUBLE GValue.
    pub unsafe fn get_double(&self) -> f64 {
        gobject_ffi::g_value_get_double(&self.inner)
    }

    /// Set the contents of a G_TYPE_STRING GValue to v_string .
    pub unsafe fn set_string(&mut self, v_string: &str) {
        gobject_ffi::g_value_set_string(&mut self.inner, v_string.to_glib_none().0);
    }

    /// Get the contents of a G_TYPE_STRING GValue.
    pub unsafe fn get_string(&self) -> Option<String> {
        from_glib_none(gobject_ffi::g_value_get_string(&self.inner))
    }

    /// Set the contents of a G_TYPE_BOXED derived GValue to v_boxed .
    pub unsafe fn set_boxed<T>(&mut self, v_box: &T) {
        gobject_ffi::g_value_set_boxed(&mut self.inner, ::std::mem::transmute(v_box))
    }

    /*pub fn take_boxed<T>(&self, v_box: &T) {
        gobject_ffi::g_value_take_boxed(&mut self.inner, ::std::mem::transmute(v_box))
    }*/

    /// Get the contents of a G_TYPE_BOXED derived GValue.
    pub unsafe fn get_boxed<'r, T>(&'r self) -> &'r T {
        ::std::mem::transmute(gobject_ffi::g_value_get_boxed(&self.inner))
    }

    /*pub unsafe fn dup_boxed<'r, T>(&'r self) -> &'r T {
        ::std::mem::transmute(gobject_ffi::g_value_dup_boxed(&mut self.inner))
    }*/

    /// Set the contents of a pointer GValue to v_pointer .
    pub unsafe fn set_pointer<T>(&mut self, v_pointer: &T) {
        gobject_ffi::g_value_set_pointer(&mut self.inner, ::std::mem::transmute(v_pointer))
    }

    /// Get the contents of a pointer GValue.
    pub unsafe fn get_pointer<'r, T>(&'r self) -> &'r T {
        ::std::mem::transmute(gobject_ffi::g_value_get_pointer(&self.inner))
    }

    /// Set the contents of a G_TYPE_OBJECT derived GValue to v_object .
    ///
    /// g_value_set_object() increases the reference count of v_object (the GValue holds a reference
    /// to v_object ). If you do not wish to increase the reference count of the object (i.e. you
    /// wish to pass your current reference to the GValue because you no longer need it), use
    /// g_value_take_object() instead.
    ///
    /// It is important that your GValue holds a reference to v_object (either its own, or one it
    /// has taken) to ensure that the object won't be destroyed while the GValue still exists).
    pub unsafe fn set_object<T>(&mut self, v_object: &T) {
        gobject_ffi::g_value_set_object(&mut self.inner, ::std::mem::transmute(v_object))
    }

    /// Get the contents of a G_TYPE_OBJECT derived GValue.
    pub unsafe fn get_object<'r, T>(&'r self) -> &'r T {
        ::std::mem::transmute(gobject_ffi::g_value_get_object(&self.inner))
    }

    /// Set the contents of a G_TYPE_GTYPE GValue to v_gtype .
    // FIXME shouldn't be like that
    pub unsafe fn set_gtype(&mut self, v_gtype: Type) {
        gobject_ffi::g_value_set_gtype(&mut self.inner, v_gtype.to_glib())
    }

    /// Get the contents of a G_TYPE_GTYPE GValue.
    // FIXME shouldn't be like that
    pub unsafe fn get_gtype(&self) -> Type {
        from_glib(gobject_ffi::g_value_get_gtype(&self.inner))
    }

    pub unsafe fn set<T: ValuePublic>(&mut self, val: &T) {
        val.set(self);
    }

    pub unsafe fn get<T: ValuePublic>(&self) -> T {
        ValuePublic::get(self)
    }

    /// Returns whether a GValue of type src_type can be copied into a GValue of type dest_type .
    pub fn compatible(src_type: Type, dest_type: Type) -> bool {
        unsafe { to_bool(gobject_ffi::g_value_type_compatible(src_type.to_glib(), dest_type.to_glib())) }
    }

    /// Check whether g_value_transform() is able to transform values of type src_type into
    /// values of type dest_type . Note that for the types to be transformable, they must be
    /// compatible and a transform function must be registered.
    pub fn transformable(src_type: Type, dest_type: Type) -> bool {
        unsafe { to_bool(gobject_ffi::g_value_type_transformable(src_type.to_glib(), dest_type.to_glib())) }
    }

    pub fn as_ptr(&self) -> *const gobject_ffi::GValue {
        &self.inner
    }

    pub fn as_mut_ptr(&mut self) -> *mut gobject_ffi::GValue {
        &mut self.inner
    }
}

impl Drop for Value {
    fn drop(&mut self) {
        unsafe { self.unset(); }
    }
}

impl ValuePublic for i32 {
    unsafe fn get(gvalue: &Value) -> i32 {
        gvalue.get_int()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_int(*self)
    }
}

impl ValuePublic for u32 {
    unsafe fn get(gvalue: &Value) -> u32 {
        gvalue.get_uint()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_uint(*self)
    }
}

impl ValuePublic for i64 {
    unsafe fn get(gvalue: &Value) -> i64 {
        gvalue.get_int64()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_int64(*self)
    }
}

impl ValuePublic for u64 {
    unsafe fn get(gvalue: &Value) -> u64 {
        gvalue.get_uint64()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_uint64(*self)
    }
}

impl ValuePublic for bool {
    unsafe fn get(gvalue: &Value) -> bool {
        gvalue.get_boolean()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_boolean(*self)
    }
}

impl ValuePublic for i8 {
    unsafe fn get(gvalue: &Value) -> i8 {
        gvalue.get_schar()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_schar(*self)
    }
}

impl ValuePublic for u8 {
    unsafe fn get(gvalue: &Value) -> u8 {
        gvalue.get_uchar()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_uchar(*self)
    }
}

impl ValuePublic for f32 {
    unsafe fn get(gvalue: &Value) -> f32 {
        gvalue.get_float()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_float(*self)
    }
}

impl ValuePublic for f64 {
    unsafe fn get(gvalue: &Value) -> f64 {
        gvalue.get_double()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_double(*self)
    }
}

impl ValuePublic for Type {
    unsafe fn get(gvalue: &Value) -> Type {
        gvalue.get_gtype()
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_gtype(*self)
    }
}

impl ValuePublic for String {
    unsafe fn get(gvalue: &Value) -> String {
        match gvalue.get_string() {
            Some(s) => s,
            None => String::new()
        }
    }

    unsafe fn set(&self, gvalue: &mut Value) {
        gvalue.set_string(self.as_ref())
    }
}
<|endoftext|>


<commit_before>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::new(), neighbours: HashMap::new(), }
    }

    pub fn seed(mut self) -> World {
        let cur_gen_cap = self.generation.capacity();
        let max_gen_cap = (self.width * self.height) as usize;
        if cur_gen_cap < max_gen_cap {
            self.generation.reserve(max_gen_cap - cur_gen_cap);
        }
        (0..self.width).cartesian_product(0..self.height)
                       .filter(|_| random())
                       .fold(&mut self.generation, |acc, point| {
                            acc.insert(point);
                            acc
                       });
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        let mut next_generation = HashSet::with_capacity(self.generation.len() * 2);
        self.neighbours.iter()
            .filter(|&(n, c)| self.decide_fate(n, *c))
            .map(|(n, _)| *n)
            .fold(&mut next_generation, |acc, point| {
                acc.insert(point);
                acc
            });
        self.generation = next_generation;
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        write!(f, "{}", buf)
    }
}
<commit_msg>Remove unnecessary formatting<commit_after>use itertools::Itertools;
use std::collections::{HashMap, HashSet};
use std::fmt;
use rand::random;

type Point = (isize, isize);

#[derive(Debug, Clone)]
pub struct World {
    width: isize,
    height: isize,
    generation: HashSet<Point>,
    neighbours: HashMap<Point, usize>,
    age: usize,
}

impl World {
    pub fn new(width: isize, height: isize)  -> World {
        World { width: width, height: height, age: 0,
                generation: HashSet::new(), neighbours: HashMap::new(), }
    }

    pub fn seed(mut self) -> World {
        let cur_gen_cap = self.generation.capacity();
        let max_gen_cap = (self.width * self.height) as usize;
        if cur_gen_cap < max_gen_cap {
            self.generation.reserve(max_gen_cap - cur_gen_cap);
        }
        (0..self.width).cartesian_product(0..self.height)
                       .filter(|_| random())
                       .fold(&mut self.generation, |acc, point| {
                            acc.insert(point);
                            acc
                       });
        self.calculate_neighbours();
        self
    }

    pub fn evolve(&mut self) -> &World {
        let mut next_generation = HashSet::with_capacity(self.generation.len() * 2);
        self.neighbours.iter()
            .filter(|&(n, c)| self.decide_fate(n, *c))
            .map(|(n, _)| *n)
            .fold(&mut next_generation, |acc, point| {
                acc.insert(point);
                acc
            });
        self.generation = next_generation;
        self.calculate_neighbours();
        self.age += 1;
        self
    }

    fn calculate_neighbours(&mut self) {
        self.neighbours.clear();
        for &(x, y) in self.generation.iter() {
            (-1..2)
            .cartesian_product(-1..2)
            .filter(|&(dx, dy)| dx != 0 || dy != 0)
            .map(|(dx, dy)| (dx + x, dy + y))
            .fold(&mut self.neighbours, |acc, point| {
                *acc.entry(point).or_insert(0) += 1;
                acc
            });
        };
    }

    fn decide_fate(&self, p: &Point, c: usize) -> bool {
        if self.generation.contains(p) {
            c == 3 || c == 2
        } else {
            c == 3
        }
    }
}

impl fmt::Display for World {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut buf = String::with_capacity(((self.width + 2) * (self.height + 2) + 50) as usize);
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '┌' } else if x == self.width + 1 { '┐' } else { '─' });
        }
        buf.push('\n');
        for y in 0..self.height {
            buf.push('│');
            for x in 0..self.width {
                buf.push(if self.generation.contains(&(x, y)) { '*' } else { ' ' });
            }
            buf.push('|');
            if y == 0 {
                buf.push_str(&format!(" cells: {}", self.generation.len()));
            }
            if y == 1 {
                buf.push_str(&format!(" age: {}", self.age));
            }
            buf.push('\n');
        }
        for x in 0..self.width + 2 {
            buf.push(if x == 0 { '└' } else if x == self.width + 1 { '┘' } else { '─' });
        }
        f.write_str(&buf)
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;
extern crate fern;
extern crate failure;
extern crate clap;
extern crate libloading;
extern crate x11;

use clap::{Arg, App, ArgMatches};
use clap::AppSettings::*;
use failure::{ResultExt, Error, Fail};
use config::Config;
use workspaces::Workspaces;
use xlib_window_system::XlibWindowSystem;
use xlib_window_system::XlibEvent::{XMapRequest, XConfigurationNotify, XConfigurationRequest,
                                    XDestroy, XUnmapNotify, XPropertyNotify, XEnterNotify,
                                    XFocusIn, XFocusOut, XKeyPress, XButtonPress};

mod config;
mod keycode;
mod commands;
mod xlib_window_system;
mod workspaces;
mod workspace;
mod container;
mod statusbar;
mod stack;
mod layout;
mod utils;

fn process_cli<'a>() -> ArgMatches<'a> {
    App::new("xr3wm")
        .version("0.0.1")
        .author("Cristian Kubis <cristian.kubis@tsunix.de>")
        .about("i3wm inspired tiling window manager")
        .setting(DeriveDisplayOrder)
        .arg(Arg::with_name("verbose")
             .short("v")
             .long("verbose")
             .multiple(true)
             .help("increrases the logging verbosity each use for up to 2 times"))
        .get_matches()
}

// initialization of the logging system
fn init_logger(verbosity: u64, logfile: &str) -> Result<(), Error> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!("[{}] {}", record.level(), message))
        })
        // set the verbosity of the logging
        .level(match verbosity {
            1 => log::LevelFilter::Debug,
            x if x > 1 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Info
        })
        // output everything but errors to stdout
        .chain(
            fern::Dispatch::new()
                .filter(move |metadata| metadata.level() != log::LevelFilter::Error)
                .chain(::std::io::stdout()))
        // output errors to stderr
        .chain(
            fern::Dispatch::new()
                .level(log::LevelFilter::Error)
                .chain(::std::io::stderr()))
        // duplicate all logs in a log file
        .chain(fern::log_file(logfile)
            .context("failed to open log file")?)
        .apply()
        .map_err(|e| e.into())
}

fn run() -> Result<(), Error> {
    let matches = process_cli();

    let verbosity = matches.occurrences_of("verbose");

    // initialize logging system
    if let Err(e) = init_logger(verbosity, concat!(env!("HOME"), "/.xr3wm/xr3wm.log")) {
        eprintln!("[ERROR] failed to initialize logging system: {}", e);
        ::std::process::exit(1);
    }

    info!("loading config");
    let (mut config, ws_cfg_list) = Config::load()
        .map_err(|e| {
            let error = utils::concat_error_chain(&e);
            utils::xmessage(&format!("failed to load config:\n{}", error))
                .map_err(|e| warn!("failed to run xmessage: {}", e))
                .ok();
            e
        })
        .context("failed to load config")?;

    let xws = &XlibWindowSystem::new();
    xws.grab_modifier(config.mod_key);

    let workspaces = Workspaces::new(ws_cfg_list, xws)
        .context("failed to create workspaces")?;

    if let Some(ref mut statusbar) = config.statusbar {
        statusbar.start()
            .context("failed to start statusbar")?;
    }

    info!("entering event loop");
    run_event_loop(config, xws, workspaces)
}

fn run_event_loop(mut config: Config, ws: &XlibWindowSystem, mut workspaces: Workspaces) -> Result<(), Error> {
    loop {
        match ws.get_event() {
            XMapRequest(window) => {
                debug!("XMapRequest: {}", window);
                if !workspaces.contains(window) {
                    let class = ws.get_class_name(window);
                    let mut is_hooked = false;

                    for hook in config.manage_hooks.iter() {
                        if hook.class_name == class {
                            is_hooked = true;
                            hook.cmd.call(ws, &mut workspaces, &config, window);
                        }
                    }

                    if !is_hooked {
                        workspaces.add_window(None, ws, &config, window);
                        workspaces.focus_window(ws, &config, window);
                    }
                }
            }
            XDestroy(window) => {
                debug!("XDestroy: {}", window);

                if workspaces.contains(window) {
                    workspaces.remove_window(ws, &config, window);
                }
            }
            XUnmapNotify(window, send) => {
                debug!("XUnmapNotify: {} {}", window, send);

                if send && workspaces.contains(window) {
                    workspaces.remove_window(ws, &config, window);
                }
            }
            XPropertyNotify(window, atom, _) => {
                if atom == ws.get_atom("WM_HINTS", false) {
                    if let Some(idx) = workspaces.find_window(window) {
                        workspaces.get_mut(idx)
                            .set_urgency(ws.is_urgent(window), ws, &config, window);
                    }
                }
            }
            XConfigurationNotify(_) => {
                workspaces.rescreen(ws, &config);
            }
            XConfigurationRequest(window, changes, mask) => {
                let unmanaged = workspaces.is_unmanaged(window) || !workspaces.contains(window);
                ws.configure_window(window, changes, mask, unmanaged);
            }
            XEnterNotify(window) => {
                trace!("XEnterNotify: {}", window);
                workspaces.focus_window(ws, &config, window);
            }
            XFocusIn(window) => {
                trace!("XFocusIn: {}", window);
                workspaces.focus_window(ws, &config, window);
            }
            XFocusOut(window) => {
                trace!("XFocusOut: {}", window);
                /*if workspaces.current().focused_window() == Some(window) {
                    workspaces.current_mut().unfocus_window(ws, &config);
                }*/
            }
            XButtonPress(window) => {
                workspaces.focus_window(ws, &config, window);
            }
            XKeyPress(_, mods, key) => {
                trace!("XKeyPress: {}, {}", mods, key);
                let mods = mods & !(config.mod_key | 0b10010);

                for (binding, cmd) in config.keybindings.iter() {
                    if binding.mods == mods && binding.key == key {
                        cmd.call(ws, &mut workspaces, &config)
                            .map_err(|e| error!("{}", utils::concat_error_chain(&e)))
                            .ok();
                    }
                }
            }
            _ => {}
        }

        if let Some(ref mut statusbar) = config.statusbar {
            if let Err(e) = statusbar.update(ws, &workspaces) {
                error!("{}", e.context("failed to update statusbar"));
            }
        }
    }

}

fn main() {
    // failure crate boilerplate
    if let Err(e) = run() {
        use std::io::Write;
        let mut stderr = std::io::stderr();
        let got_logger = log_enabled!(log::Level::Error);

        let mut fail: &dyn Fail = e.as_fail();
        if got_logger {
            error!("{}", fail);
        } else {
            writeln!(&mut stderr, "{}", fail).ok();
        }

        while let Some(cause) = fail.cause() {
            if got_logger {
                error!("caused by: {}", cause);
            } else {
                writeln!(&mut stderr, "caused by: {}", cause).ok();
            }

            if let Some(bt) = cause.backtrace() {
                error!("backtrace: {}", bt)
            }
            fail = cause;
        }

        stderr.flush().ok();
        ::std::process::exit(1);
    }
}
<commit_msg>Fix invisible windows on initial WM start<commit_after>#[macro_use]
extern crate log;
extern crate fern;
extern crate failure;
extern crate clap;
extern crate libloading;
extern crate x11;

use clap::{Arg, App, ArgMatches};
use clap::AppSettings::*;
use failure::{ResultExt, Error, Fail};
use config::Config;
use workspaces::Workspaces;
use xlib_window_system::XlibWindowSystem;
use xlib_window_system::XlibEvent::{XMapRequest, XConfigurationNotify, XConfigurationRequest,
                                    XDestroy, XUnmapNotify, XPropertyNotify, XEnterNotify,
                                    XFocusIn, XFocusOut, XKeyPress, XButtonPress};

mod config;
mod keycode;
mod commands;
mod xlib_window_system;
mod workspaces;
mod workspace;
mod container;
mod statusbar;
mod stack;
mod layout;
mod utils;

fn process_cli<'a>() -> ArgMatches<'a> {
    App::new("xr3wm")
        .version("0.0.1")
        .author("Cristian Kubis <cristian.kubis@tsunix.de>")
        .about("i3wm inspired tiling window manager")
        .setting(DeriveDisplayOrder)
        .arg(Arg::with_name("verbose")
             .short("v")
             .long("verbose")
             .multiple(true)
             .help("increrases the logging verbosity each use for up to 2 times"))
        .get_matches()
}

// initialization of the logging system
fn init_logger(verbosity: u64, logfile: &str) -> Result<(), Error> {
    fern::Dispatch::new()
        .format(|out, message, record| {
            out.finish(format_args!("[{}] {}", record.level(), message))
        })
        // set the verbosity of the logging
        .level(match verbosity {
            1 => log::LevelFilter::Debug,
            x if x > 1 => log::LevelFilter::Trace,
            _ => log::LevelFilter::Info
        })
        // output everything but errors to stdout
        .chain(
            fern::Dispatch::new()
                .filter(move |metadata| metadata.level() != log::LevelFilter::Error)
                .chain(::std::io::stdout()))
        // output errors to stderr
        .chain(
            fern::Dispatch::new()
                .level(log::LevelFilter::Error)
                .chain(::std::io::stderr()))
        // duplicate all logs in a log file
        .chain(fern::log_file(logfile)
            .context("failed to open log file")?)
        .apply()
        .map_err(|e| e.into())
}

fn run() -> Result<(), Error> {
    let matches = process_cli();

    let verbosity = matches.occurrences_of("verbose");

    // initialize logging system
    if let Err(e) = init_logger(verbosity, concat!(env!("HOME"), "/.xr3wm/xr3wm.log")) {
        eprintln!("[ERROR] failed to initialize logging system: {}", e);
        ::std::process::exit(1);
    }

    info!("loading config");
    let (mut config, ws_cfg_list) = Config::load()
        .map_err(|e| {
            let error = utils::concat_error_chain(&e);
            utils::xmessage(&format!("failed to load config:\n{}", error))
                .map_err(|e| warn!("failed to run xmessage: {}", e))
                .ok();
            e
        })
        .context("failed to load config")?;

    let xws = &XlibWindowSystem::new();
    xws.grab_modifier(config.mod_key);

    let mut workspaces = Workspaces::new(ws_cfg_list, xws)
        .context("failed to create workspaces")?;

    workspaces.current_mut().show(xws, &config);

    if let Some(ref mut statusbar) = config.statusbar {
        statusbar.start()
            .context("failed to start statusbar")?;
    }

    info!("entering event loop");
    run_event_loop(config, xws, workspaces)
}

fn run_event_loop(mut config: Config, ws: &XlibWindowSystem, mut workspaces: Workspaces) -> Result<(), Error> {
    loop {
        match ws.get_event() {
            XMapRequest(window) => {
                debug!("XMapRequest: {}", window);
                if !workspaces.contains(window) {
                    let class = ws.get_class_name(window);
                    let mut is_hooked = false;

                    for hook in config.manage_hooks.iter() {
                        if hook.class_name == class {
                            is_hooked = true;
                            hook.cmd.call(ws, &mut workspaces, &config, window);
                        }
                    }

                    if !is_hooked {
                        workspaces.add_window(None, ws, &config, window);
                        workspaces.focus_window(ws, &config, window);
                    }
                }
            }
            XDestroy(window) => {
                debug!("XDestroy: {}", window);

                if workspaces.contains(window) {
                    workspaces.remove_window(ws, &config, window);
                }
            }
            XUnmapNotify(window, send) => {
                debug!("XUnmapNotify: {} {}", window, send);

                if send && workspaces.contains(window) {
                    workspaces.remove_window(ws, &config, window);
                }
            }
            XPropertyNotify(window, atom, _) => {
                if atom == ws.get_atom("WM_HINTS", false) {
                    if let Some(idx) = workspaces.find_window(window) {
                        workspaces.get_mut(idx)
                            .set_urgency(ws.is_urgent(window), ws, &config, window);
                    }
                }
            }
            XConfigurationNotify(_) => {
                workspaces.rescreen(ws, &config);
            }
            XConfigurationRequest(window, changes, mask) => {
                let unmanaged = workspaces.is_unmanaged(window) || !workspaces.contains(window);
                ws.configure_window(window, changes, mask, unmanaged);
            }
            XEnterNotify(window) => {
                trace!("XEnterNotify: {}", window);
                workspaces.focus_window(ws, &config, window);
            }
            XFocusIn(window) => {
                trace!("XFocusIn: {}", window);
                workspaces.focus_window(ws, &config, window);
            }
            XFocusOut(window) => {
                trace!("XFocusOut: {}", window);
                /*if workspaces.current().focused_window() == Some(window) {
                    workspaces.current_mut().unfocus_window(ws, &config);
                }*/
            }
            XButtonPress(window) => {
                workspaces.focus_window(ws, &config, window);
            }
            XKeyPress(_, mods, key) => {
                trace!("XKeyPress: {}, {}", mods, key);
                let mods = mods & !(config.mod_key | 0b10010);

                for (binding, cmd) in config.keybindings.iter() {
                    if binding.mods == mods && binding.key == key {
                        cmd.call(ws, &mut workspaces, &config)
                            .map_err(|e| error!("{}", utils::concat_error_chain(&e)))
                            .ok();
                    }
                }
            }
            _ => {}
        }

        if let Some(ref mut statusbar) = config.statusbar {
            if let Err(e) = statusbar.update(ws, &workspaces) {
                error!("{}", e.context("failed to update statusbar"));
            }
        }
    }

}

fn main() {
    // failure crate boilerplate
    if let Err(e) = run() {
        use std::io::Write;
        let mut stderr = std::io::stderr();
        let got_logger = log_enabled!(log::Level::Error);

        let mut fail: &dyn Fail = e.as_fail();
        if got_logger {
            error!("{}", fail);
        } else {
            writeln!(&mut stderr, "{}", fail).ok();
        }

        while let Some(cause) = fail.cause() {
            if got_logger {
                error!("caused by: {}", cause);
            } else {
                writeln!(&mut stderr, "caused by: {}", cause).ok();
            }

            if let Some(bt) = cause.backtrace() {
                error!("backtrace: {}", bt)
            }
            fail = cause;
        }

        stderr.flush().ok();
        ::std::process::exit(1);
    }
}
<|endoftext|>


<commit_before>use eyre::{bail, Result};
use graph_triples::{direction, relations, Direction, Pairs, Relation, Resource, Triple};
use path_slash::PathExt;
use petgraph::{
    graph::NodeIndex,
    stable_graph::StableGraph,
    visit::{EdgeRef, IntoEdgeReferences, IntoNodeReferences},
};
use schemars::{
    gen::SchemaGenerator,
    schema::{Schema, SchemaObject},
    schema_for, JsonSchema,
};
use serde::{ser::SerializeMap, Serialize};
use serde_json::json;
use serde_with::skip_serializing_none;
use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};
use strum::Display;
use utils::some_string;

/// A dependency graph for a project or document
#[derive(Debug, Default, Clone)]
pub struct Graph {
    /// The path of the project or document that this graph is for
    ///
    /// Primarily used to make file paths relative in visualizations and
    /// if ever persisting the graph.
    path: PathBuf,

    /// The graph itself
    ///
    /// Use a `petgraph::StableGraph` so that nodes can be added and removed
    /// without changing node indices.
    graph: StableGraph<Resource, Relation>,

    /// Indices of the nodes in the tree
    ///
    /// This is necessary to keep track of which resources
    /// are already in the graph and re-use their index if they are.
    indices: HashMap<Resource, NodeIndex>,
}

impl Serialize for Graph {
    /// Custom serialization to strip prefix from paths, add stable node indices,
    /// and exclude properties that are included by default by `petgraph` (e.g `node_holes`).
    ///
    /// Our general approach is to keep paths absolute whilst in memory and only convert to
    /// relative when necessary (e.g. visualizations). See also `Graph::to_dot`.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let nodes: Vec<serde_json::Value> = self
            .graph
            .node_references()
            .map(|(index, resource)| {
                let mut obj = serde_json::to_value(resource).expect("To be able to serialize");
                let obj = obj.as_object_mut().expect("To be an object");

                // Strip prefix from paths
                if let Some(path) = match resource {
                    Resource::Symbol(symbol) => Some(symbol.path.clone()),
                    Resource::Node(node) => Some(node.path.clone()),
                    Resource::File(file) => Some(file.path.clone()),
                    _ => None,
                } {
                    let path = path
                        .strip_prefix(&self.path)
                        .unwrap_or(&path)
                        .to_slash_lossy();
                    obj.insert("path".to_string(), json!(path));
                }

                obj.insert("index".to_string(), json!(index));
                json!(obj)
            })
            .collect();

        let edges: Vec<serde_json::Value> = self
            .graph
            .edge_references()
            .map(|edge| -> serde_json::Value {
                json!({
                    "from": edge.source(),
                    "to": edge.target(),
                    "relation": edge.weight()
                })
            })
            .collect();

        let mut map = serializer.serialize_map(Some(2))?;
        map.serialize_entry("nodes", &nodes)?;
        map.serialize_entry("edges", &edges)?;
        map.end()
    }
}

/// The available graph serialization formats
pub const FORMATS: [&str; 3] = ["dot", "json", "yaml"];

impl Graph {
    /// Create a new, empty graph
    pub fn new<P: AsRef<Path>>(path: P) -> Graph {
        Graph {
            path: PathBuf::from(path.as_ref()),
            indices: HashMap::new(),
            graph: StableGraph::new(),
        }
    }

    /// Create a graph from set of dependency relations
    pub fn from_relations<P: AsRef<Path>>(path: P, relations: &[(Resource, Pairs)]) -> Graph {
        let mut graph = Graph::new(path);
        for (subject, pairs) in relations {
            for (relation, object) in pairs {
                graph.add_triple((subject.clone(), relation.clone(), object.clone()));
            }
        }
        graph
    }

    /// Add a resource to the graph
    pub fn add_resource(&mut self, resource: Resource) {
        if self.indices.get(&resource).is_none() {
            let index = self.graph.add_node(resource.clone());
            self.indices.insert(resource, index);
        }
    }

    /// Add a triple to the graph
    pub fn add_triple(&mut self, (subject, relation, object): Triple) {
        let subject = if let Some(index) = self.indices.get(&subject) {
            *index
        } else {
            let index = self.graph.add_node(subject.clone());
            self.indices.insert(subject, index);
            index
        };

        let object = if let Some(index) = self.indices.get(&object) {
            *index
        } else {
            let index = self.graph.add_node(object.clone());
            self.indices.insert(object, index);
            index
        };

        let (from, to) = match direction(&relation) {
            Direction::From => (object, subject),
            Direction::To => (subject, object),
        };

        self.graph.add_edge(from, to, relation);
    }

    /// Add a set of triples to the graph
    pub fn add_triples(&mut self, triples: Vec<Triple>) {
        triples
            .into_iter()
            .for_each(|triple| self.add_triple(triple))
    }

    /// Convert the graph to some format
    pub fn to_format(&self, format: &str) -> Result<String> {
        Ok(match format {
            "dot" => self.to_dot(),
            "json" => serde_json::to_string_pretty(self)?,
            "yaml" => serde_yaml::to_string(self)?,
            _ => bail!("Unknown graph format '{}'", format),
        })
    }

    /// Convert the graph to a visualization nodes and edges
    pub fn to_dot(&self) -> String {
        let nodes = self
            .indices
            .iter()
            .map(|(resource, node)| {
                let index = node.index();

                let path = match resource {
                    Resource::Symbol(symbol) => symbol.path.clone(),
                    Resource::Node(node) => node.path.clone(),
                    Resource::File(file) => file.path.clone(),
                    _ => PathBuf::new(),
                };
                let path = path
                    .strip_prefix(&self.path)
                    .unwrap_or(&path)
                    .to_slash_lossy();

                let (shape, fill_color, label) = match resource {
                    Resource::Symbol(symbol) => (
                        "diamond",
                        "#efb8b8",
                        format!(
                            "{}{}",
                            if !symbol.kind.is_empty() {
                                format!("{}\\n", symbol.kind)
                            } else {
                                "".to_string()
                            },
                            symbol.name
                        ),
                    ),
                    Resource::Node(node) => {
                        let label = if !node.id.starts_with('_') {
                            format!("{}\\n{}", node.kind, node.id)
                        } else {
                            node.kind.clone()
                        };
                        ("box", "#efe0b8", label)
                    }
                    Resource::File(..) => ("note", "#d1efb8", path.clone()),
                    Resource::Source(source) => ("house", "#efb8d4", source.name.clone()),
                    Resource::Module(module) => ("invhouse", "#b8efed", module.name.clone()),
                    Resource::Url(url) => ("box", "#cab8ef", url.url.clone()),
                };

                let node = match resource {
                    Resource::File(..) => format!(
                        r#"  n{index} [shape="point", style="invis" label="{label}"]"#,
                        index = index,
                        label = label
                    ),
                    _ => format!(
                        r#"  n{index} [shape="{shape}" fillcolor="{fill_color}" label="{label}"]"#,
                        index = index,
                        shape = shape,
                        fill_color = fill_color,
                        label = label.replace('\"', "\\\"")
                    ),
                };

                (path, node)
            })
            .collect::<Vec<(String, String)>>();

        let mut clusters: HashMap<String, Vec<String>> = HashMap::new();
        for (path, node) in nodes {
            clusters.entry(path).or_default().push(node)
        }

        let path_to_cluster = |path: &Path| {
            clusters
                .keys()
                .position(|key| {
                    key == &path
                        .strip_prefix(&self.path)
                        .unwrap_or(path)
                        .to_slash_lossy()
                })
                .unwrap_or(0)
        };

        let subgraphs = clusters
            .iter()
            .enumerate()
            .map(|(index, (label, nodes))| {
                if label.is_empty() {
                    nodes.join("\n")
                } else {
                    [
                        &format!("  subgraph cluster{} {{\n", index),
                        &format!("    label=\"{}\" fillcolor=\"#d1efb8\"\n  ", label),
                        &nodes.join("\n  "),
                        "\n  }",
                    ]
                    .concat()
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        let edges = self
            .graph
            .edge_indices()
            .filter_map(|edge| {
                if let (Some((from, to)), Some(relation)) = (
                    self.graph.edge_endpoints(edge),
                    self.graph.edge_weight(edge),
                ) {
                    let (label, style) = match relation {
                        Relation::Convert(relations::Convert { auto: active })
                        | Relation::Import(relations::Import { auto: active }) => (
                            relation.to_string(),
                            if *active { "solid" } else { "dashed" },
                        ),
                        Relation::Assign(relations::Assign { range })
                        | Relation::Use(relations::Use { range })
                        | Relation::Read(relations::Read { range })
                        | Relation::Write(relations::Write { range }) => {
                            let label = if *range == relations::NULL_RANGE {
                                relation.to_string()
                            } else {
                                format!("{} L{}", relation, range.0 + 1)
                            };
                            (label, "solid")
                        }
                        _ => (relation.to_string(), "solid"),
                    };

                    let ltail = if let Some(Resource::File(file)) = self.graph.node_weight(from) {
                        format!(" ltail=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    let lhead = if let Some(Resource::File(file)) = self.graph.node_weight(to) {
                        format!(" lhead=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    Some(format!(
                        r#"  n{from} -> n{to} [label="{label}" style="{style}"{ltail}{lhead}]"#,
                        from = from.index(),
                        to = to.index(),
                        label = label,
                        style = style,
                        ltail = ltail,
                        lhead = lhead,
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        format!(
            r#"digraph {{
  graph [rankdir=LR compound=true fontname=Helvetica fontsize=12 labeljust=l color=gray]
  node [style=filled fontname=Helvetica fontsize=11]
  edge [fontname=Helvetica fontsize=10]

{subgraphs}

{edges}
}}
"#,
            subgraphs = subgraphs,
            edges = edges
        )
    }
}

#[derive(Debug, Display, JsonSchema, Serialize)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum GraphEventType {
    Updated,
}

#[skip_serializing_none]
#[derive(Debug, JsonSchema, Serialize)]
#[schemars(deny_unknown_fields)]
pub struct GraphEvent {
    /// The path of the project (absolute)
    project: PathBuf,

    /// The type of event
    #[serde(rename = "type")]
    type_: GraphEventType,

    /// The graph at the time of the event
    #[schemars(schema_with = "GraphEvent::graph_schema")]
    graph: Graph,
}

impl GraphEvent {
    /// Generate the JSON Schema for the `graph` property
    fn graph_schema(_generator: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            reference: some_string!("Graph"),
            ..Default::default()
        })
    }

    /// Publish a `GraphEvent`.
    ///
    /// Will publish an event under the `projects:<project>:graph` topic.
    pub fn publish(project: &Path, type_: GraphEventType, graph: &Graph) {
        let topic = &format!("projects:{}:graph", project.display());
        let event = GraphEvent {
            project: project.to_path_buf(),
            type_,
            graph: graph.clone(),
        };
        events::publish(topic, &event)
    }
}

/// Get JSON Schemas for this crate
pub fn schemas() -> Result<serde_json::Value> {
    Ok(json!([
        schema_for!(Resource),
        schema_for!(Relation),
        schema_for!(GraphEvent),
        serde_json::json!({
            "$id": "Triple",
            "title": "Triple",
            "description": "A subject-relation-object triple",
            "type" : "array",
            "items": [
                {
                    "tsType": "Resource"
                },
                {
                    "tsType": "Relation"
                },
                {
                    "tsType": "Resource"
                }
            ],
            "minItems": 3,
            "maxItems": 3
        }),
        serde_json::json!({
            "$id": "Graph",
            "title": "Graph",
            "description": "A project dependency graph",
            "type" : "object",
            "required": ["nodes", "edges"],
            "properties": {
                "nodes": {
                    "description": "The resources in the graph",
                    "type": "array",
                    "items": {
                        "tsType": "Resource"
                    },
                    "isRequired": true
                },
                "edges": {
                    "description": "The relations between resources in the graph",
                    "type": "array",
                    "items": {
                        "type": "object",
                        "required": ["from", "to", "relation"],
                        "properties": {
                            "from": "integer",
                            "to": "integer",
                            "relation" : {
                                "tsType": "Resource"
                            }
                        },
                        "additionalProperties": false
                    },
                    "isRequired": true
                }
            },
            "additionalProperties": false
        }),
    ]))
}
<commit_msg>fix(Graphs): Place line number in parentheses for GraphViz format<commit_after>use eyre::{bail, Result};
use graph_triples::{direction, relations, Direction, Pairs, Relation, Resource, Triple};
use path_slash::PathExt;
use petgraph::{
    graph::NodeIndex,
    stable_graph::StableGraph,
    visit::{EdgeRef, IntoEdgeReferences, IntoNodeReferences},
};
use schemars::{
    gen::SchemaGenerator,
    schema::{Schema, SchemaObject},
    schema_for, JsonSchema,
};
use serde::{ser::SerializeMap, Serialize};
use serde_json::json;
use serde_with::skip_serializing_none;
use std::{
    collections::HashMap,
    path::{Path, PathBuf},
};
use strum::Display;
use utils::some_string;

/// A dependency graph for a project or document
#[derive(Debug, Default, Clone)]
pub struct Graph {
    /// The path of the project or document that this graph is for
    ///
    /// Primarily used to make file paths relative in visualizations and
    /// if ever persisting the graph.
    path: PathBuf,

    /// The graph itself
    ///
    /// Use a `petgraph::StableGraph` so that nodes can be added and removed
    /// without changing node indices.
    graph: StableGraph<Resource, Relation>,

    /// Indices of the nodes in the tree
    ///
    /// This is necessary to keep track of which resources
    /// are already in the graph and re-use their index if they are.
    indices: HashMap<Resource, NodeIndex>,
}

impl Serialize for Graph {
    /// Custom serialization to strip prefix from paths, add stable node indices,
    /// and exclude properties that are included by default by `petgraph` (e.g `node_holes`).
    ///
    /// Our general approach is to keep paths absolute whilst in memory and only convert to
    /// relative when necessary (e.g. visualizations). See also `Graph::to_dot`.
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let nodes: Vec<serde_json::Value> = self
            .graph
            .node_references()
            .map(|(index, resource)| {
                let mut obj = serde_json::to_value(resource).expect("To be able to serialize");
                let obj = obj.as_object_mut().expect("To be an object");

                // Strip prefix from paths
                if let Some(path) = match resource {
                    Resource::Symbol(symbol) => Some(symbol.path.clone()),
                    Resource::Node(node) => Some(node.path.clone()),
                    Resource::File(file) => Some(file.path.clone()),
                    _ => None,
                } {
                    let path = path
                        .strip_prefix(&self.path)
                        .unwrap_or(&path)
                        .to_slash_lossy();
                    obj.insert("path".to_string(), json!(path));
                }

                obj.insert("index".to_string(), json!(index));
                json!(obj)
            })
            .collect();

        let edges: Vec<serde_json::Value> = self
            .graph
            .edge_references()
            .map(|edge| -> serde_json::Value {
                json!({
                    "from": edge.source(),
                    "to": edge.target(),
                    "relation": edge.weight()
                })
            })
            .collect();

        let mut map = serializer.serialize_map(Some(2))?;
        map.serialize_entry("nodes", &nodes)?;
        map.serialize_entry("edges", &edges)?;
        map.end()
    }
}

/// The available graph serialization formats
pub const FORMATS: [&str; 3] = ["dot", "json", "yaml"];

impl Graph {
    /// Create a new, empty graph
    pub fn new<P: AsRef<Path>>(path: P) -> Graph {
        Graph {
            path: PathBuf::from(path.as_ref()),
            indices: HashMap::new(),
            graph: StableGraph::new(),
        }
    }

    /// Create a graph from set of dependency relations
    pub fn from_relations<P: AsRef<Path>>(path: P, relations: &[(Resource, Pairs)]) -> Graph {
        let mut graph = Graph::new(path);
        for (subject, pairs) in relations {
            for (relation, object) in pairs {
                graph.add_triple((subject.clone(), relation.clone(), object.clone()));
            }
        }
        graph
    }

    /// Add a resource to the graph
    pub fn add_resource(&mut self, resource: Resource) {
        if self.indices.get(&resource).is_none() {
            let index = self.graph.add_node(resource.clone());
            self.indices.insert(resource, index);
        }
    }

    /// Add a triple to the graph
    pub fn add_triple(&mut self, (subject, relation, object): Triple) {
        let subject = if let Some(index) = self.indices.get(&subject) {
            *index
        } else {
            let index = self.graph.add_node(subject.clone());
            self.indices.insert(subject, index);
            index
        };

        let object = if let Some(index) = self.indices.get(&object) {
            *index
        } else {
            let index = self.graph.add_node(object.clone());
            self.indices.insert(object, index);
            index
        };

        let (from, to) = match direction(&relation) {
            Direction::From => (object, subject),
            Direction::To => (subject, object),
        };

        self.graph.add_edge(from, to, relation);
    }

    /// Add a set of triples to the graph
    pub fn add_triples(&mut self, triples: Vec<Triple>) {
        triples
            .into_iter()
            .for_each(|triple| self.add_triple(triple))
    }

    /// Convert the graph to some format
    pub fn to_format(&self, format: &str) -> Result<String> {
        Ok(match format {
            "dot" => self.to_dot(),
            "json" => serde_json::to_string_pretty(self)?,
            "yaml" => serde_yaml::to_string(self)?,
            _ => bail!("Unknown graph format '{}'", format),
        })
    }

    /// Convert the graph to a visualization nodes and edges
    pub fn to_dot(&self) -> String {
        let nodes = self
            .indices
            .iter()
            .map(|(resource, node)| {
                let index = node.index();

                let path = match resource {
                    Resource::Symbol(symbol) => symbol.path.clone(),
                    Resource::Node(node) => node.path.clone(),
                    Resource::File(file) => file.path.clone(),
                    _ => PathBuf::new(),
                };
                let path = path
                    .strip_prefix(&self.path)
                    .unwrap_or(&path)
                    .to_slash_lossy();

                let (shape, fill_color, label) = match resource {
                    Resource::Symbol(symbol) => (
                        "diamond",
                        "#efb8b8",
                        format!(
                            "{}{}",
                            if !symbol.kind.is_empty() {
                                format!("{}\\n", symbol.kind)
                            } else {
                                "".to_string()
                            },
                            symbol.name
                        ),
                    ),
                    Resource::Node(node) => {
                        let label = if !node.id.starts_with('_') {
                            format!("{}\\n{}", node.kind, node.id)
                        } else {
                            node.kind.clone()
                        };
                        ("box", "#efe0b8", label)
                    }
                    Resource::File(..) => ("note", "#d1efb8", path.clone()),
                    Resource::Source(source) => ("house", "#efb8d4", source.name.clone()),
                    Resource::Module(module) => ("invhouse", "#b8efed", module.name.clone()),
                    Resource::Url(url) => ("box", "#cab8ef", url.url.clone()),
                };

                let node = match resource {
                    Resource::File(..) => format!(
                        r#"  n{index} [shape="point", style="invis" label="{label}"]"#,
                        index = index,
                        label = label
                    ),
                    _ => format!(
                        r#"  n{index} [shape="{shape}" fillcolor="{fill_color}" label="{label}"]"#,
                        index = index,
                        shape = shape,
                        fill_color = fill_color,
                        label = label.replace('\"', "\\\"")
                    ),
                };

                (path, node)
            })
            .collect::<Vec<(String, String)>>();

        let mut clusters: HashMap<String, Vec<String>> = HashMap::new();
        for (path, node) in nodes {
            clusters.entry(path).or_default().push(node)
        }

        let path_to_cluster = |path: &Path| {
            clusters
                .keys()
                .position(|key| {
                    key == &path
                        .strip_prefix(&self.path)
                        .unwrap_or(path)
                        .to_slash_lossy()
                })
                .unwrap_or(0)
        };

        let subgraphs = clusters
            .iter()
            .enumerate()
            .map(|(index, (label, nodes))| {
                if label.is_empty() {
                    nodes.join("\n")
                } else {
                    [
                        &format!("  subgraph cluster{} {{\n", index),
                        &format!("    label=\"{}\" fillcolor=\"#d1efb8\"\n  ", label),
                        &nodes.join("\n  "),
                        "\n  }",
                    ]
                    .concat()
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        let edges = self
            .graph
            .edge_indices()
            .filter_map(|edge| {
                if let (Some((from, to)), Some(relation)) = (
                    self.graph.edge_endpoints(edge),
                    self.graph.edge_weight(edge),
                ) {
                    let (label, style) = match relation {
                        Relation::Convert(relations::Convert { auto: active })
                        | Relation::Import(relations::Import { auto: active }) => (
                            relation.to_string(),
                            if *active { "solid" } else { "dashed" },
                        ),
                        Relation::Assign(relations::Assign { range })
                        | Relation::Use(relations::Use { range })
                        | Relation::Read(relations::Read { range })
                        | Relation::Write(relations::Write { range }) => {
                            let label = if *range == relations::NULL_RANGE {
                                relation.to_string()
                            } else {
                                format!("{} (L{})", relation, range.0 + 1)
                            };
                            (label, "solid")
                        }
                        _ => (relation.to_string(), "solid"),
                    };

                    let ltail = if let Some(Resource::File(file)) = self.graph.node_weight(from) {
                        format!(" ltail=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    let lhead = if let Some(Resource::File(file)) = self.graph.node_weight(to) {
                        format!(" lhead=\"cluster{}\"", path_to_cluster(&file.path))
                    } else {
                        "".to_string()
                    };

                    Some(format!(
                        r#"  n{from} -> n{to} [label="{label}" style="{style}"{ltail}{lhead}]"#,
                        from = from.index(),
                        to = to.index(),
                        label = label,
                        style = style,
                        ltail = ltail,
                        lhead = lhead,
                    ))
                } else {
                    None
                }
            })
            .collect::<Vec<String>>()
            .join("\n");

        format!(
            r#"digraph {{
  graph [rankdir=LR compound=true fontname=Helvetica fontsize=12 labeljust=l color=gray]
  node [style=filled fontname=Helvetica fontsize=11]
  edge [fontname=Helvetica fontsize=10]

{subgraphs}

{edges}
}}
"#,
            subgraphs = subgraphs,
            edges = edges
        )
    }
}

#[derive(Debug, Display, JsonSchema, Serialize)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum GraphEventType {
    Updated,
}

#[skip_serializing_none]
#[derive(Debug, JsonSchema, Serialize)]
#[schemars(deny_unknown_fields)]
pub struct GraphEvent {
    /// The path of the project (absolute)
    project: PathBuf,

    /// The type of event
    #[serde(rename = "type")]
    type_: GraphEventType,

    /// The graph at the time of the event
    #[schemars(schema_with = "GraphEvent::graph_schema")]
    graph: Graph,
}

impl GraphEvent {
    /// Generate the JSON Schema for the `graph` property
    fn graph_schema(_generator: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            reference: some_string!("Graph"),
            ..Default::default()
        })
    }

    /// Publish a `GraphEvent`.
    ///
    /// Will publish an event under the `projects:<project>:graph` topic.
    pub fn publish(project: &Path, type_: GraphEventType, graph: &Graph) {
        let topic = &format!("projects:{}:graph", project.display());
        let event = GraphEvent {
            project: project.to_path_buf(),
            type_,
            graph: graph.clone(),
        };
        events::publish(topic, &event)
    }
}

/// Get JSON Schemas for this crate
pub fn schemas() -> Result<serde_json::Value> {
    Ok(json!([
        schema_for!(Resource),
        schema_for!(Relation),
        schema_for!(GraphEvent),
        serde_json::json!({
            "$id": "Triple",
            "title": "Triple",
            "description": "A subject-relation-object triple",
            "type" : "array",
            "items": [
                {
                    "tsType": "Resource"
                },
                {
                    "tsType": "Relation"
                },
                {
                    "tsType": "Resource"
                }
            ],
            "minItems": 3,
            "maxItems": 3
        }),
        serde_json::json!({
            "$id": "Graph",
            "title": "Graph",
            "description": "A project dependency graph",
            "type" : "object",
            "required": ["nodes", "edges"],
            "properties": {
                "nodes": {
                    "description": "The resources in the graph",
                    "type": "array",
                    "items": {
                        "tsType": "Resource"
                    },
                    "isRequired": true
                },
                "edges": {
                    "description": "The relations between resources in the graph",
                    "type": "array",
                    "items": {
                        "type": "object",
                        "required": ["from", "to", "relation"],
                        "properties": {
                            "from": "integer",
                            "to": "integer",
                            "relation" : {
                                "tsType": "Resource"
                            }
                        },
                        "additionalProperties": false
                    },
                    "isRequired": true
                }
            },
            "additionalProperties": false
        }),
    ]))
}
<|endoftext|>


<commit_before>pub fn primitive_types_main() {
    println!("///*** Primitive Types ***\\\\\\\n");

    arrays();
    bools();
    chars();

    println!("");
}

fn arrays() {
    println!("*** Arrays ***");

    let mut array: [i32; 3] = [0; 3];

    array[1] = 1;
    array[2] = 2;

    assert_eq!([1, 2], &array[1..]);

    // only if array has 32 of fever elements
    for x in &array {
        print!("{} ", x);
    }
    println!("");

    // any size
    for x in array.iter() {
        print!("{} ", x);
    }
    println!("");

    println!("");
}

fn bools() {
    println!("*** Bools ***");

    // binary operations
    let bool_val = true & false | false;
    assert!(!bool_val);

    // simple usage

    let praise_the_borrow_checker = true;

    if praise_the_borrow_checker {
        println!("yeah!");
    } else {
        println!("what?!");
    }

    match praise_the_borrow_checker {
        true => println!("keep praising!"),
        false => println!("you should praise!"),
    }

    // casting to a number

    assert_eq!(true as i32, 1);
    assert_eq!(false as i32, 0);

    // bool from a string

    use std::str::FromStr;

    assert_eq!(FromStr::from_str("true"), Ok(true));
    assert_eq!(FromStr::from_str("false"), Ok(false));
    assert!(<bool as FromStr>::from_str("not even a bool").is_err());

    assert_eq!("true".parse(), Ok(true));
    assert_eq!("false".parse(), Ok(false));
    assert!("not even a bool".parse::<bool>().is_err());

    println!("");
}

fn chars() {
    println!("*** Chars ***");

    use std;

    // char is always 4 bytes in size
    let v = vec!['h', 'e', 'l', 'l', 'o'];

    assert_eq!(20, v.len() * std::mem::size_of::<char>());

    let s = String::from("hello");

    // five elements, one byte per element
    assert_eq!(5, s.len() * std::mem::size_of::<u8>());

    assert!('1'.is_digit(10));
    assert!('f'.is_digit(16));
    assert!(!'f'.is_digit(10));

    assert_eq!('1'.to_digit(10), Some(1));
    assert_eq!('f'.to_digit(16), Some(15));

    assert_eq!('f'.to_digit(10), None);
    assert_eq!('z'.to_digit(16), None);

    println!("Unicode escape sequence for X: {}", 'X'.escape_unicode());

    // experimental api
    println!("Debug escape for \\n: {}", '\n'.escape_debug());

    println!("default escape for '\"': {}", '"'.escape_default());

    assert_eq!(1, 'A'.len_utf8());
    assert_eq!(2, 'ß'.len_utf8());

    assert_eq!(1, 'ß'.len_utf16());

    // encoding as utfs

    let mut b = [0; 2];
    let result = 'ß'.encode_utf8(&mut b);

    assert_eq!(result, "ß");
    assert_eq!(result.len(), 2);

    assert!('a'.is_alphabetic());

    assert!('a'.is_lowercase());
    assert!('ß'.is_lowercase());

    assert!('A'.is_uppercase());

    assert!(' '.is_whitespace());
    assert!(!'x'.is_whitespace());

    assert!('x'.is_alphanumeric());
    assert!('1'.is_alphanumeric());

    assert!('\r'.is_control());
    assert!(!'x'.is_control());

    assert!('8'.is_numeric());
    assert!(!'a'.is_numeric());

    println!("'X' to lowercase is: {}", 'X'.to_lowercase());
    assert_eq!('C'.to_lowercase().to_string(), "c");

    println!("'a' to uppercase is: {}", 'a'.to_uppercase());
    assert_eq!('a'.to_uppercase().to_string(), "A");

    println!("");
}
<commit_msg>[Rust] STD Library - Primitive Types - f32<commit_after>pub fn primitive_types_main() {
    println!("///*** Primitive Types ***\\\\\\\n");

    arrays();
    bools();
    chars();
    f32s();

    println!("");
}

fn arrays() {
    println!("*** Arrays ***");

    let mut array: [i32; 3] = [0; 3];

    array[1] = 1;
    array[2] = 2;

    assert_eq!([1, 2], &array[1..]);

    // only if array has 32 of fever elements
    for x in &array {
        print!("{} ", x);
    }
    println!("");

    // any size
    for x in array.iter() {
        print!("{} ", x);
    }
    println!("");

    println!("");
}

fn bools() {
    println!("*** Bools ***");

    // binary operations
    let bool_val = true & false | false;
    assert!(!bool_val);

    // simple usage

    let praise_the_borrow_checker = true;

    if praise_the_borrow_checker {
        println!("yeah!");
    } else {
        println!("what?!");
    }

    match praise_the_borrow_checker {
        true => println!("keep praising!"),
        false => println!("you should praise!"),
    }

    // casting to a number

    assert_eq!(true as i32, 1);
    assert_eq!(false as i32, 0);

    // bool from a string

    use std::str::FromStr;

    assert_eq!(FromStr::from_str("true"), Ok(true));
    assert_eq!(FromStr::from_str("false"), Ok(false));
    assert!(<bool as FromStr>::from_str("not even a bool").is_err());

    assert_eq!("true".parse(), Ok(true));
    assert_eq!("false".parse(), Ok(false));
    assert!("not even a bool".parse::<bool>().is_err());

    println!("");
}

fn chars() {
    println!("*** Chars ***");

    use std;

    // char is always 4 bytes in size
    let v = vec!['h', 'e', 'l', 'l', 'o'];

    assert_eq!(20, v.len() * std::mem::size_of::<char>());

    let s = String::from("hello");

    // five elements, one byte per element
    assert_eq!(5, s.len() * std::mem::size_of::<u8>());

    assert!('1'.is_digit(10));
    assert!('f'.is_digit(16));
    assert!(!'f'.is_digit(10));

    assert_eq!('1'.to_digit(10), Some(1));
    assert_eq!('f'.to_digit(16), Some(15));

    assert_eq!('f'.to_digit(10), None);
    assert_eq!('z'.to_digit(16), None);

    println!("Unicode escape sequence for X: {}", 'X'.escape_unicode());

    // experimental api
    println!("Debug escape for \\n: {}", '\n'.escape_debug());

    println!("default escape for '\"': {}", '"'.escape_default());

    assert_eq!(1, 'A'.len_utf8());
    assert_eq!(2, 'ß'.len_utf8());

    assert_eq!(1, 'ß'.len_utf16());

    // encoding as utfs

    let mut b = [0; 2];
    let result = 'ß'.encode_utf8(&mut b);

    assert_eq!(result, "ß");
    assert_eq!(result.len(), 2);

    assert!('a'.is_alphabetic());

    assert!('a'.is_lowercase());
    assert!('ß'.is_lowercase());

    assert!('A'.is_uppercase());

    assert!(' '.is_whitespace());
    assert!(!'x'.is_whitespace());

    assert!('x'.is_alphanumeric());
    assert!('1'.is_alphanumeric());

    assert!('\r'.is_control());
    assert!(!'x'.is_control());

    assert!('8'.is_numeric());
    assert!(!'a'.is_numeric());

    println!("'X' to lowercase is: {}", 'X'.to_lowercase());
    assert_eq!('C'.to_lowercase().to_string(), "c");

    println!("'a' to uppercase is: {}", 'a'.to_uppercase());
    assert_eq!('a'.to_uppercase().to_string(), "A");

    println!("");
}

fn f32s() {
    println!("*** f32 ***");

    use std::f32;

    let nan = f32::NAN;
    assert!(nan.is_nan());
    assert!(!89_f32.is_nan());

    let inf = f32::INFINITY;
    let n_inf = f32::NEG_INFINITY;

    assert!(!89_f32.is_infinite());
    assert!(!nan.is_infinite());

    assert!(inf.is_infinite());
    assert!(n_inf.is_infinite());

    assert!(89_f32.is_finite());
    assert!(!inf.is_finite());
    assert!(!n_inf.is_finite());
    assert!(!nan.is_finite());

    let min = f32::MIN_POSITIVE;
    let max = f32::MAX;

    let lower_than_min = 1.0e-40_f32;
    let zero = 0.0_f32;

    assert!(min.is_normal());
    assert!(max.is_normal());

    assert!(!zero.is_normal());
    assert!(!f32::NAN.is_normal());
    assert!(!f32::INFINITY.is_normal());

    // values between 0 and min are Subnormal
    assert!(!lower_than_min.is_normal());

    use std::num::FpCategory;

    assert_eq!(12.4_f32.classify(), FpCategory::Normal);
    assert_eq!(f32::INFINITY.classify(), FpCategory::Infinite);

    assert_eq!(3.99_f32.floor(), 3.0);

    assert_eq!(3.01_f32.ceil(), 4.0);

    assert_eq!(3.3_f32.round(), 3.0);
    assert_eq!(3.5_f32.round(), 4.0);

    assert_eq!(3.3_f32.trunc(), 3.0);
    assert_eq!(3.9_f32.trunc(), 3.0);

    assert_eq!(3.5_f32.fract(), 0.5);
    assert_eq!(3.0_f32.fract(), 0.0);

    assert_eq!(3.5_f32.abs(), 3.5);
    assert_eq!((-3.5_f32).abs(), 3.5);

    assert_eq!(1.0, 3.5_f32.signum());
    assert_eq!(-1.0, (-3.5_f32).signum());

    assert!(f32::NAN.signum().is_nan());

    assert!(7.0_f32.is_sign_positive());
    assert!(!(-7.0_f32).is_sign_positive());

    assert!((-7.0_f32).is_sign_negative());
    assert!(!7.0_f32.is_sign_negative());

    assert!(!f32::NAN.is_sign_positive() && !f32::NAN.is_sign_negative());

    println!("10.0 * 2.0 + 0.5 = {}", 10.0_f32.mul_add(2.0, 0.5));

    assert_eq!(0.25, 4.0_f32.recip());

    assert_eq!(32.0, 2.0_f32.powi(5));

    assert_eq!(32.0, 2.0_f32.powf(5.0));

    assert_eq!(4.0, 16.0_f32.sqrt());

    println!("e^2 = {}", 2.0_f32.exp());

    println!("2^6 = {}", 6.0_f32.exp2());

    // natural logarithm
    println!("ln(10) = {}", 10.0_f32.ln());

    println!("log(10, 2) = {}", 10.0_f32.log(2.0));

    println!("log2(10) = {}", 10.0_f32.log2());

    println!("log10(20) = {}", 20.0_f32.log10());

    println!("pi to degrees: {}", f32::consts::PI.to_degrees());

    println!("180 deg to radians: {}", 180.0_f32.to_radians());

    assert_eq!(3.0, 1.0_f32.max(3.0));
    assert_eq!(1.0, 1.0_f32.min(3.0));

    assert_eq!(3.0, 27.0_f32.cbrt());

    println!("hypot of 2.0 and 3.0 = {}", 2.0_f32.hypot(3.0));

    // radians
    println!("sin of 3: {}", 3.0_f32.sin());
    println!("cos of 3: {}", 3.0_f32.cos());
    println!("tan of 3: {}", 3.0_f32.tan());

    println!("asin of 0.8: {}", 0.8_f32.asin());
    println!("acos of 0.8: {}", 0.8_f32.acos());
    println!("atan of 0.8: {}", 0.8_f32.atan());
    println!("atan2 of 3.0 and 0.5: {}", 3.0_f32.atan2(0.5));

    println!("sin and cos of 3: {:?}", 3.0_f32.sin_cos());

    println!("e^2-1 is {}", 2.0_f32.exp_m1());

    println!("ln_1p of 2.5: {}", 2.5_f32.ln_1p());

    println!("sinh of 3: {}", 3.0_f32.sinh());
    println!("cosh of 3: {}", 3.0_f32.cosh());
    println!("tanh of 3: {}", 3.0_f32.tanh());

    println!("asinh of 3: {}", 3.0_f32.asinh());
    println!("acosh of 3: {}", 3.0_f32.acosh());
    println!("atanh of 0.8: {}", 0.8_f32.atanh());

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


<commit_before>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

brush!(Brush {
    ["../assets/logo.png",
        [Logo,
        0, 0, 92, 24, 0, 0]
    ]

    ["../assets/icon.png",
        [IconHeart,
            0, 8, 8, 8, 0, 0]
        [IconHalfHeart,
            0, 8, 8, 8, 8, 0]
        [IconNoHeart,
            0, 8, 8, 8, 16, 0]
        [IconShard,
            0, 8, 8, 8, 24, 0]
        [IconHalfShard,
            0, 8, 8, 8, 32, 0]
        [IconNoShard,
            0, 8, 8, 8, 40, 0]
    ]

    ["../assets/blocks.png",
        [BlockRear,
            16, 16, 32, 32,   0,   0,
            16, 16, 32, 32,  32,   0,
            16, 16, 32, 32,  64,   0,
            16, 16, 32, 16,  96,   0,
             0, 16, 32, 16, 112,   0,
            16, 16, 32, 16, 128,   0,
             0, 16, 32, 16, 144,   0]
        [BlockRock,
            16, 16, 32, 32,   0,  32,
            16, 16, 32, 32,  32,  32,
            16, 16, 32, 32,  64,  32,
            16, 16, 32, 16,  96,  32,
             0, 16, 32, 16, 112,  32,
            16, 16, 32, 16, 128,  32,
             0, 16, 32, 16, 144,  32]
    ]

    ["../assets/walls.png",
        [BrickWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  32,   0,
             0, 16, 32, 16,  48,   0]
        [BrickWindowWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  64,   0,
             0, 16, 32, 16,  80,   0]
        [BrickOpenWall,
            16, 16, 32, 16,   0,   0,
             0, 16, 32, 16,  16,   0,
            16, 16, 32, 16,  96,   0,
             0, 16, 32, 16, 112,   0]
        [DoorWall,
            16, 16, 32, 16, 128,   0,
             0, 16, 32, 16, 144,   0,
            16, 16, 32, 16, 160,   0,
             0, 16, 32, 16, 176,   0]
        [BarsWall,
            16, 16, 32, 16, 192,   0,
             0, 16, 32, 16, 208,   0,
            16, 16, 32, 16, 224,   0,
             0, 16, 32, 16, 240,   0]
        [FenceWall,
            16, 16, 32, 16,   0,  32,
             0, 16, 32, 16,  16,  32,
            16, 16, 32, 16,  32,  32,
             0, 16, 32, 16,  48,  32]
        [HouseWall,
            16, 16, 32, 16,  64,  32,
             0, 16, 32, 16,  80,  32,
            16, 16, 32, 16,  96,  32,
             0, 16, 32, 16, 112,  32]
        [RockWall,
            16, 16, 32, 16, 128,  32,
             0, 16, 32, 16, 144,  32,
            16, 16, 32, 16, 160,  32,
             0, 16, 32, 16, 176,  32]
    ]

    ["../assets/floors.png",
        [BlankFloor,
            16, 16, 32, 32,   0,   0]
        [Floor,
            16, 16, 32, 32,  32,   0]
        [Grass,
            16, 16, 32, 32,  64,   0]
        [Water,
            16, 16, 32, 32,  96,   0]
        [Shallows,
            16, 16, 32, 32, 128,   0]
    ]

    ["../assets/mobs.png",
        [Human,
            16, 16, 32, 32,   0,   0]
        [Snake,
            16, 16, 32, 32,  32,   0]
        [Dreg,
            16, 16, 32, 32,  64,   0]
        [Ogre,
            16, 16, 32, 32,  96,   0]
        [Wraith,
            16, 16, 32, 32, 128,   0]
        [Octopus,
            16, 16, 32, 32, 160,   0]
        [Bug,
            16, 16, 32, 32, 192,   0]
        [Ooze,
            16, 16, 32, 32, 224,   0]
        [Efreet,
            16, 16, 32, 32,   0,  32]
        [Serpent,
            // Head
            16, 16, 32, 32,  32,  32,
            // Burrow mound
            16, 16, 32, 32,  64,  32]
    ]

    ["../assets/props.png",
        [CursorBottom,
            16, 16, 32, 32,   0,   0]
        [CursorTop,
            16, 16, 32, 32,  32,   0]
        [Table,
            16, 16, 32, 32,  64,   0]
        [Stone,
            16, 16, 32, 32,  96,   0]
        [Fountain,
            16, 16, 32, 32, 128,   0]
        [Altar,
            16, 16, 32, 32, 160,   0]
        [Barrell,
            16, 16, 32, 32, 192,   0]
        [Stalagmite,
            16, 16, 32, 32, 224,   0]
        [Pillar,
            16, 16, 32, 32,   0,  32]
        [Grave,
            16, 16, 32, 32,  32,  32]
        [Crystal,
            16, 16, 32, 32,  64,  32]
        [Menhir,
            16, 16, 32, 32,  96,  32]
        [Sword,
            16, 16, 32, 32, 128,  32]
        [Helmet,
            16, 16, 32, 32, 160,  32]
        [Potion,
            16, 16, 32, 32, 192,  32]
        [Wand,
            16, 16, 32, 32, 224,  32]
        [Health,
            16, 16, 32, 32,   0,  64]
        [Knives,
            16, 16, 32, 32,  32,  64]
        [Armor,
            16, 16, 32, 32,  64,  64]
        [Ring,
            16, 16, 32, 32,  96,  64]
        [StairsDown,
            16, 16, 32, 32, 128,  64]
        [TreeTrunk,
            16, 16, 32, 32, 160,  64]
        [TreeFoliage,
            16, 16, 32, 32, 192,  64]
    ]
});
<commit_msg>Fix botched brush data<commit_after>//////////// Brush cache boilerplate ////////////

use std::cell::{RefCell};
use calx::{ImageStore, IndexCache};
use calx::backend::{CanvasBuilder, Image};

brush!(Brush {
    ["../assets/logo.png",
        [Logo,
        0, 0, 92, 24, 0, 0]
    ]

    ["../assets/icon.png",
        [IconHeart,
            0, 8, 8, 8, 0, 0]
        [IconHalfHeart,
            0, 8, 8, 8, 8, 0]
        [IconNoHeart,
            0, 8, 8, 8, 16, 0]
        [IconShard,
            0, 8, 8, 8, 24, 0]
        [IconHalfShard,
            0, 8, 8, 8, 32, 0]
        [IconNoShard,
            0, 8, 8, 8, 40, 0]
    ]

    ["../assets/blocks.png",
        [BlockRear,
            16, 16, 32, 32,   0,   0,
            16, 16, 32, 32,  32,   0,
            16, 16, 32, 32,  64,   0,
            16, 16, 16, 32,  96,   0,
             0, 16, 16, 32, 112,   0,
            16, 16, 16, 32, 128,   0,
             0, 16, 16, 32, 144,   0]
        [BlockRock,
            16, 16, 32, 32,   0,  32,
            16, 16, 32, 32,  32,  32,
            16, 16, 32, 32,  64,  32,
            16, 16, 16, 32,  96,  32,
             0, 16, 16, 32, 112,  32,
            16, 16, 16, 32, 128,  32,
             0, 16, 16, 32, 144,  32]
    ]

    ["../assets/walls.png",
        [BrickWall,
            16, 16, 16, 32,   0,   0,
             0, 16, 16, 32,  16,   0,
            16, 16, 16, 32,  32,   0,
             0, 16, 16, 32,  48,   0]
        [BrickWindowWall,
            16, 16, 16, 32,   0,   0,
             0, 16, 16, 32,  16,   0,
            16, 16, 16, 32,  64,   0,
             0, 16, 16, 32,  80,   0]
        [BrickOpenWall,
            16, 16, 16, 32,   0,   0,
             0, 16, 16, 32,  16,   0,
            16, 16, 16, 32,  96,   0,
             0, 16, 16, 32, 112,   0]
        [DoorWall,
            16, 16, 16, 32, 128,   0,
             0, 16, 16, 32, 144,   0,
            16, 16, 16, 32, 160,   0,
             0, 16, 16, 32, 176,   0]
        [BarsWall,
            16, 16, 16, 32, 192,   0,
             0, 16, 16, 32, 208,   0,
            16, 16, 16, 32, 224,   0,
             0, 16, 16, 32, 240,   0]
        [FenceWall,
            16, 16, 16, 32,   0,  32,
             0, 16, 16, 32,  16,  32,
            16, 16, 16, 32,  32,  32,
             0, 16, 16, 32,  48,  32]
        [HouseWall,
            16, 16, 16, 32,  64,  32,
             0, 16, 16, 32,  80,  32,
            16, 16, 16, 32,  96,  32,
             0, 16, 16, 32, 112,  32]
        [RockWall,
            16, 16, 16, 32, 128,  32,
             0, 16, 16, 32, 144,  32,
            16, 16, 16, 32, 160,  32,
             0, 16, 16, 32, 176,  32]
    ]

    ["../assets/floors.png",
        [BlankFloor,
            16, 16, 32, 32,   0,   0]
        [Floor,
            16, 16, 32, 32,  32,   0]
        [Grass,
            16, 16, 32, 32,  64,   0]
        [Water,
            16, 16, 32, 32,  96,   0]
        [Shallows,
            16, 16, 32, 32, 128,   0]
    ]

    ["../assets/mobs.png",
        [Human,
            16, 16, 32, 32,   0,   0]
        [Snake,
            16, 16, 32, 32,  32,   0]
        [Dreg,
            16, 16, 32, 32,  64,   0]
        [Ogre,
            16, 16, 32, 32,  96,   0]
        [Wraith,
            16, 16, 32, 32, 128,   0]
        [Octopus,
            16, 16, 32, 32, 160,   0]
        [Bug,
            16, 16, 32, 32, 192,   0]
        [Ooze,
            16, 16, 32, 32, 224,   0]
        [Efreet,
            16, 16, 32, 32,   0,  32]
        [Serpent,
            // Head
            16, 16, 32, 32,  32,  32,
            // Burrow mound
            16, 16, 32, 32,  64,  32]
    ]

    ["../assets/props.png",
        [CursorBottom,
            16, 16, 32, 32,   0,   0]
        [CursorTop,
            16, 16, 32, 32,  32,   0]
        [Table,
            16, 16, 32, 32,  64,   0]
        [Stone,
            16, 16, 32, 32,  96,   0]
        [Fountain,
            16, 16, 32, 32, 128,   0]
        [Altar,
            16, 16, 32, 32, 160,   0]
        [Barrell,
            16, 16, 32, 32, 192,   0]
        [Stalagmite,
            16, 16, 32, 32, 224,   0]
        [Pillar,
            16, 16, 32, 32,   0,  32]
        [Grave,
            16, 16, 32, 32,  32,  32]
        [Crystal,
            16, 16, 32, 32,  64,  32]
        [Menhir,
            16, 16, 32, 32,  96,  32]
        [Sword,
            16, 16, 32, 32, 128,  32]
        [Helmet,
            16, 16, 32, 32, 160,  32]
        [Potion,
            16, 16, 32, 32, 192,  32]
        [Wand,
            16, 16, 32, 32, 224,  32]
        [Health,
            16, 16, 32, 32,   0,  64]
        [Knives,
            16, 16, 32, 32,  32,  64]
        [Armor,
            16, 16, 32, 32,  64,  64]
        [Ring,
            16, 16, 32, 32,  96,  64]
        [StairsDown,
            16, 16, 32, 32, 128,  64]
        [TreeTrunk,
            16, 16, 32, 32, 160,  64]
        [TreeFoliage,
            16, 16, 32, 32, 192,  64]
    ]
});
<|endoftext|>