<commit_before>extern crate lexer;
use std::io;
use std::io::Write;
use lexer::{Item, StateFn, Lexer};

const NUMBER_SIGNS: &'static str = "+-";
const NUMBERS: &'static str = "0123456789";
const DECIMAL_SIGN: &'static str = ".";
const NEGATE_SIGN: char = '-';

#[derive(Debug, PartialEq)]
pub enum ItemType {
    Number,
    GroupStart,
    GroupEnd,
    OperatorPlus,
    OperatorMinus,
    OperatorMul,
    OperatorDiv,
    OperatorNegate,
}

fn ignore_whitespace(l: &mut Lexer<ItemType>) -> Option<()> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(_) => {
                l.backup();
                break;
            }
        }
    }
    Some(())
}

fn lex_binary_op(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(')') => l.emit(ItemType::GroupEnd),
            Some(ch) => {
                match ch {
                    '+' => l.emit(ItemType::OperatorPlus),
                    '-' => l.emit(ItemType::OperatorMinus),
                    '*' => l.emit(ItemType::OperatorMul),
                    '/' => l.emit(ItemType::OperatorDiv),
                    _ => panic!("unexpected: {}, expected operator", ch)
                }
                break;
            },
        }
    }

    Some(StateFn(lex_group_or_number))
}

fn lex_group_or_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(ch) if ch == NEGATE_SIGN => {
                if l.peek().map_or(false, |ch| NUMBERS.contains(ch)) {
                    l.backup();
                    return Some(StateFn(lex_number));
                }
                l.emit(ItemType::OperatorNegate);
            },
            Some('(') => {
                l.emit(ItemType::GroupStart);
            },
            Some(')') => {
                l.emit(ItemType::GroupEnd);
                return Some(StateFn(lex_binary_op));
            },
            Some(_) => {
                l.backup();
                return Some(StateFn(lex_number));
            }
        }
    }
}

fn lex_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    if let None = ignore_whitespace(l) {
        return None;
    }

    l.accept(NUMBER_SIGNS);

    if !l.accept_run(NUMBERS) {
        l.backup();
        panic!("unexpected: {:?}, expected number", l.next());
    }

    if l.accept(DECIMAL_SIGN) {
        l.accept_run(NUMBERS);
    }

    l.emit(ItemType::Number);

    Some(StateFn(lex_binary_op))
}

fn evaluate_group(items: &[Item<ItemType>]) -> f64 {
    let end_pos = items.iter()
                        .position(|item| item.typ == ItemType::GroupEnd)
                        .expect("unclosed group");

    evaluate_binary_op(&items[end_pos+1..], evaluate(&items[..end_pos]))
}

fn evaluate_binary_op(items: &[Item<ItemType>], op_a: f64) -> f64 {
    match items.len() {
        0 => op_a,
        n if n >=2 => {
            let op_b = evaluate(&items[1..]);
            apply_binary_op(&items[0], op_a, op_b)
        }
        _ => panic!("malformed operator")
    }
}

fn apply_binary_op(item: &Item<ItemType>, op_a: f64, op_b: f64) -> f64 {
    match item.typ {
        ItemType::OperatorPlus => op_a + op_b,
        ItemType::OperatorMinus => op_a - op_b,
        ItemType::OperatorMul => op_a * op_b,
        ItemType::OperatorDiv => op_a / op_b,
        _ => panic!("invalid operator item: {:?}", item),
    }
}

fn evaluate(items: &[Item<ItemType>]) -> f64 {
    if items.len() == 0 {
        return 0.0
    }
    let item = &items[0];

    match item.typ {
        ItemType::GroupStart => evaluate_group(&items[1..]),
        ItemType::OperatorNegate => -evaluate(&items[1..]),
        ItemType::Number => {
            let op_a = item.val.parse().unwrap();
            evaluate_binary_op(&items[1..], op_a)
        },
        _ => panic!("unable to evaluate: {:?}", item),
    }
}

fn main() {
    loop {
        println!("Input an expression or q to quit");
        print!(">>> ");
        io::stdout().flush().ok().expect("failed to flush stdout");

        let input = {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).ok().expect("read error");
            buffer.trim().to_owned()
        };

        if input == "q" {
            return
        }

        let items = lexer::lex(&input, lex_group_or_number);

        if items.len() == 0 {
            continue;
        }

        println!("{}", evaluate(&items));
    }
}

#[test]
fn test_parser() {
    let data = "-( 123 + 2 * 3 ) * 4 + -5 * -(5+6)";
    let expected_items = vec!(
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "123" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "2" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "3" },
        Item { typ: ItemType::GroupEnd, val: ")" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "4" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "-5" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "5" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "6" },
        Item { typ: ItemType::GroupEnd, val: ")" },
    );
    let items = lexer::lex(data, lex_group_or_number);
    println!("data: {:?}", data);
    println!("items: {:?}", items);
    assert_eq!(expected_items, items);
}
<commit_msg>example: fixed error in group parsing<commit_after>extern crate lexer;
use std::io;
use std::io::Write;
use lexer::{Item, StateFn, Lexer};

const NUMBER_SIGNS: &'static str = "+-";
const NUMBERS: &'static str = "0123456789";
const DECIMAL_SIGN: &'static str = ".";
const NEGATE_SIGN: char = '-';

#[derive(Debug, PartialEq)]
pub enum ItemType {
    Number,
    GroupStart,
    GroupEnd,
    OperatorPlus,
    OperatorMinus,
    OperatorMul,
    OperatorDiv,
    OperatorNegate,
}

fn ignore_whitespace(l: &mut Lexer<ItemType>) -> Option<()> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(_) => {
                l.backup();
                break;
            }
        }
    }
    Some(())
}

fn lex_binary_op(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(')') => l.emit(ItemType::GroupEnd),
            Some(ch) => {
                match ch {
                    '+' => l.emit(ItemType::OperatorPlus),
                    '-' => l.emit(ItemType::OperatorMinus),
                    '*' => l.emit(ItemType::OperatorMul),
                    '/' => l.emit(ItemType::OperatorDiv),
                    _ => panic!("unexpected: {}, expected operator", ch)
                }
                break;
            },
        }
    }

    Some(StateFn(lex_group_or_number))
}

fn lex_group_or_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    loop {
        match l.next() {
            None => return None,
            Some(ch) if ch.is_whitespace() => l.ignore(),
            Some(ch) if ch == NEGATE_SIGN => {
                if l.peek().map_or(false, |ch| NUMBERS.contains(ch)) {
                    l.backup();
                    return Some(StateFn(lex_number));
                }
                l.emit(ItemType::OperatorNegate);
            },
            Some('(') => {
                l.emit(ItemType::GroupStart);
            },
            Some(')') => {
                l.emit(ItemType::GroupEnd);
                return Some(StateFn(lex_binary_op));
            },
            Some(_) => {
                l.backup();
                return Some(StateFn(lex_number));
            }
        }
    }
}

fn lex_number(l: &mut Lexer<ItemType>) -> Option<StateFn<ItemType>> {
    if let None = ignore_whitespace(l) {
        return None;
    }

    l.accept(NUMBER_SIGNS);

    if !l.accept_run(NUMBERS) {
        l.backup();
        panic!("unexpected: {:?}, expected number", l.next());
    }

    if l.accept(DECIMAL_SIGN) {
        l.accept_run(NUMBERS);
    }

    l.emit(ItemType::Number);

    Some(StateFn(lex_binary_op))
}

fn evaluate_group(items: &[Item<ItemType>]) -> f64 {
    let end_pos = {
        let mut inner_groups = 0usize;
        let mut pos = None;

        for (idx, item) in items.iter().enumerate() {
            match item.typ {
                ItemType::GroupStart => inner_groups += 1,
                ItemType::GroupEnd if inner_groups > 0 => inner_groups -= 1,
                ItemType::GroupEnd if inner_groups == 0 => {
                    pos = Some(idx);
                    break;
                }
                _ => {},
            }
        }
        pos
    }.expect("unclosed group");

    evaluate_binary_op(&items[end_pos+1..], evaluate(&items[..end_pos]))
}

fn evaluate_binary_op(items: &[Item<ItemType>], op_a: f64) -> f64 {
    match items.len() {
        0 => op_a,
        n if n >=2 => {
            let op_b = evaluate(&items[1..]);
            apply_binary_op(&items[0], op_a, op_b)
        }
        _ => panic!("malformed operator")
    }
}

fn apply_binary_op(item: &Item<ItemType>, op_a: f64, op_b: f64) -> f64 {
    match item.typ {
        ItemType::OperatorPlus => op_a + op_b,
        ItemType::OperatorMinus => op_a - op_b,
        ItemType::OperatorMul => op_a * op_b,
        ItemType::OperatorDiv => op_a / op_b,
        _ => panic!("invalid operator item: {:?}", item),
    }
}

fn evaluate(items: &[Item<ItemType>]) -> f64 {
    if items.len() == 0 {
        return 0.0
    }
    let item = &items[0];

    match item.typ {
        ItemType::GroupStart => evaluate_group(&items[1..]),
        ItemType::OperatorNegate => -evaluate(&items[1..]),
        ItemType::Number => {
            let op_a = item.val.parse().unwrap();
            evaluate_binary_op(&items[1..], op_a)
        },
        _ => panic!("unable to evaluate: {:?}", item),
    }
}

fn main() {
    loop {
        println!("Input an expression or q to quit");
        print!(">>> ");
        io::stdout().flush().ok().expect("failed to flush stdout");

        let input = {
            let mut buffer = String::new();
            io::stdin().read_line(&mut buffer).ok().expect("read error");
            buffer.trim().to_owned()
        };

        if input == "q" {
            return
        }

        let items = lexer::lex(&input, lex_group_or_number);

        if items.len() == 0 {
            continue;
        }

        println!("{}", evaluate(&items));
    }
}

#[test]
fn test_parser() {
    let data = "-( 123 + 2 * 3 ) * 4 + -5 * -(5+6)";
    let expected_items = vec!(
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "123" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "2" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "3" },
        Item { typ: ItemType::GroupEnd, val: ")" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::Number, val: "4" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "-5" },
        Item { typ: ItemType::OperatorMul, val: "*" },
        Item { typ: ItemType::OperatorNegate, val: "-" },
        Item { typ: ItemType::GroupStart, val: "(" },
        Item { typ: ItemType::Number, val: "5" },
        Item { typ: ItemType::OperatorPlus, val: "+" },
        Item { typ: ItemType::Number, val: "6" },
        Item { typ: ItemType::GroupEnd, val: ")" },
    );
    let items = lexer::lex(data, lex_group_or_number);
    println!("data: {:?}", data);
    println!("items: {:?}", items);
    assert_eq!(expected_items, items);
}
<|endoftext|>


<commit_before>// Copyright 2017 LambdaStack All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(unused_imports)]

extern crate ceph_rust;
extern crate libc;

use libc::*;
use std::ffi::{CStr, CString};
use std::{ptr, str, slice};

#[cfg(target_os = "linux")]
use ceph_rust::ceph as ceph_helpers;
#[cfg(target_os = "linux")]
use ceph_rust::rados as ceph;
#[cfg(target_os = "linux")]
use ceph_rust::admin_sockets::*;

use ceph_rust::JsonData;

macro_rules! zeroed_c_char_buf {
	($n:expr) => {
		repeat(0).take($n).collect::<Vec<c_char>>();
	}
}

#[cfg(not(target_os = "linux"))]
fn main() {}

// NB: The examples below show a mix of raw native access and rust specific calls.

#[cfg(target_os = "linux")]
fn main() {
    let mut major: i32 = 0;
    let mut minor: i32 = 0;
    let mut extra: i32 = 0;

    let config_file = CString::new("/etc/ceph/ceph.conf").unwrap();
    let pool_name = CString::new("lsio").unwrap();
    let mut cluster: ceph::rados_t = std::ptr::null_mut();
    let mut ret_code: i32;

    // NB: These examples (except for a few) are low level examples that require the unsafe block.
    // However, work for the higher level pur Rust is being worked on in the ceph.rs module of
    // the library. A few of those are present below. We will create a common Result or Option
    // return and allow for pattern matching.

    // Example of accessing the `Admin Socket` for mon
    match admin_socket_command("help", "/var/run/ceph/ceph-mon.ceph-vm1.asok") {
        Ok(json) => {
            println!("{}", json);
        },
        Err(e) => { println!("{}", e); },
    }

    unsafe {
        ceph::rados_version(&mut major, &mut minor, &mut extra);
        ret_code = ceph::rados_create(&mut cluster, std::ptr::null());
        println!("Return code: {} - {:?}", ret_code, cluster);

        ret_code = ceph::rados_conf_read_file(cluster, config_file.as_ptr());
        println!("Return code: {} - {:?}", ret_code, cluster);

        ret_code = ceph::rados_connect(cluster);
        println!("Return code: {} - {:?}", ret_code, cluster);

        ret_code = ceph::rados_pool_create(cluster, pool_name.as_ptr());
        println!("Return code: {}", ret_code);

        let pools_list = ceph_helpers::rados_pools(cluster).unwrap();
        println!("{:?}", pools_list);

        ret_code = ceph::rados_pool_delete(cluster, pool_name.as_ptr());
        println!("Return code: {}", ret_code);

        let instance_id = ceph::rados_get_instance_id(cluster);
        println!("Instance ID: {}", instance_id);

        let buf_size: usize = 37; // 36 is the constant size +1 for null.
        let mut fs_id: Vec<u8> = Vec::with_capacity(buf_size);

        let len = ceph::rados_cluster_fsid(cluster, fs_id.as_mut_ptr() as *mut c_char, buf_size);
        let slice = slice::from_raw_parts(fs_id.as_mut_ptr(), buf_size - 1);
        let s: &str = str::from_utf8(slice).unwrap();
        println!("rados_cluster_fsid len: {} - {}", len, s);

        // Rust specific example...
        let cluster_stat = ceph_helpers::rados_stat_cluster(cluster);
        println!("Cluster stat: {:?}", cluster_stat);

        // Mon command to check the health. Same as `ceph -s`
        match ceph_helpers::ceph_mon_command(cluster, "prefix", "status", None) {
            Ok((outbuf, outs)) => {
                match outbuf {
                    Some(output) => println!("Ceph mon command (outbuf):\n{}", output),
                    None => {},
                }
                match outs {
                    Some(output) => println!("Ceph mon command (outs):\n{}", output),
                    None => {},
                }
            },
            Err(e) => {println!("{:?}", e);},
        }

        // Print CephHealth of cluster
        println!("{}", ceph_helpers::ceph_health_string(cluster).unwrap_or("".to_string()));

        // Print Status of cluster health a different way
        println!("{}", ceph_helpers::ceph_status(cluster, &["health", "overall_status"]).unwrap());

        // This command encapsulates the lower level mon, osd, pg commands and returns JsonData objects based on the key path
        println!("{:?}", ceph_helpers::ceph_command(cluster, "prefix", "status", ceph_helpers::CephCommandTypes::Mon, &["health"]));

        // Get a list of Ceph librados commands in JSON format.
        // It's very long so it's commented out.
        // println!("{}", ceph_helpers::ceph_commands(cluster, None).unwrap().pretty());

        // Currently - parses the `ceph --version` call. The admin socket commands `version` and `git_version`
        // will be called soon to replace the string parse.
        let ceph_ver = ceph_helpers::ceph_version("/var/run/ceph/ceph-mon.ceph-vm1.asok"); // Change to the real mon admin socket name
        println!("Ceph Version - {:?}", ceph_ver);

        ceph::rados_shutdown(cluster);
    }

    println!("RADOS Version - v{}.{}.{}", major, minor, extra);

}
<commit_msg>Rustfmt<commit_after>// Copyright 2017 LambdaStack All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#![allow(unused_imports)]

extern crate ceph_rust;
extern crate libc;

use ceph_rust::JsonData;
#[cfg(target_os = "linux")]
use ceph_rust::admin_sockets::*;

#[cfg(target_os = "linux")]
use ceph_rust::ceph as ceph_helpers;
#[cfg(target_os = "linux")]
use ceph_rust::rados as ceph;
use libc::*;
use std::{ptr, slice, str};
use std::ffi::{CStr, CString};

macro_rules! zeroed_c_char_buf {
	($n:expr) => {
		repeat(0).take($n).collect::<Vec<c_char>>();
	}
}

#[cfg(not(target_os = "linux"))]
fn main() {}

// NB: The examples below show a mix of raw native access and rust specific calls.

#[cfg(target_os = "linux")]
fn main() {
    let mut major: i32 = 0;
    let mut minor: i32 = 0;
    let mut extra: i32 = 0;

    let config_file = CString::new("/etc/ceph/ceph.conf").unwrap();
    let pool_name = CString::new("lsio").unwrap();
    let mut cluster: ceph::rados_t = std::ptr::null_mut();
    let mut ret_code: i32;

    // NB: These examples (except for a few) are low level examples that require the unsafe block.
    // However, work for the higher level pur Rust is being worked on in the ceph.rs module of
    // the library. A few of those are present below. We will create a common Result or Option
    // return and allow for pattern matching.

    // Example of accessing the `Admin Socket` for mon
    match admin_socket_command("help", "/var/run/ceph/ceph-mon.ceph-vm1.asok") {
        Ok(json) => {
            println!("{}", json);
        },
        Err(e) => {
            println!("{}", e);
        },
    }

    ceph::rados_libversion(&mut major, &mut minor, &mut extra);
    ret_code = ceph::rados_create(&mut cluster, std::ptr::null());
    println!("Return code: {} - {:?}", ret_code, cluster);
    unsafe {

        ret_code = ceph::rados_conf_read_file(cluster, config_file.as_ptr());
        println!("Return code: {} - {:?}", ret_code, cluster);

        ret_code = ceph::rados_connect(cluster);
        println!("Return code: {} - {:?}", ret_code, cluster);

        ret_code = ceph::rados_pool_create(cluster, pool_name.as_ptr());
        println!("Return code: {}", ret_code);

        let pools_list = ceph_helpers::rados_pools(cluster).unwrap();
        println!("{:?}", pools_list);

        ret_code = ceph::rados_pool_delete(cluster, pool_name.as_ptr());
        println!("Return code: {}", ret_code);

        let instance_id = ceph::rados_get_instance_id(cluster);
        println!("Instance ID: {}", instance_id);

        let buf_size: usize = 37; // 36 is the constant size +1 for null.
        let mut fs_id: Vec<u8> = Vec::with_capacity(buf_size);

        let len = ceph::rados_cluster_fsid(cluster, fs_id.as_mut_ptr() as *mut c_char, buf_size);
        let slice = slice::from_raw_parts(fs_id.as_mut_ptr(), buf_size - 1);
        let s: &str = str::from_utf8(slice).unwrap();
        println!("rados_cluster_fsid len: {} - {}", len, s);

        // Rust specific example...
        let cluster_stat = ceph_helpers::rados_stat_cluster(cluster);
        println!("Cluster stat: {:?}", cluster_stat);

        // Mon command to check the health. Same as `ceph -s`
        match ceph_helpers::ceph_mon_command(cluster, "prefix", "status", None) {
            Ok((outbuf, outs)) => {
                match outbuf {
                    Some(output) => println!("Ceph mon command (outbuf):\n{}", output),
                    None => {},
                }
                match outs {
                    Some(output) => println!("Ceph mon command (outs):\n{}", output),
                    None => {},
                }
            },
            Err(e) => {
                println!("{:?}", e);
            },
        }

        // Print CephHealth of cluster
        println!("{}", ceph_helpers::ceph_health_string(cluster).unwrap_or("".to_string()));

        // Print Status of cluster health a different way
        println!("{}", ceph_helpers::ceph_status(cluster, &["health", "overall_status"]).unwrap());

        // This command encapsulates the lower level mon, osd, pg commands and returns JsonData
        // objects based on the key path
        println!("{:?}",
                 ceph_helpers::ceph_command(cluster,
                                            "prefix",
                                            "status",
                                            ceph_helpers::CephCommandTypes::Mon,
                                            &["health"]));

        // Get a list of Ceph librados commands in JSON format.
        // It's very long so it's commented out.
        // println!("{}", ceph_helpers::ceph_commands(cluster, None).unwrap().pretty());

        // Currently - parses the `ceph --version` call. The admin socket commands `version`
        // and `git_version`
        // will be called soon to replace the string parse.
        // Change to the real mon admin socket name
        let ceph_ver = ceph_helpers::ceph_version("/var/run/ceph/ceph-mon.ceph-vm1.asok");
        println!("Ceph Version - {:?}", ceph_ver);

        ceph::rados_shutdown(cluster);
    }

    println!("RADOS Version - v{}.{}.{}", major, minor, extra);

}
<|endoftext|>


<commit_before>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`. If the `Serialize` implementation of the
/// interpolated type decides to fail, or if the interpolated type contains a
/// map with non-string keys, the `json!` macro will panic.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

// Rocket relies on this because they export their own `json!` with a different
// doc comment than ours, and various Rust bugs prevent them from calling our
// `json!` from their `json!` so they call `json_internal!` directly. Check with
// @SergioBenitez before making breaking changes to this macro.
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export]
#[doc(hidden)]
macro_rules! json_internal {
    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
    // of the elements.
    //
    // Must be invoked as: json_internal!(@array [] $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done with trailing comma.
    (@array [$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    (@array [$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
    };

    // Next element is `true`.
    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
    };

    // Next element is `false`.
    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
    };

    // Next element is an array.
    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    (@array [$($elems:expr,)*] $last:expr) => {
        json_internal!(@array [$($elems,)* json_internal!($last)])
    };

    // Comma after the most recent element.
    (@array [$($elems:expr),*] , $($rest:tt)*) => {
        json_internal!(@array [$($elems,)*] $($rest)*)
    };

    // Unexpected token after most recent element.
    (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
        json_unexpected!($unexpected)
    };

    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an object {...}. Each entry is
    // inserted into the given map variable.
    //
    // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*))
    //
    // We require two copies of the input tokens so that we can match on one
    // copy and trigger errors on the other copy.
    //////////////////////////////////////////////////////////////////////////

    // Done.
    (@object $object:ident () () ()) => {};

    // Insert the current entry followed by trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_internal!(@object $object () ($($rest)*) ($($rest)*));
    };

    // Current entry followed by unexpected token.
    (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
        json_unexpected!($unexpected);
    };

    // Insert the last entry without trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
    };

    // Next value is `true`.
    (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
    };

    // Next value is `false`.
    (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
    };

    // Next value is an array.
    (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)));
    };

    // Missing value for last entry. Trigger a reasonable error message.
    (@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
        // "unexpected end of macro invocation"
        json_internal!();
    };

    // Missing colon and value for last entry. Trigger a reasonable error
    // message.
    (@object $object:ident ($($key:tt)+) () $copy:tt) => {
        // "unexpected end of macro invocation"
        json_internal!();
    };

    // Misplaced colon. Trigger a reasonable error message.
    (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
        // Takes no arguments so "no rules expected the token `:`".
        json_unexpected!($colon);
    };

    // Found a comma inside a key. Trigger a reasonable error message.
    (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
        // Takes no arguments so "no rules expected the token `,`".
        json_unexpected!($comma);
    };

    // Key is fully parenthesized. This avoids clippy double_parens false
    // positives because the parenthesization may be necessary here.
    (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
    };

    // Munch a token into the current key.
    (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
    };

    //////////////////////////////////////////////////////////////////////////
    // The main implementation.
    //
    // Must be invoked as: json_internal!($($json)+)
    //////////////////////////////////////////////////////////////////////////

    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_internal!(@array [] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_internal!(@object object () ($($tt)+) ($($tt)+));
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    // Must be below every other rule.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! json_unexpected {
    () => {};
}
<commit_msg>Local inner macros<commit_after>// Copyright 2017 Serde Developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// Construct a `serde_json::Value` from a JSON literal.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let value = json!({
///     "code": 200,
///     "success": true,
///     "payload": {
///         "features": [
///             "serde",
///             "json"
///         ]
///     }
/// });
/// # }
/// ```
///
/// Variables or expressions can be interpolated into the JSON literal. Any type
/// interpolated into an array element or object value must implement Serde's
/// `Serialize` trait, while any type interpolated into a object key must
/// implement `Into<String>`. If the `Serialize` implementation of the
/// interpolated type decides to fail, or if the interpolated type contains a
/// map with non-string keys, the `json!` macro will panic.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let code = 200;
/// let features = vec!["serde", "json"];
///
/// let value = json!({
///    "code": code,
///    "success": code == 200,
///    "payload": {
///        features[0]: features[1]
///    }
/// });
/// # }
/// ```
///
/// Trailing commas are allowed inside both arrays and objects.
///
/// ```rust
/// # #[macro_use]
/// # extern crate serde_json;
/// #
/// # fn main() {
/// let value = json!([
///     "notice",
///     "the",
///     "trailing",
///     "comma -->",
/// ]);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! json {
    // Hide distracting implementation details from the generated rustdoc.
    ($($json:tt)+) => {
        json_internal!($($json)+)
    };
}

// Rocket relies on this because they export their own `json!` with a different
// doc comment than ours, and various Rust bugs prevent them from calling our
// `json!` from their `json!` so they call `json_internal!` directly. Check with
// @SergioBenitez before making breaking changes to this macro.
//
// Changes are fine as long as `json_internal!` does not call any new helper
// macros and can still be invoked as `json_internal!($($json)+)`.
#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! json_internal {
    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an array [...]. Produces a vec![...]
    // of the elements.
    //
    // Must be invoked as: json_internal!(@array [] $($tt)*)
    //////////////////////////////////////////////////////////////////////////

    // Done with trailing comma.
    (@array [$($elems:expr,)*]) => {
        vec![$($elems,)*]
    };

    // Done without trailing comma.
    (@array [$($elems:expr),*]) => {
        vec![$($elems),*]
    };

    // Next element is `null`.
    (@array [$($elems:expr,)*] null $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(null)] $($rest)*)
    };

    // Next element is `true`.
    (@array [$($elems:expr,)*] true $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(true)] $($rest)*)
    };

    // Next element is `false`.
    (@array [$($elems:expr,)*] false $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!(false)] $($rest)*)
    };

    // Next element is an array.
    (@array [$($elems:expr,)*] [$($array:tt)*] $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!([$($array)*])] $($rest)*)
    };

    // Next element is a map.
    (@array [$($elems:expr,)*] {$($map:tt)*} $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!({$($map)*})] $($rest)*)
    };

    // Next element is an expression followed by comma.
    (@array [$($elems:expr,)*] $next:expr, $($rest:tt)*) => {
        json_internal!(@array [$($elems,)* json_internal!($next),] $($rest)*)
    };

    // Last element is an expression with no trailing comma.
    (@array [$($elems:expr,)*] $last:expr) => {
        json_internal!(@array [$($elems,)* json_internal!($last)])
    };

    // Comma after the most recent element.
    (@array [$($elems:expr),*] , $($rest:tt)*) => {
        json_internal!(@array [$($elems,)*] $($rest)*)
    };

    // Unexpected token after most recent element.
    (@array [$($elems:expr),*] $unexpected:tt $($rest:tt)*) => {
        json_unexpected!($unexpected)
    };

    //////////////////////////////////////////////////////////////////////////
    // TT muncher for parsing the inside of an object {...}. Each entry is
    // inserted into the given map variable.
    //
    // Must be invoked as: json_internal!(@object $map () ($($tt)*) ($($tt)*))
    //
    // We require two copies of the input tokens so that we can match on one
    // copy and trigger errors on the other copy.
    //////////////////////////////////////////////////////////////////////////

    // Done.
    (@object $object:ident () () ()) => {};

    // Insert the current entry followed by trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr) , $($rest:tt)*) => {
        $object.insert(($($key)+).into(), $value);
        json_internal!(@object $object () ($($rest)*) ($($rest)*));
    };

    // Current entry followed by unexpected token.
    (@object $object:ident [$($key:tt)+] ($value:expr) $unexpected:tt $($rest:tt)*) => {
        json_unexpected!($unexpected);
    };

    // Insert the last entry without trailing comma.
    (@object $object:ident [$($key:tt)+] ($value:expr)) => {
        $object.insert(($($key)+).into(), $value);
    };

    // Next value is `null`.
    (@object $object:ident ($($key:tt)+) (: null $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(null)) $($rest)*);
    };

    // Next value is `true`.
    (@object $object:ident ($($key:tt)+) (: true $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(true)) $($rest)*);
    };

    // Next value is `false`.
    (@object $object:ident ($($key:tt)+) (: false $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!(false)) $($rest)*);
    };

    // Next value is an array.
    (@object $object:ident ($($key:tt)+) (: [$($array:tt)*] $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!([$($array)*])) $($rest)*);
    };

    // Next value is a map.
    (@object $object:ident ($($key:tt)+) (: {$($map:tt)*} $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!({$($map)*})) $($rest)*);
    };

    // Next value is an expression followed by comma.
    (@object $object:ident ($($key:tt)+) (: $value:expr , $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)) , $($rest)*);
    };

    // Last value is an expression with no trailing comma.
    (@object $object:ident ($($key:tt)+) (: $value:expr) $copy:tt) => {
        json_internal!(@object $object [$($key)+] (json_internal!($value)));
    };

    // Missing value for last entry. Trigger a reasonable error message.
    (@object $object:ident ($($key:tt)+) (:) $copy:tt) => {
        // "unexpected end of macro invocation"
        json_internal!();
    };

    // Missing colon and value for last entry. Trigger a reasonable error
    // message.
    (@object $object:ident ($($key:tt)+) () $copy:tt) => {
        // "unexpected end of macro invocation"
        json_internal!();
    };

    // Misplaced colon. Trigger a reasonable error message.
    (@object $object:ident () (: $($rest:tt)*) ($colon:tt $($copy:tt)*)) => {
        // Takes no arguments so "no rules expected the token `:`".
        json_unexpected!($colon);
    };

    // Found a comma inside a key. Trigger a reasonable error message.
    (@object $object:ident ($($key:tt)*) (, $($rest:tt)*) ($comma:tt $($copy:tt)*)) => {
        // Takes no arguments so "no rules expected the token `,`".
        json_unexpected!($comma);
    };

    // Key is fully parenthesized. This avoids clippy double_parens false
    // positives because the parenthesization may be necessary here.
    (@object $object:ident () (($key:expr) : $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object ($key) (: $($rest)*) (: $($rest)*));
    };

    // Munch a token into the current key.
    (@object $object:ident ($($key:tt)*) ($tt:tt $($rest:tt)*) $copy:tt) => {
        json_internal!(@object $object ($($key)* $tt) ($($rest)*) ($($rest)*));
    };

    //////////////////////////////////////////////////////////////////////////
    // The main implementation.
    //
    // Must be invoked as: json_internal!($($json)+)
    //////////////////////////////////////////////////////////////////////////

    (null) => {
        $crate::Value::Null
    };

    (true) => {
        $crate::Value::Bool(true)
    };

    (false) => {
        $crate::Value::Bool(false)
    };

    ([]) => {
        $crate::Value::Array(vec![])
    };

    ([ $($tt:tt)+ ]) => {
        $crate::Value::Array(json_internal!(@array [] $($tt)+))
    };

    ({}) => {
        $crate::Value::Object($crate::Map::new())
    };

    ({ $($tt:tt)+ }) => {
        $crate::Value::Object({
            let mut object = $crate::Map::new();
            json_internal!(@object object () ($($tt)+) ($($tt)+));
            object
        })
    };

    // Any Serialize type: numbers, strings, struct literals, variables etc.
    // Must be below every other rule.
    ($other:expr) => {
        $crate::to_value(&$other).unwrap()
    };
}

#[macro_export]
#[doc(hidden)]
macro_rules! json_unexpected {
    () => {};
}
<|endoftext|>


<commit_before>extern crate polydraw;

use std::cmp::Ordering;
use std::i64;

use polydraw::geom::point::Point;
use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer, EdgeType, Poly, create_default_vec};

#[derive(Debug, Clone, Copy)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, x1: i64, y1: i64, x2: i64, y2: i64) -> Self {
      Edge {
         edge_type: edge_type,
         p1: Point::new(x1, y1),
         p2: Point::new(x2, y2),
      }
   }

   #[inline]
   pub fn vert_top(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVT, x1, y1, x2, y2)
   }

   #[inline]
   pub fn vert_bottom(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVB, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBL, x1, y1, x2, y2)
   }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Partial {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
   pub edge: usize,
   pub poly: usize,
}

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,

   edges: Vec<Edge>,
   polys: Vec<Poly>,

   edge_min_y: Vec<i64>,
   edge_max_y: Vec<i64>,
   edge_order: Vec<usize>,

   partials: Vec<Partial>,
}

impl ClipRenderer {
   fn new() -> Self {
      let edges = vec![
         Edge::top_left(5, 1, 1, 6),       // 0
         Edge::top_right(1, 6, 8, 9),      // 1
         Edge::bottom_right(8, 9, 9, 6),   // 2
         Edge::bottom_left(9, 6, 5, 1),    // 3
         Edge::top_right(1, 1, 3, 8),      // 4
         Edge::bottom_right(3, 8, 10, 4),  // 5
         Edge::bottom_left(10, 4, 1, 1),   // 6
      ];

      let polys = vec![
         Poly::new(0, 4, 0),    // 0
         Poly::new(4, 7, 1),    // 1
      ];

      let edge_min_y = create_default_vec(65536);
      let edge_max_y = create_default_vec(65536);
      let edge_order = create_default_vec(65536);

      let partials = create_default_vec(65536);

      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,

         edges: edges,
         polys: polys,

         edge_min_y: edge_min_y,
         edge_max_y: edge_max_y,
         edge_order: edge_order,

         partials: partials,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }

   fn init_edge_min_max_y(&mut self) {
      for edge_index in 0..self.edges.len() {
         let ref edge = self.edges[edge_index];

         let mut min_y = i64::MAX;
         let mut max_y = i64::MIN;

         let (edge_min_y, edge_max_y) = if edge.edge_type.reversed() {
            (edge.p2.y, edge.p1.y)
         } else {
            (edge.p1.y, edge.p2.y)
         };

         if edge_min_y < min_y  {
            min_y = edge_min_y;
         }

         if edge_max_y > max_y {
            max_y = edge_max_y;
         }

         self.edge_min_y[edge_index] = min_y;
         self.edge_max_y[edge_index] = max_y;
         self.edge_order[edge_index] = edge_index;
      }

      self.sort_edge_order();

      let edges_len = self.edges.len();

      println!("MIN Y {:?}", &self.edge_min_y[..edges_len]);
      println!("MAX Y {:?}", &self.edge_max_y[..edges_len]);
      println!("ORDER {:?}", &self.edge_order[..edges_len]);

      self.iterate_edges();

      panic!("END");
   }

   fn sort_edge_order(&mut self) {
      let edge_order = &mut self.edge_order;
      let edge_min_y = &self.edge_min_y;
      let edge_max_y = &self.edge_max_y;

      edge_order.sort_by(|a, b| {
         match edge_min_y[*a].cmp(&edge_min_y[*b]) {
            Ordering::Less => Ordering::Less,
            Ordering::Greater => Ordering::Greater,
            Ordering::Equal => edge_max_y[*a].cmp(&edge_max_y[*b])
         }
      });
   }

   fn iterate_edges(&self) {
      let mut prev_y = i64::MIN;
      for order_index in 0..self.edges.len() {
         let edge_index = self.edge_order[order_index];
         let ref edge = self.edges[edge_index];
         let min_y = self.edge_min_y[edge_index];

         if min_y != prev_y {
            println!("HOR {:?}", min_y);
            prev_y = min_y;
         }
      }
   }

   fn transfer_partials(&mut self) {
      let partial_index = 0;

      for poly_index in 0..self.polys.len() {
         let ref poly = self.polys[poly_index];

         for edge_index in poly.start..poly.end {
            let ref edge = self.edges[edge_index];

            self.partials[partial_index] = Partial {
               edge_type: edge.edge_type,
               p1: edge.p1,
               p2: edge.p2,
               edge: edge_index,
               poly: poly_index,
            };
         }
      }

      let edges_len = self.edges.len();

      println!("PARTIALS {:?}", &self.partials[..edges_len]);
   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      self.transfer_partials();

      self.init_edge_min_max_y();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<commit_msg>Converting the clip min/max y vectors to work with partials<commit_after>extern crate polydraw;

use std::cmp::Ordering;
use std::i64;

use polydraw::geom::point::Point;
use polydraw::{Application, Renderer, Frame};
use polydraw::raster::{Scene, Rasterizer, EdgeType, Poly, create_default_vec};

#[derive(Debug, Clone, Copy)]
pub struct Edge {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
}

impl Edge {
   #[inline]
   pub fn new(edge_type: EdgeType, x1: i64, y1: i64, x2: i64, y2: i64) -> Self {
      Edge {
         edge_type: edge_type,
         p1: Point::new(x1, y1),
         p2: Point::new(x2, y2),
      }
   }

   #[inline]
   pub fn vert_top(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVT, x1, y1, x2, y2)
   }

   #[inline]
   pub fn vert_bottom(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LVB, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn hori_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LHL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn top_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LTL, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_right(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBR, x1, y1, x2, y2)
   }

   #[inline]
   pub fn bottom_left(x1: i64, y1: i64, x2: i64, y2: i64) -> Edge {
      Edge::new(EdgeType::LBL, x1, y1, x2, y2)
   }
}

#[derive(Debug, Clone, Copy, Default)]
pub struct Partial {
   pub edge_type: EdgeType,
   pub p1: Point,
   pub p2: Point,
   pub edge: usize,
   pub poly: usize,
}

struct ClipRenderer {
   rasterizer: Rasterizer,
   div_per_pixel: i64,

   edges: Vec<Edge>,
   polys: Vec<Poly>,

   partials: Vec<Partial>,
   partials_end: usize,

   partials_min_y: Vec<i64>,
   partials_max_y: Vec<i64>,
   partials_order: Vec<usize>,
}

impl ClipRenderer {
   fn new() -> Self {
      let edges = vec![
         Edge::top_left(5, 1, 1, 6),       // 0
         Edge::top_right(1, 6, 8, 9),      // 1
         Edge::bottom_right(8, 9, 9, 6),   // 2
         Edge::bottom_left(9, 6, 5, 1),    // 3
         Edge::top_right(1, 1, 3, 8),      // 4
         Edge::bottom_right(3, 8, 10, 4),  // 5
         Edge::bottom_left(10, 4, 1, 1),   // 6
      ];

      let polys = vec![
         Poly::new(0, 4, 0),    // 0
         Poly::new(4, 7, 1),    // 1
      ];

      let partials = create_default_vec(65536);

      let partials_min_y = create_default_vec(65536);
      let partials_max_y = create_default_vec(65536);
      let partials_order = create_default_vec(65536);

      ClipRenderer {
         rasterizer: Rasterizer::new(),
         div_per_pixel: 1000,

         edges: edges,
         polys: polys,

         partials: partials,
         partials_end: 0,

         partials_min_y: partials_min_y,
         partials_max_y: partials_max_y,
         partials_order: partials_order,
      }
   }

   fn create_scene(&self) -> Scene {
      let points = vec![];

      let segments = vec![];

      let circles = vec![];

      let edges = vec![];

      let polys = vec![];

      let colors = vec![];

      Scene {
         points: points,
         segments: segments,
         circles: circles,
         edges: edges,
         polys: polys,
         colors: colors,
      }
   }

   fn eval_partials_min_max_y(&mut self) {
      for partial_index in 0..self.partials_end {
         let ref partial = self.partials[partial_index];

         let mut min_y = i64::MAX;
         let mut max_y = i64::MIN;

         let (partial_min_y, partial_max_y) = if partial.edge_type.reversed() {
            (partial.p2.y, partial.p1.y)
         } else {
            (partial.p1.y, partial.p2.y)
         };

         if partial_min_y < min_y  {
            min_y = partial_min_y;
         }

         if partial_max_y > max_y {
            max_y = partial_max_y;
         }

         self.partials_min_y[partial_index] = min_y;
         self.partials_max_y[partial_index] = max_y;
         self.partials_order[partial_index] = partial_index;
      }

      self.sort_partials_order();

      println!("MIN Y {:?}", &self.partials_min_y[..self.partials_end]);
      println!("MAX Y {:?}", &self.partials_max_y[..self.partials_end]);
      println!("ORDER {:?}", &self.partials_order[..self.partials_end]);

      self.iterate_partials();

      panic!("END");
   }

   fn sort_partials_order(&mut self) {
      let partials_order = &mut self.partials_order[..self.partials_end];
      let partials_min_y = &self.partials_min_y;
      let partials_max_y = &self.partials_max_y;

      partials_order.sort_by(|a, b| {
         match partials_min_y[*a].cmp(&partials_min_y[*b]) {
            Ordering::Less => Ordering::Less,
            Ordering::Greater => Ordering::Greater,
            Ordering::Equal => partials_max_y[*a].cmp(&partials_max_y[*b])
         }
      });
   }

   fn iterate_partials(&self) {
      let mut prev_y = i64::MIN;
      for order_index in 0..self.partials_end {
         let partial_index = self.partials_order[order_index];
         let min_y = self.partials_min_y[partial_index];

         println!("I MIN Y {:?} {:?}", partial_index, min_y);

         if min_y != prev_y {
            println!("HOR {:?}", min_y);
            prev_y = min_y;
         }
      }
   }

   fn transfer_partials(&mut self) {
      self.partials_end = 0;

      for poly_index in 0..self.polys.len() {
         let ref poly = self.polys[poly_index];

         for edge_index in poly.start..poly.end {
            let ref edge = self.edges[edge_index];

            self.partials[self.partials_end] = Partial {
               edge_type: edge.edge_type,
               p1: edge.p1,
               p2: edge.p2,
               edge: edge_index,
               poly: poly_index,
            };

            self.partials_end += 1;
         }
      }

      println!("PARTIALS {:?}", &self.partials[..self.partials_end]);
   }
}

impl Renderer for ClipRenderer {
   fn render(&mut self, frame: &mut Frame) {
      frame.clear();

      self.transfer_partials();

      self.eval_partials_min_max_y();

      let scene = self.create_scene();

      self.rasterizer.render(&scene, frame, self.div_per_pixel);
   }
}

fn main() {
   let mut renderer = ClipRenderer::new();

   Application::new()
      .renderer(&mut renderer)
      .title("Clip")
      .run();
}
<|endoftext|>


<commit_before>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    // log!(target: "my_target", Level::Info; key1 = 42, key2 = true; "a {} event", "log");
    (target: $target:expr, $lvl:expr, $($key:tt = $value:expr),+; $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
                $crate::__private_api::Option::Some(&[$((__log_key!($key), &$value)),+])
            );
        }
    });

    // log!(target: "my_target", Level::Info; "a {} event", "log");
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
                $crate::__private_api::Option::None,
            );
        }
    });

    // log!(Level::Info, "a log event")
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+));
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // error!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Error, $($arg)+));

    // error!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Error, $($arg)+))
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // warn!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Warn, $($arg)+));

    // warn!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Warn, $($arg)+))
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successfull connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // info!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Info, $($arg)+));

    // info!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Info, $($arg)+))
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // debug!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Debug, $($arg)+));

    // debug!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Debug, $($arg)+))
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // trace!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Trace, $($arg)+));

    // trace!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Trace, $($arg)+))
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_key {
    // key1 = 42
    ($($args:ident)*) => {
        stringify!($($args)*)
    };
    // "key1" = 42
    ($($args:expr)*) => {
        $($args)*
    };
}
<commit_msg>typo fix<commit_after>// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/// The standard logging macro.
///
/// This macro will generically log with the specified `Level` and `format!`
/// based argument list.
///
/// # Examples
///
/// ```edition2018
/// use log::{log, Level};
///
/// # fn main() {
/// let data = (42, "Forty-two");
/// let private_data = "private";
///
/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
///     data.0, data.1, private_data);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log {
    // log!(target: "my_target", Level::Info; key1 = 42, key2 = true; "a {} event", "log");
    (target: $target:expr, $lvl:expr, $($key:tt = $value:expr),+; $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
                $crate::__private_api::Option::Some(&[$((__log_key!($key), &$value)),+])
            );
        }
    });

    // log!(target: "my_target", Level::Info; "a {} event", "log");
    (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
        let lvl = $lvl;
        if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
            $crate::__private_api_log(
                __log_format_args!($($arg)+),
                lvl,
                &($target, __log_module_path!(), __log_file!(), __log_line!()),
                $crate::__private_api::Option::None,
            );
        }
    });

    // log!(Level::Info, "a log event")
    ($lvl:expr, $($arg:tt)+) => (log!(target: __log_module_path!(), $lvl, $($arg)+));
}

/// Logs a message at the error level.
///
/// # Examples
///
/// ```edition2018
/// use log::error;
///
/// # fn main() {
/// let (err_info, port) = ("No connection", 22);
///
/// error!("Error: {} on port {}", err_info, port);
/// error!(target: "app_events", "App Error: {}, Port: {}", err_info, 22);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! error {
    // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // error!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Error, $($arg)+));

    // error!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Error, $($arg)+))
}

/// Logs a message at the warn level.
///
/// # Examples
///
/// ```edition2018
/// use log::warn;
///
/// # fn main() {
/// let warn_description = "Invalid Input";
///
/// warn!("Warning! {}!", warn_description);
/// warn!(target: "input_events", "App received warning: {}", warn_description);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! warn {
    // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // warn!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Warn, $($arg)+));

    // warn!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Warn, $($arg)+))
}

/// Logs a message at the info level.
///
/// # Examples
///
/// ```edition2018
/// use log::info;
///
/// # fn main() {
/// # struct Connection { port: u32, speed: f32 }
/// let conn_info = Connection { port: 40, speed: 3.20 };
///
/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
/// info!(target: "connection_events", "Successful connection, port: {}, speed: {}",
///       conn_info.port, conn_info.speed);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! info {
    // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // info!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Info, $($arg)+));

    // info!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Info, $($arg)+))
}

/// Logs a message at the debug level.
///
/// # Examples
///
/// ```edition2018
/// use log::debug;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! debug {
    // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // debug!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Debug, $($arg)+));

    // debug!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Debug, $($arg)+))
}

/// Logs a message at the trace level.
///
/// # Examples
///
/// ```edition2018
/// use log::trace;
///
/// # fn main() {
/// # struct Position { x: f32, y: f32 }
/// let pos = Position { x: 3.234, y: -1.223 };
///
/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
/// trace!(target: "app_events", "x is {} and y is {}",
///        if pos.x >= 0.0 { "positive" } else { "negative" },
///        if pos.y >= 0.0 { "positive" } else { "negative" });
/// # }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! trace {
    // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
    // trace!(target: "my_target", "a {} event", "log")
    (target: $target:expr, $($arg:tt)+) => (log!(target: $target, $crate::Level::Trace, $($arg)+));

    // trace!("a {} event", "log")
    ($($arg:tt)+) => (log!($crate::Level::Trace, $($arg)+))
}

/// Determines if a message logged at the specified level in that module will
/// be logged.
///
/// This can be used to avoid expensive computation of log message arguments if
/// the message would be ignored anyway.
///
/// # Examples
///
/// ```edition2018
/// use log::Level::Debug;
/// use log::{debug, log_enabled};
///
/// # fn foo() {
/// if log_enabled!(Debug) {
///     let data = expensive_call();
///     debug!("expensive debug data: {} {}", data.x, data.y);
/// }
/// if log_enabled!(target: "Global", Debug) {
///    let data = expensive_call();
///    debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
/// }
/// # }
/// # struct Data { x: u32, y: u32 }
/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
/// # fn main() {}
/// ```
#[macro_export(local_inner_macros)]
macro_rules! log_enabled {
    (target: $target:expr, $lvl:expr) => {{
        let lvl = $lvl;
        lvl <= $crate::STATIC_MAX_LEVEL
            && lvl <= $crate::max_level()
            && $crate::__private_api_enabled(lvl, $target)
    }};
    ($lvl:expr) => {
        log_enabled!(target: __log_module_path!(), $lvl)
    };
}

// The log macro above cannot invoke format_args directly because it uses
// local_inner_macros. A format_args invocation there would resolve to
// $crate::format_args which does not exist. Instead invoke format_args here
// outside of local_inner_macros so that it resolves (probably) to
// core::format_args or std::format_args. Same for the several macros that
// follow.
//
// This is a workaround until we drop support for pre-1.30 compilers. At that
// point we can remove use of local_inner_macros, use $crate:: when invoking
// local macros, and invoke format_args directly.
#[doc(hidden)]
#[macro_export]
macro_rules! __log_format_args {
    ($($args:tt)*) => {
        format_args!($($args)*)
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_module_path {
    () => {
        module_path!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_file {
    () => {
        file!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_line {
    () => {
        line!()
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __log_key {
    // key1 = 42
    ($($args:ident)*) => {
        stringify!($($args)*)
    };
    // "key1" = 42
    ($($args:expr)*) => {
        $($args)*
    };
}
<|endoftext|>


<commit_before>// Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

use crate::PythonLogLevel;

use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::fs::File;
use std::fs::OpenOptions;
use std::future::Future;
use std::io::{stderr, Stderr, Write};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};

use lazy_static::lazy_static;
use log::{debug, log, set_logger, set_max_level, LevelFilter, Log, Metadata, Record};
use parking_lot::Mutex;
use simplelog::{ConfigBuilder, LevelPadding, WriteLogger};
use tokio::task_local;
use uuid::Uuid;

const TIME_FORMAT_STR: &str = "%H:%M:%S:%3f";

pub type StdioHandler = Box<dyn Fn(&str) -> () + Send>;

lazy_static! {
  pub static ref LOGGER: Logger = Logger::new();
}

pub struct Logger {
  pantsd_log: Mutex<MaybeWriteLogger<File>>,
  stderr_log: Mutex<MaybeWriteLogger<Stderr>>,
  show_rust_3rdparty_logs: AtomicBool,
  stderr_handlers: Mutex<HashMap<Uuid, StdioHandler>>,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      pantsd_log: Mutex::new(MaybeWriteLogger::empty()),
      stderr_log: Mutex::new(MaybeWriteLogger::empty()),
      show_rust_3rdparty_logs: AtomicBool::new(true),
      stderr_handlers: Mutex::new(HashMap::new()),
    }
  }

  pub fn init(max_level: u64, show_rust_3rdparty_logs: bool) {
    let max_python_level: Result<PythonLogLevel, _> = max_level.try_into();
    match max_python_level {
      Ok(python_level) => {
        let level: log::LevelFilter = python_level.into();
        set_max_level(level);
        LOGGER
          .show_rust_3rdparty_logs
          .store(show_rust_3rdparty_logs, Ordering::SeqCst);
        if set_logger(&*LOGGER).is_err() {
          debug!("Logging already initialized.");
        }
      }
      Err(err) => panic!("Unrecognised log level from python: {}: {}", max_level, err),
    };
  }

  fn maybe_increase_global_verbosity(&self, new_level: log::LevelFilter) {
    if log::max_level() < new_level {
      set_max_level(new_level);
    }
  }

  pub fn set_stderr_logger(&self, python_level: u64) -> Result<(), String> {
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .map(|level: PythonLogLevel| {
        self.maybe_increase_global_verbosity(level.into());
        *self.stderr_log.lock() = MaybeWriteLogger::new(
          stderr(),
          level.into(),
          self.show_rust_3rdparty_logs.load(Ordering::SeqCst),
        )
      })
  }

  ///
  /// Set up a file logger which logs at python_level to log_file_path.
  /// Returns the file descriptor of the log file.
  ///
  #[cfg(unix)]
  pub fn set_pantsd_logger(
    &self,
    log_file_path: PathBuf,
    python_level: u64,
  ) -> Result<std::os::unix::io::RawFd, String> {
    use std::os::unix::io::AsRawFd;
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .and_then(|level: PythonLogLevel| {
        {
          // Maybe close open file by dropping the existing logger
          *self.pantsd_log.lock() = MaybeWriteLogger::empty();
        }
        OpenOptions::new()
          .create(true)
          .append(true)
          .open(log_file_path)
          .map(|file| {
            let fd = file.as_raw_fd();
            self.maybe_increase_global_verbosity(level.into());
            *self.pantsd_log.lock() = MaybeWriteLogger::new(
              file,
              level.into(),
              self.show_rust_3rdparty_logs.load(Ordering::SeqCst),
            );
            fd
          })
          .map_err(|err| format!("Error opening pantsd logfile: {}", err))
      })
  }

  /// log_from_python is only used in the Python FFI, which in turn is only called within the
  /// Python `NativeHandler` class. Every logging call from Python should get proxied through this
  /// function, which translates the log message into the Rust log paradigm provided by
  /// the `log` crate.
  pub fn log_from_python(message: &str, python_level: u64, target: &str) -> Result<(), String> {
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .map(|level: PythonLogLevel| {
        log!(target: target, level.into(), "{}", message);
      })
  }

  pub fn register_stderr_handler(&self, callback: StdioHandler) -> Uuid {
    let mut handlers = self.stderr_handlers.lock();
    let unique_id = Uuid::new_v4();
    handlers.insert(unique_id, callback);
    unique_id
  }

  pub fn deregister_stderr_handler(&self, unique_id: Uuid) {
    let mut handlers = self.stderr_handlers.lock();
    handlers.remove(&unique_id);
  }
}

impl Log for Logger {
  fn enabled(&self, _metadata: &Metadata) -> bool {
    // Individual log levels are handled by each sub-logger,
    // And a global filter is applied to set_max_level.
    // No need to filter here.
    true
  }

  fn log(&self, record: &Record) {
    let destination = get_destination();
    match destination {
      Destination::Stderr => {
        let cur_time = chrono::Utc::now().format(TIME_FORMAT_STR);
        let level = record.level();
        let log_string: String = format!("{} [{}] {}", cur_time, level, record.args());

        {
          let handlers_map = self.stderr_handlers.lock();
          if handlers_map.len() == 0 {
            self.stderr_log.lock().log(record);
          } else {
            for callback in handlers_map.values() {
              callback(&log_string);
            }
          }
        }
      }
      Destination::Pantsd => self.pantsd_log.lock().log(record),
    }
  }

  fn flush(&self) {
    self.stderr_log.lock().flush();
    self.pantsd_log.lock().flush();
  }
}

struct MaybeWriteLogger<W: Write + Send + 'static> {
  level: LevelFilter,
  show_rust_3rdparty_logs: bool,
  inner: Option<Box<WriteLogger<W>>>,
}

impl<W: Write + Send + 'static> MaybeWriteLogger<W> {
  pub fn empty() -> MaybeWriteLogger<W> {
    MaybeWriteLogger {
      level: LevelFilter::Off,
      show_rust_3rdparty_logs: true,
      inner: None,
    }
  }

  pub fn new(
    writable: W,
    level: LevelFilter,
    show_rust_3rdparty_logs: bool,
  ) -> MaybeWriteLogger<W> {
    // We initialize the inner WriteLogger with no filters so that we don't
    // have to create a new one every time we change the level of the outer
    // MaybeWriteLogger.

    let config = ConfigBuilder::new()
      .set_time_format_str(TIME_FORMAT_STR)
      .set_thread_level(LevelFilter::Off)
      .set_level_padding(LevelPadding::Off)
      .build();

    MaybeWriteLogger {
      level,
      show_rust_3rdparty_logs,
      inner: Some(WriteLogger::new(LevelFilter::max(), config, writable)),
    }
  }
}

impl<W: Write + Send + 'static> Log for MaybeWriteLogger<W> {
  fn enabled(&self, metadata: &Metadata) -> bool {
    metadata.level() <= self.level
  }

  fn log(&self, record: &Record) {
    if !self.enabled(record.metadata()) {
      return;
    }
    let mut should_log = self.show_rust_3rdparty_logs;
    if !self.show_rust_3rdparty_logs {
      if let Some(ref module_path) = record.module_path() {
        for pants_package in super::pants_packages::PANTS_PACKAGE_NAMES {
          if &module_path.split("::").next().unwrap() == pants_package {
            should_log = true;
            break;
          }
        }
      } else {
        should_log = true;
      }
    }
    if !should_log {
      return;
    }
    if let Some(ref logger) = self.inner {
      logger.log(record);
    }
  }

  fn flush(&self) {
    if let Some(ref logger) = self.inner {
      logger.flush();
    }
  }
}

///
/// Thread- or task-local context for where the Logger should send log statements.
///
/// We do this in a per-thread way because we find that Pants threads generally are either
/// daemon-specific or user-facing. We make sure that every time we spawn a thread on the Python
/// side, we set the thread-local information, and every time we submit a Future to a tokio Runtime
/// on the rust side, we set the task-local information.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub enum Destination {
  Pantsd,
  Stderr,
}

impl TryFrom<&str> for Destination {
  type Error = String;
  fn try_from(dest: &str) -> Result<Self, Self::Error> {
    match dest {
      "pantsd" => Ok(Destination::Pantsd),
      "stderr" => Ok(Destination::Stderr),
      other => Err(format!("Unknown log destination: {:?}", other)),
    }
  }
}

thread_local! {
  static THREAD_DESTINATION: RefCell<Destination> = RefCell::new(Destination::Stderr)
}

task_local! {
  static TASK_DESTINATION: Destination;
}

///
/// Set the current log destination for a Thread, but _not_ for a Task. Tasks must always be spawned
/// by callers using the `scope_task_destination` helper (generally via task_executor::Executor.)
///
pub fn set_thread_destination(destination: Destination) {
  THREAD_DESTINATION.with(|thread_destination| {
    *thread_destination.borrow_mut() = destination;
  })
}

///
/// Propagate the current log destination to a Future representing a newly spawned Task. Usage of
/// this method should mostly be contained to task_executor::Executor.
///
pub async fn scope_task_destination<F>(destination: Destination, f: F) -> F::Output
where
  F: Future,
{
  TASK_DESTINATION.scope(destination, f).await
}

///
/// Get the current log destination, from either a Task or a Thread.
///
/// TODO: Having this return an Option and tracking down all cases where it has defaulted would be
/// good.
///
pub fn get_destination() -> Destination {
  if let Ok(destination) = TASK_DESTINATION.try_with(|destination| *destination) {
    destination
  } else {
    THREAD_DESTINATION.with(|destination| *destination.borrow())
  }
}
<commit_msg>Log timestamps should be in the local time zone (#9927)<commit_after>// Copyright 2018 Pants project contributors (see CONTRIBUTORS.md).
// Licensed under the Apache License, Version 2.0 (see LICENSE).

use crate::PythonLogLevel;

use std::cell::RefCell;
use std::collections::HashMap;
use std::convert::{TryFrom, TryInto};
use std::fs::File;
use std::fs::OpenOptions;
use std::future::Future;
use std::io::{stderr, Stderr, Write};
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};

use lazy_static::lazy_static;
use log::{debug, log, set_logger, set_max_level, LevelFilter, Log, Metadata, Record};
use parking_lot::Mutex;
use simplelog::{ConfigBuilder, LevelPadding, WriteLogger};
use tokio::task_local;
use uuid::Uuid;

const TIME_FORMAT_STR: &str = "%H:%M:%S";

pub type StdioHandler = Box<dyn Fn(&str) -> () + Send>;

lazy_static! {
  pub static ref LOGGER: Logger = Logger::new();
}

pub struct Logger {
  pantsd_log: Mutex<MaybeWriteLogger<File>>,
  stderr_log: Mutex<MaybeWriteLogger<Stderr>>,
  show_rust_3rdparty_logs: AtomicBool,
  stderr_handlers: Mutex<HashMap<Uuid, StdioHandler>>,
}

impl Logger {
  pub fn new() -> Logger {
    Logger {
      pantsd_log: Mutex::new(MaybeWriteLogger::empty()),
      stderr_log: Mutex::new(MaybeWriteLogger::empty()),
      show_rust_3rdparty_logs: AtomicBool::new(true),
      stderr_handlers: Mutex::new(HashMap::new()),
    }
  }

  pub fn init(max_level: u64, show_rust_3rdparty_logs: bool) {
    let max_python_level: Result<PythonLogLevel, _> = max_level.try_into();
    match max_python_level {
      Ok(python_level) => {
        let level: log::LevelFilter = python_level.into();
        set_max_level(level);
        LOGGER
          .show_rust_3rdparty_logs
          .store(show_rust_3rdparty_logs, Ordering::SeqCst);
        if set_logger(&*LOGGER).is_err() {
          debug!("Logging already initialized.");
        }
      }
      Err(err) => panic!("Unrecognised log level from python: {}: {}", max_level, err),
    };
  }

  fn maybe_increase_global_verbosity(&self, new_level: log::LevelFilter) {
    if log::max_level() < new_level {
      set_max_level(new_level);
    }
  }

  pub fn set_stderr_logger(&self, python_level: u64) -> Result<(), String> {
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .map(|level: PythonLogLevel| {
        self.maybe_increase_global_verbosity(level.into());
        *self.stderr_log.lock() = MaybeWriteLogger::new(
          stderr(),
          level.into(),
          self.show_rust_3rdparty_logs.load(Ordering::SeqCst),
        )
      })
  }

  ///
  /// Set up a file logger which logs at python_level to log_file_path.
  /// Returns the file descriptor of the log file.
  ///
  #[cfg(unix)]
  pub fn set_pantsd_logger(
    &self,
    log_file_path: PathBuf,
    python_level: u64,
  ) -> Result<std::os::unix::io::RawFd, String> {
    use std::os::unix::io::AsRawFd;
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .and_then(|level: PythonLogLevel| {
        {
          // Maybe close open file by dropping the existing logger
          *self.pantsd_log.lock() = MaybeWriteLogger::empty();
        }
        OpenOptions::new()
          .create(true)
          .append(true)
          .open(log_file_path)
          .map(|file| {
            let fd = file.as_raw_fd();
            self.maybe_increase_global_verbosity(level.into());
            *self.pantsd_log.lock() = MaybeWriteLogger::new(
              file,
              level.into(),
              self.show_rust_3rdparty_logs.load(Ordering::SeqCst),
            );
            fd
          })
          .map_err(|err| format!("Error opening pantsd logfile: {}", err))
      })
  }

  /// log_from_python is only used in the Python FFI, which in turn is only called within the
  /// Python `NativeHandler` class. Every logging call from Python should get proxied through this
  /// function, which translates the log message into the Rust log paradigm provided by
  /// the `log` crate.
  pub fn log_from_python(message: &str, python_level: u64, target: &str) -> Result<(), String> {
    python_level
      .try_into()
      .map_err(|err| format!("{}", err))
      .map(|level: PythonLogLevel| {
        log!(target: target, level.into(), "{}", message);
      })
  }

  pub fn register_stderr_handler(&self, callback: StdioHandler) -> Uuid {
    let mut handlers = self.stderr_handlers.lock();
    let unique_id = Uuid::new_v4();
    handlers.insert(unique_id, callback);
    unique_id
  }

  pub fn deregister_stderr_handler(&self, unique_id: Uuid) {
    let mut handlers = self.stderr_handlers.lock();
    handlers.remove(&unique_id);
  }
}

impl Log for Logger {
  fn enabled(&self, _metadata: &Metadata) -> bool {
    // Individual log levels are handled by each sub-logger,
    // And a global filter is applied to set_max_level.
    // No need to filter here.
    true
  }

  fn log(&self, record: &Record) {
    use chrono::Timelike;
    let destination = get_destination();
    match destination {
      Destination::Stderr => {
        let cur_date = chrono::Local::now();
        let time_str = format!(
          "{}.{:02}",
          cur_date.format(TIME_FORMAT_STR),
          cur_date.time().nanosecond() / 10_000_000 // two decimal places of precision
        );
        let level = record.level();
        let log_string: String = format!("{} [{}] {}", time_str, level, record.args());

        {
          let handlers_map = self.stderr_handlers.lock();
          if handlers_map.len() == 0 {
            self.stderr_log.lock().log(record);
          } else {
            for callback in handlers_map.values() {
              callback(&log_string);
            }
          }
        }
      }
      Destination::Pantsd => self.pantsd_log.lock().log(record),
    }
  }

  fn flush(&self) {
    self.stderr_log.lock().flush();
    self.pantsd_log.lock().flush();
  }
}

struct MaybeWriteLogger<W: Write + Send + 'static> {
  level: LevelFilter,
  show_rust_3rdparty_logs: bool,
  inner: Option<Box<WriteLogger<W>>>,
}

impl<W: Write + Send + 'static> MaybeWriteLogger<W> {
  pub fn empty() -> MaybeWriteLogger<W> {
    MaybeWriteLogger {
      level: LevelFilter::Off,
      show_rust_3rdparty_logs: true,
      inner: None,
    }
  }

  pub fn new(
    writable: W,
    level: LevelFilter,
    show_rust_3rdparty_logs: bool,
  ) -> MaybeWriteLogger<W> {
    // We initialize the inner WriteLogger with no filters so that we don't
    // have to create a new one every time we change the level of the outer
    // MaybeWriteLogger.

    let config = ConfigBuilder::new()
      .set_time_format_str(TIME_FORMAT_STR)
      .set_thread_level(LevelFilter::Off)
      .set_level_padding(LevelPadding::Off)
      .build();

    MaybeWriteLogger {
      level,
      show_rust_3rdparty_logs,
      inner: Some(WriteLogger::new(LevelFilter::max(), config, writable)),
    }
  }
}

impl<W: Write + Send + 'static> Log for MaybeWriteLogger<W> {
  fn enabled(&self, metadata: &Metadata) -> bool {
    metadata.level() <= self.level
  }

  fn log(&self, record: &Record) {
    if !self.enabled(record.metadata()) {
      return;
    }
    let mut should_log = self.show_rust_3rdparty_logs;
    if !self.show_rust_3rdparty_logs {
      if let Some(ref module_path) = record.module_path() {
        for pants_package in super::pants_packages::PANTS_PACKAGE_NAMES {
          if &module_path.split("::").next().unwrap() == pants_package {
            should_log = true;
            break;
          }
        }
      } else {
        should_log = true;
      }
    }
    if !should_log {
      return;
    }
    if let Some(ref logger) = self.inner {
      logger.log(record);
    }
  }

  fn flush(&self) {
    if let Some(ref logger) = self.inner {
      logger.flush();
    }
  }
}

///
/// Thread- or task-local context for where the Logger should send log statements.
///
/// We do this in a per-thread way because we find that Pants threads generally are either
/// daemon-specific or user-facing. We make sure that every time we spawn a thread on the Python
/// side, we set the thread-local information, and every time we submit a Future to a tokio Runtime
/// on the rust side, we set the task-local information.
///
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[repr(C)]
pub enum Destination {
  Pantsd,
  Stderr,
}

impl TryFrom<&str> for Destination {
  type Error = String;
  fn try_from(dest: &str) -> Result<Self, Self::Error> {
    match dest {
      "pantsd" => Ok(Destination::Pantsd),
      "stderr" => Ok(Destination::Stderr),
      other => Err(format!("Unknown log destination: {:?}", other)),
    }
  }
}

thread_local! {
  static THREAD_DESTINATION: RefCell<Destination> = RefCell::new(Destination::Stderr)
}

task_local! {
  static TASK_DESTINATION: Destination;
}

///
/// Set the current log destination for a Thread, but _not_ for a Task. Tasks must always be spawned
/// by callers using the `scope_task_destination` helper (generally via task_executor::Executor.)
///
pub fn set_thread_destination(destination: Destination) {
  THREAD_DESTINATION.with(|thread_destination| {
    *thread_destination.borrow_mut() = destination;
  })
}

///
/// Propagate the current log destination to a Future representing a newly spawned Task. Usage of
/// this method should mostly be contained to task_executor::Executor.
///
pub async fn scope_task_destination<F>(destination: Destination, f: F) -> F::Output
where
  F: Future,
{
  TASK_DESTINATION.scope(destination, f).await
}

///
/// Get the current log destination, from either a Task or a Thread.
///
/// TODO: Having this return an Option and tracking down all cases where it has defaulted would be
/// good.
///
pub fn get_destination() -> Destination {
  if let Ok(destination) = TASK_DESTINATION.try_with(|destination| *destination) {
    destination
  } else {
    THREAD_DESTINATION.with(|destination| *destination.borrow())
  }
}
<|endoftext|>


<commit_before>#[macro_export]
macro_rules! gc_ref_type {
    (pub struct $ref_type: ident / $storage_type: ident <'a> {
        $($field_name: ident / $field_setter_name: ident : $field_type: ty),*
    }) => {
        struct $storage_type <'a> {
            $($field_name: <$field_type as HeapInline<'a>>::Storage,)*
        }

        unsafe impl<'a> $crate::Mark<'a> for $crate::Markable<$storage_type<'a>> {
            unsafe fn mark(ptr: *mut $crate::Markable<$storage_type<'a>>) {
                if !ptr.is_null() && !(*ptr).marked {
                    (*ptr).marked = true;
                    $(
                        $crate::Mark::mark(
                            &mut (*ptr).value.$field_name
                                as *mut <$field_type as $crate::HeapInline<'a>>::Storage);
                    )*
                }
            }
        }

        #[allow(raw_pointer_derive)]
        #[derive(Clone, Debug, PartialEq)]
        pub struct $ref_type<'a>($crate::PinnedRef<'a, $crate::Markable<$storage_type<'a>>>);

        impl<'a> $ref_type<'a> {
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.ptr;
                    unsafe {
                        <$field_type as $crate::HeapInline<'a>>::from_heap(
                            &*self.0.heap,
                            &(*ptr).value.$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.ptr;
                    unsafe {
                        (*ptr).value.$field_name =
                            <$field_type as $crate::HeapInline<'a>>::to_heap(v);
                    }
                }
            )*
        }

        unsafe impl<'a> $crate::HeapInline<'a> for $ref_type<'a> {
            type Storage = *mut $crate::Markable<$storage_type<'a>>;

            fn to_heap(self) -> Self::Storage {
                self.0.ptr
            }

            unsafe fn from_heap(heap: &$crate::Heap<'a>, v: &Self::Storage) -> Self {
                $ref_type($crate::PinnedRef::new(heap, *v))
            }
        }

        impl<'a> $crate::GCRef for $ref_type<'a> {
            #[cfg(test)]
            fn address(&self) -> usize {
                unsafe { ::std::mem::transmute(self.0.ptr) }
            }
        }
    }
}

<commit_msg>Add another `$crate::`.<commit_after>#[macro_export]
macro_rules! gc_ref_type {
    (pub struct $ref_type: ident / $storage_type: ident <'a> {
        $($field_name: ident / $field_setter_name: ident : $field_type: ty),*
    }) => {
        struct $storage_type <'a> {
            $($field_name: <$field_type as $crate::HeapInline<'a>>::Storage,)*
        }

        unsafe impl<'a> $crate::Mark<'a> for $crate::Markable<$storage_type<'a>> {
            unsafe fn mark(ptr: *mut $crate::Markable<$storage_type<'a>>) {
                if !ptr.is_null() && !(*ptr).marked {
                    (*ptr).marked = true;
                    $(
                        $crate::Mark::mark(
                            &mut (*ptr).value.$field_name
                                as *mut <$field_type as $crate::HeapInline<'a>>::Storage);
                    )*
                }
            }
        }

        #[allow(raw_pointer_derive)]
        #[derive(Clone, Debug, PartialEq)]
        pub struct $ref_type<'a>($crate::PinnedRef<'a, $crate::Markable<$storage_type<'a>>>);

        impl<'a> $ref_type<'a> {
            $(
                pub fn $field_name(&self) -> $field_type {
                    let ptr = self.0.ptr;
                    unsafe {
                        <$field_type as $crate::HeapInline<'a>>::from_heap(
                            &*self.0.heap,
                            &(*ptr).value.$field_name)
                    }
                }

                pub fn $field_setter_name(&self, v: $field_type) {
                    let ptr = self.0.ptr;
                    unsafe {
                        (*ptr).value.$field_name =
                            <$field_type as $crate::HeapInline<'a>>::to_heap(v);
                    }
                }
            )*
        }

        unsafe impl<'a> $crate::HeapInline<'a> for $ref_type<'a> {
            type Storage = *mut $crate::Markable<$storage_type<'a>>;

            fn to_heap(self) -> Self::Storage {
                self.0.ptr
            }

            unsafe fn from_heap(heap: &$crate::Heap<'a>, v: &Self::Storage) -> Self {
                $ref_type($crate::PinnedRef::new(heap, *v))
            }
        }

        impl<'a> $crate::GCRef for $ref_type<'a> {
            #[cfg(test)]
            fn address(&self) -> usize {
                unsafe { ::std::mem::transmute(self.0.ptr) }
            }
        }
    }
}
<|endoftext|>