<commit_before>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::cell::RefCell;
use std::ops::{Range, Index};
use std::net::TcpStream;
use std::io::{Cursor, Read, Write};
use std::path::Path;
use std::vec::Vec;
use std::collections::HashMap;

use num::pow;
use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
    pub aps: PayloadAPS<'a>,
    pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
    pub alert: PayloadAPSAlert<'a>,
    pub badge: Option<i32>,
    pub sound: Option<&'a str>,
    pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
    Plain(&'a str),
    Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	match *self {
	    Payload{ref aps, ref info} => {
		if let Some(ref map) = *info {
	    	    encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
			try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
			let mut index = 1usize;
			for (key, val) in map.iter() {
			    try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
			    index = index + 1;
			}
			Ok(())
	    	    })
		}
		else {
	    	    encoder.emit_struct("Payload", 1, |encoder| {
			try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
			Ok(())
	    	    })
		}
	    }
	}
    }
}

impl<'a> Encodable for PayloadAPS<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
	    PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
	        let mut count = 1;
	        if badge.is_some() { count = count + 1; }
	        if sound.is_some() { count = count + 1; }
	        if content_available.is_some() { count = count + 1; }

	        let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
	            try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
	            index = index + 1;
	            if badge.is_some() {
		        try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            if sound.is_some() {
		        try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            if content_available.is_some() {
		        try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            Ok(())
    	        })
            }
        }
    }
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	match *self {
	    PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
	    },
	    PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
		    try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
		    try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
		    Ok(())
		})
	    }
	}
    }
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
    let mut total = 0u32;
    let mut n = hex.to_string().len();

    for c in hex.chars() {
        n = n - 1;
	match c {
	    '0'...'9' => {
		total += pow(16, n) * ((c as u32) - ('0' as u32));
	    },
	    'a'...'f' => {
		total += pow(16, n) * ((c as u32) - ('a' as u32) + 10);
	    },
	    _ => {
	    }
	}
    }

    return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
    let mut device_token_bytes: Vec<u8> = Vec::new();
    for i in 0..8 {
	let string = device_token.to_string();
	let range = Range{start:i*8, end:i*8+8};
	let sub_str = string.index(range);

	let sub_str_num = hex_to_int(sub_str);
	let mut sub_str_bytes = vec![];
	let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

        for s in sub_str_bytes.iter() {
            device_token_bytes.push(*s);
        }
    }

    return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
    let mut token = "".to_string();
    for i in 0..8 {
	let range = Range{start:i*4, end:i*4+4};
	let sub_slice = binary.index(range);

	let mut rdr = Cursor::new(sub_slice.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	token = format!("{}{:x}", token, num);
    }
    return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
    let mut rdr = Cursor::new(binary.to_vec());
    let num = rdr.read_u32::<BigEndian>().unwrap();

    return num;
}

pub struct APNS<'a> {
    pub sandbox: bool,
    pub certificate: &'a Path,
    pub private_key: &'a Path,
    pub ca_certificate: &'a Path,
    pub ssl_stream: RefCell<Option<SslStream<TcpStream>>>
}

impl<'a> APNS<'a> {
    pub fn new(sandbox: bool, cert_file: &'a Path, private_key_file: &'a Path, ca_file: &'a Path) -> APNS<'a> {
	APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file, ssl_stream: RefCell::new(None)}
    }

    #[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
	let apns_feedback_production = "feedback.push.apple.com:2196";
	let apns_feedback_development = "feedback.sandbox.push.apple.com:2196";

	let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
	let mut stream = try!(get_ssl_stream(apns_feedback_url, self.certificate, self.private_key, self.ca_certificate));

	let mut tokens: Vec<(u32, String)> = Vec::new();
        let mut read_buffer = [0u8; 38];
        loop {
            match stream.read(&mut read_buffer) {
                Ok(size) => {
                    if size != 38 {
                        break;
                    }
                },
                Err(..) => {
                    /*				return Result::Err(SslError::StreamError(error));*/
                    break;
                }
            }

	    let time_range = Range{start:0, end:4};
	    let time_slice = read_buffer.index(time_range);
	    let time = convert_to_timestamp(time_slice);

	    let token_range = Range{start:6, end:38};
	    let token_slice = read_buffer.index(token_range);
            let token = convert_to_token(token_slice);

	    tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

    #[allow(dead_code)]
    pub fn send_payload(&self, payload: Payload, device_token: &str) {
        let notification_bytes = get_notification_bytes(payload, device_token);

	let mut should_retry = true;
        let mut borrow_ssl_stream = self.ssl_stream.borrow_mut();

        if let Some(ssls) = borrow_ssl_stream.as_mut() {
            if let Ok(..) = ssls.write_all(&notification_bytes) {
                if let Ok(..) = ssls.flush() {
                    should_retry = false;
                }
            }
            /*
            // Response error code
            let mut read_buffer = [0u8; 6];
            match ssls.read(&mut read_buffer) {
            Ok(size) => {
            if size == 6 {
            for c in read_buffer.iter() {
            print!("{}", c);
        }
            println!("");
        }
            println!("ssl_stream read size {}", size);
        },
            Err(error) => {
            println!("ssl_stream read error {:?}", error);
        }
        }
             */
        }

        if should_retry {
            // try to recreate ssl stream

            println!("try to recreate ssl stream");

            let apns_url_production = "gateway.push.apple.com:2195";
            let apns_url_development = "gateway.sandbox.push.apple.com:2195";

            let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

            let ssl_result = get_ssl_stream(apns_url, self.certificate, self.private_key, self.ca_certificate);
            *borrow_ssl_stream = match ssl_result {
                Ok(mut ssls) => {
                if let Err(error) = ssls.write_all(&notification_bytes) {
                    println!("ssl_stream write error {:?}", error);
                }
                let _ = ssls.flush();
                Some(ssls)
            },
            Err(error) => {
            println!("failed to get_ssl_stream error {:?}", error);
            None
        }
    };
}
	}
}

fn get_notification_bytes(payload: Payload, device_token: &str) -> Vec<u8> {
    let payload_str = match json::encode(&payload) {
        Ok(json_str) => { json_str.to_string() }
        Err(error) => {
            println!("json encode error {:?}", error);
            return vec![];
        }
    };

    let payload_bytes = payload_str.into_bytes();
    let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

    let mut notification_buffer: Vec<u8> = vec![];
    let mut message_buffer: Vec<u8> = vec![];

    // Device token
    let mut device_token_length = vec![];
    let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

    message_buffer.push(1u8);
    for s in device_token_length.iter() {
        message_buffer.push(*s);
    }
    for s in device_token_bytes.iter() {
        message_buffer.push(*s);
    }

    // Payload
    let mut payload_length = vec![];
    let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

    message_buffer.push(2u8);
    for s in payload_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_bytes.iter() {
        message_buffer.push(*s);
    }

    // Notification identifier
    let payload_id = rand::thread_rng().gen();
    let mut payload_id_be = vec![];
    let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

    let mut payload_id_length = vec![];
    let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

    message_buffer.push(3u8);
    for s in payload_id_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_id_be.iter() {
        message_buffer.push(*s);
    }

    //	Expiration date
    let time = time::now().to_timespec().sec + 86400;	// expired after one day
    let mut exp_date_be = vec![];
    let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

    let mut exp_date_length = vec![];
    let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

    message_buffer.push(4u8);
    for s in exp_date_length.iter() {
        message_buffer.push(*s);
    }
    for s in exp_date_be.iter() {
        message_buffer.push(*s);
    }

    // Priority
    let mut priority_length = vec![];
    let _ = priority_length.write_u16::<BigEndian>(1u16);

    message_buffer.push(5u8);
    for s in priority_length.iter() {
        message_buffer.push(*s);
    }
    message_buffer.push(10u8);

    let mut message_buffer_length = vec![];
    let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

    let command = 2u8;
    notification_buffer.push(command);
    for s in message_buffer_length.iter() {
        notification_buffer.push(*s);
    }
    for s in message_buffer.iter() {
        notification_buffer.push(*s);
    }

    return notification_buffer;
}

fn get_ssl_stream(url: &str, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
	let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

	if let Err(error) = context.set_CA_file(ca_file) {
		println!("set_CA_file error {:?}", error);
	}
	if let Err(error) = context.set_certificate_file(cert_file, openssl::x509::X509FileType::PEM) {
		println!("set_certificate_file error {:?}", error);
	}
	if let Err(error) = context.set_private_key_file(private_key_file, openssl::x509::X509FileType::PEM) {
		println!("set_private_key_file error {:?}", error);
	}

	let tcp_conn = match TcpStream::connect(url) {
		Ok(conn) => { conn },
		Err(error) => {
            println!("tcp_stream connect error {:?}", error);
			return Result::Err(SslError::StreamError(error));
		}
	};

	return SslStream::new(&context, tcp_conn);
}

<commit_msg>remove ssl_stream from APNS and create a new ssl_stream each time before sending notification<commit_after>use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};

use rustc_serialize::Encodable;
use rustc_serialize::Encoder;
use rustc_serialize::json;

use openssl;
use openssl::ssl;
use openssl::ssl::SslStream;
use openssl::ssl::error::SslError;

use std::ops::{Range, Index};
use std::net::TcpStream;
use std::io::{Cursor, Read, Write};
use std::path::Path;
use std::vec::Vec;
use std::collections::HashMap;

use num::pow;
use rand::{self, Rng};
use time;

#[derive(Debug)]
pub struct Payload<'a> {
    pub aps: PayloadAPS<'a>,
    pub info: Option<HashMap<&'a str, &'a str>>
}

#[derive(Debug)]
pub struct PayloadAPS<'a> {
    pub alert: PayloadAPSAlert<'a>,
    pub badge: Option<i32>,
    pub sound: Option<&'a str>,
    pub content_available: Option<i32>
}

#[derive(Debug)]
pub enum PayloadAPSAlert<'a> {
    Plain(&'a str),
    Localized(&'a str, Vec<&'a str>)
}

impl<'a> Encodable for Payload<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	match *self {
	    Payload{ref aps, ref info} => {
		if let Some(ref map) = *info {
	    	    encoder.emit_struct("Payload", 1 + map.len(), |encoder| {
			try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
			let mut index = 1usize;
			for (key, val) in map.iter() {
			    try!(encoder.emit_struct_field(key, index, |encoder| val.encode(encoder)));
			    index = index + 1;
			}
			Ok(())
	    	    })
		}
		else {
	    	    encoder.emit_struct("Payload", 1, |encoder| {
			try!(encoder.emit_struct_field( "aps", 0usize, |encoder| aps.encode(encoder)));
			Ok(())
	    	    })
		}
	    }
	}
    }
}

impl<'a> Encodable for PayloadAPS<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
        match *self {
	    PayloadAPS{ref alert, ref badge, ref sound, ref content_available} => {
	        let mut count = 1;
	        if badge.is_some() { count = count + 1; }
	        if sound.is_some() { count = count + 1; }
	        if content_available.is_some() { count = count + 1; }

	        let mut index = 0usize;
    	        encoder.emit_struct("PayloadAPS", count, |encoder| {
	            try!(encoder.emit_struct_field( "alert", index, |encoder| alert.encode(encoder)));
	            index = index + 1;
	            if badge.is_some() {
		        try!(encoder.emit_struct_field( "badge", index, |encoder| badge.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            if sound.is_some() {
		        try!(encoder.emit_struct_field( "sound", index, |encoder| sound.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            if content_available.is_some() {
		        try!(encoder.emit_struct_field( "content-available", index, |encoder| content_available.unwrap().encode(encoder)));
		        index = index + 1;
	            }
	            Ok(())
    	        })
            }
        }
    }
}

impl<'a> Encodable for PayloadAPSAlert<'a> {
    fn encode<S: Encoder>(&self, encoder: &mut S) -> Result<(), S::Error> {
	match *self {
	    PayloadAPSAlert::Plain(ref str) => {
    	        encoder.emit_str(str)
	    },
	    PayloadAPSAlert::Localized(ref key, ref args) => {
    	        encoder.emit_struct("PayloadAPSAlert", 2, |encoder| {
		    try!(encoder.emit_struct_field( "loc-key", 0usize, |encoder| key.encode(encoder)));
		    try!(encoder.emit_struct_field( "loc-args", 1usize, |encoder| args.encode(encoder)));
		    Ok(())
		})
	    }
	}
    }
}

#[allow(dead_code)]
fn hex_to_int(hex: &str) -> u32 {
    let mut total = 0u32;
    let mut n = hex.to_string().len();

    for c in hex.chars() {
        n = n - 1;
	match c {
	    '0'...'9' => {
		total += pow(16, n) * ((c as u32) - ('0' as u32));
	    },
	    'a'...'f' => {
		total += pow(16, n) * ((c as u32) - ('a' as u32) + 10);
	    },
	    _ => {
	    }
	}
    }

    return total;
}

#[allow(dead_code)]
fn convert_to_binary(device_token: &str) -> Vec<u8> {
    let mut device_token_bytes: Vec<u8> = Vec::new();
    for i in 0..8 {
	let string = device_token.to_string();
	let range = Range{start:i*8, end:i*8+8};
	let sub_str = string.index(range);

	let sub_str_num = hex_to_int(sub_str);
	let mut sub_str_bytes = vec![];
	let _ = sub_str_bytes.write_u32::<BigEndian>(sub_str_num);

        for s in sub_str_bytes.iter() {
            device_token_bytes.push(*s);
        }
    }

    return device_token_bytes;
}

#[allow(dead_code)]
pub fn convert_to_token(binary: &[u8]) -> String {
    let mut token = "".to_string();
    for i in 0..8 {
	let range = Range{start:i*4, end:i*4+4};
	let sub_slice = binary.index(range);

	let mut rdr = Cursor::new(sub_slice.to_vec());
	let num = rdr.read_u32::<BigEndian>().unwrap();

	token = format!("{}{:x}", token, num);
    }
    return token;
}

#[allow(dead_code)]
pub fn convert_to_timestamp(binary: &[u8]) -> u32 {
    let mut rdr = Cursor::new(binary.to_vec());
    let num = rdr.read_u32::<BigEndian>().unwrap();

    return num;
}

pub struct APNS<'a> {
    pub sandbox: bool,
    pub certificate: &'a Path,
    pub private_key: &'a Path,
    pub ca_certificate: &'a Path,
}

impl<'a> APNS<'a> {
    pub fn new(sandbox: bool, cert_file: &'a Path, private_key_file: &'a Path, ca_file: &'a Path) -> APNS<'a> {
	APNS{sandbox: sandbox, certificate: cert_file, private_key: private_key_file, ca_certificate: ca_file}
    }

    #[allow(dead_code)]
    pub fn get_feedback(&self) -> Result<Vec<(u32, String)>, SslError> {
	let apns_feedback_production = "feedback.push.apple.com:2196";
	let apns_feedback_development = "feedback.sandbox.push.apple.com:2196";

	let apns_feedback_url = if self.sandbox { apns_feedback_development } else { apns_feedback_production };
	let mut stream = try!(get_ssl_stream(apns_feedback_url, self.certificate, self.private_key, self.ca_certificate));

	let mut tokens: Vec<(u32, String)> = Vec::new();
        let mut read_buffer = [0u8; 38];
        loop {
            match stream.read(&mut read_buffer) {
                Ok(size) => {
                    if size != 38 {
                        break;
                    }
                },
                Err(..) => {
                    /*				return Result::Err(SslError::StreamError(error));*/
                    break;
                }
            }

	    let time_range = Range{start:0, end:4};
	    let time_slice = read_buffer.index(time_range);
	    let time = convert_to_timestamp(time_slice);

	    let token_range = Range{start:6, end:38};
	    let token_slice = read_buffer.index(token_range);
            let token = convert_to_token(token_slice);

	    tokens.push((time, token));
        }

        return Result::Ok(tokens);
    }

    #[allow(dead_code)]
    pub fn send_payload(&self, payload: Payload, device_token: &str) {
        let notification_bytes = get_notification_bytes(payload, device_token);

        let apns_url_production = "gateway.push.apple.com:2195";
        let apns_url_development = "gateway.sandbox.push.apple.com:2195";

        let apns_url = if self.sandbox { apns_url_development } else { apns_url_production };

        let ssl_result = get_ssl_stream(apns_url, self.certificate, self.private_key, self.ca_certificate);
        match ssl_result {
            Ok(mut ssls) => {
                if let Err(error) = ssls.write_all(&notification_bytes) {
                    println!("ssl_stream write error {:?}", error);
                }
                else if ssls.pending() == 6 {
                    let mut read_buffer = [0u8; 6];
                    match ssls.read(&mut read_buffer) {
                        Ok(size) => {
                            for c in read_buffer.iter() {
                                print!("{}", c);
                            }
                            println!("ssl_stream read size {:?}", size);
                        }
                        Err(error) => {
                            println!("ssl_stream read error {:?}", error);
                        }
                    }
                }
                // let _ = ssls.flush();
            },
            Err(error) => {
                println!("failed to get_ssl_stream error {:?}", error);
            }
        };
    }
}

fn get_notification_bytes(payload: Payload, device_token: &str) -> Vec<u8> {
    let payload_str = match json::encode(&payload) {
        Ok(json_str) => { json_str.to_string() }
        Err(error) => {
            println!("json encode error {:?}", error);
            return vec![];
        }
    };

    let payload_bytes = payload_str.into_bytes();
    let device_token_bytes: Vec<u8> = convert_to_binary(device_token);

    let mut notification_buffer: Vec<u8> = vec![];
    let mut message_buffer: Vec<u8> = vec![];

    // Device token
    let mut device_token_length = vec![];
    let _ = device_token_length.write_u16::<BigEndian>(device_token_bytes.len() as u16);

    message_buffer.push(1u8);
    for s in device_token_length.iter() {
        message_buffer.push(*s);
    }
    for s in device_token_bytes.iter() {
        message_buffer.push(*s);
    }

    // Payload
    let mut payload_length = vec![];
    let _ = payload_length.write_u16::<BigEndian>(payload_bytes.len() as u16);

    message_buffer.push(2u8);
    for s in payload_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_bytes.iter() {
        message_buffer.push(*s);
    }

    // Notification identifier
    let payload_id = rand::thread_rng().gen();
    let mut payload_id_be = vec![];
    let _ = payload_id_be.write_u32::<BigEndian>(payload_id);

    let mut payload_id_length = vec![];
    let _ = payload_id_length.write_u16::<BigEndian>(payload_id_be.len() as u16);

    message_buffer.push(3u8);
    for s in payload_id_length.iter() {
        message_buffer.push(*s);
    }
    for s in payload_id_be.iter() {
        message_buffer.push(*s);
    }

    //	Expiration date
    let time = time::now().to_timespec().sec + 86400;	// expired after one day
    let mut exp_date_be = vec![];
    let _ = exp_date_be.write_u32::<BigEndian>(time as u32);

    let mut exp_date_length = vec![];
    let _ = exp_date_length.write_u16::<BigEndian>(exp_date_be.len() as u16);

    message_buffer.push(4u8);
    for s in exp_date_length.iter() {
        message_buffer.push(*s);
    }
    for s in exp_date_be.iter() {
        message_buffer.push(*s);
    }

    // Priority
    let mut priority_length = vec![];
    let _ = priority_length.write_u16::<BigEndian>(1u16);

    message_buffer.push(5u8);
    for s in priority_length.iter() {
        message_buffer.push(*s);
    }
    message_buffer.push(10u8);

    let mut message_buffer_length = vec![];
    let _ = message_buffer_length.write_u32::<BigEndian>(message_buffer.len() as u32);

    let command = 2u8;
    notification_buffer.push(command);
    for s in message_buffer_length.iter() {
        notification_buffer.push(*s);
    }
    for s in message_buffer.iter() {
        notification_buffer.push(*s);
    }

    return notification_buffer;
}

fn get_ssl_stream(url: &str, cert_file: &Path, private_key_file: &Path, ca_file: &Path) -> Result<SslStream<TcpStream>, SslError> {
    let mut context = try!(ssl::SslContext::new(ssl::SslMethod::Sslv23));

    if let Err(error) = context.set_CA_file(ca_file) {
	println!("set_CA_file error {:?}", error);
    }
    if let Err(error) = context.set_certificate_file(cert_file, openssl::x509::X509FileType::PEM) {
	println!("set_certificate_file error {:?}", error);
    }
    if let Err(error) = context.set_private_key_file(private_key_file, openssl::x509::X509FileType::PEM) {
	println!("set_private_key_file error {:?}", error);
    }

    let tcp_conn = match TcpStream::connect(url) {
	Ok(conn) => { conn },
	Err(error) => {
            println!("tcp_stream connect error {:?}", error);
	    return Result::Err(SslError::StreamError(error));
	}
    };

    return SslStream::new(&context, tcp_conn);
}

<|endoftext|>


<commit_before>use std::collections::HashSet;

use clap::{App, SubCommand, Arg, ArgMatches};
use futures::prelude::*;
use futures::stream;

use attaca::marshal::{self, Object, DataObject};
use attaca::Repository;

use errors::*;

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Depth {
    Commit,
    Subtree,
    Data,
}

pub fn command() -> App<'static, 'static> {
    SubCommand::with_name("fsck")
        .about("Verify repository hashes.")
        .arg(
            Arg::with_name("depth")
                .help(
                    "Controls what objects' hashes are verified. Deeper \n\
                     objects will always have their parent objects' hashes verified.",
                )
                .next_line_help(true)
                .short("d")
                .long("depth")
                .possible_values(&["commit", "subtree", "data"])
                .default_value("commit"),
        )
}

pub fn go(repository: &mut Repository, matches: &ArgMatches) -> Result<()> {
    let depth = match matches.value_of("depth").unwrap() {
        "commit" => Depth::Commit,
        "subtree" => Depth::Subtree,
        "data" => Depth::Data,
        _ => panic!("clap verification failure!"),
    };

    {
        let ctx = repository.local(())?;

        let mut hashes = ctx.refs.head().into_iter().collect::<Vec<_>>();
        let mut visited = HashSet::new();

        while !hashes.is_empty() {
            let object_stream = {
                let next_hashes = hashes.drain(..).filter(|&hash| visited.insert(hash));
                stream::futures_unordered(next_hashes.map(|hash| {
                    ctx.read_object(hash).map(move |object| (hash, object))
                }))
            };

            object_stream
                .from_err::<Error>()
                .for_each(|(hash, object)| {
                    let real_hash = marshal::hash(&object);
                    ensure!(hash == real_hash, ErrorKind::FsckFailure(hash, real_hash));

                    match object {
                        Object::Data(DataObject::Large(ref large_object))
                            if depth <= Depth::Data => {
                            hashes.extend(large_object.children.iter().map(|&(_, hash)| hash));
                        }
                        Object::Subtree(ref subtree_object) if depth <= Depth::Subtree => {
                            hashes.extend(subtree_object.entries.iter().map(|(_, &hash)| hash));
                        }
                        Object::Commit(ref commit_object) if depth <= Depth::Commit => {
                            hashes.extend(commit_object.parents.iter().cloned());
                            if depth <= Depth::Subtree {
                                hashes.push(commit_object.subtree);
                            }
                        }
                        _ => {}
                    }

                    Ok(())
                })
                .wait()?;
        }

        ctx.close().wait()?;
    }

    Ok(())
}
<commit_msg>bin: allow 'fsck' to report multiple errors per call<commit_after>use std::collections::HashSet;
use std::fmt::Write;

use clap::{App, SubCommand, Arg, ArgMatches};
use futures::prelude::*;
use futures::stream;

use attaca::marshal::{self, Object, DataObject};
use attaca::Repository;

use errors::*;

#[derive(PartialEq, Eq, PartialOrd, Ord)]
pub enum Depth {
    Commit,
    Subtree,
    Data,
}

pub fn command() -> App<'static, 'static> {
    SubCommand::with_name("fsck")
        .about("Verify repository hashes.")
        .arg(
            Arg::with_name("depth")
                .help(
                    "Controls what objects' hashes are verified. Deeper \n\
                     objects will always have their parent objects' hashes verified.",
                )
                .next_line_help(true)
                .short("d")
                .long("depth")
                .possible_values(&["commit", "subtree", "data"])
                .default_value("commit"),
        )
}

pub fn go(repository: &mut Repository, matches: &ArgMatches) -> Result<()> {
    let depth = match matches.value_of("depth").unwrap() {
        "commit" => Depth::Commit,
        "subtree" => Depth::Subtree,
        "data" => Depth::Data,
        _ => panic!("clap verification failure!"),
    };

    let errors = {
        let ctx = repository.local(())?;

        let mut errors = Vec::new();
        let mut hashes = ctx.refs.head().into_iter().collect::<Vec<_>>();
        let mut visited = HashSet::new();

        while !hashes.is_empty() {
            let object_stream = {
                let next_hashes = hashes.drain(..).filter(|&hash| visited.insert(hash));
                stream::futures_unordered(next_hashes.map(|hash| {
                    ctx.read_object(hash).map(move |object| (hash, object))
                }))
            };

            object_stream
                .from_err::<Error>()
                .for_each(|(hash, object)| {
                    let real_hash = marshal::hash(&object);

                    if hash != real_hash {
                        errors.push(Error::from_kind(ErrorKind::FsckFailure(hash, real_hash)));
                    }

                    match object {
                        Object::Data(DataObject::Large(ref large_object))
                            if depth <= Depth::Data => {
                            hashes.extend(large_object.children.iter().map(|&(_, hash)| hash));
                        }
                        Object::Subtree(ref subtree_object) if depth <= Depth::Subtree => {
                            hashes.extend(subtree_object.entries.iter().map(|(_, &hash)| hash));
                        }
                        Object::Commit(ref commit_object) if depth <= Depth::Commit => {
                            hashes.extend(commit_object.parents.iter().cloned());
                            if depth <= Depth::Subtree {
                                hashes.push(commit_object.subtree);
                            }
                        }
                        _ => {}
                    }

                    Ok(())
                })
                .wait()?;
        }

        ctx.close().wait()?;

        errors
    };

    if errors.is_empty() {
        println!("No errors detected!");
    } else {
        let mut buf = String::new();
        writeln!(buf, "Oh no! {} errors detected:", errors.len())?;

        for ek in errors {
            writeln!(buf, "\t{}", ek)?;
        }

        println!("{}", buf);
    }

    Ok(())
}
<|endoftext|>


<commit_before>extern crate exa;
use exa::Exa;

use std::env::args_os;
use std::io::{stdout, stderr, Write, ErrorKind};
use std::process::exit;

fn main() {
    let args = args_os().skip(1);
    match Exa::new(args, &mut stdout()) {
        Ok(mut exa) => {
            match exa.run() {
                Ok(exit_status) => exit(exit_status),
                Err(e) => {
                    match e.kind() {
                        ErrorKind::BrokenPipe => exit(0),
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            exit(1);
                        },
                    };
                }
            };
        },

        Err(ref e) if e.is_error() => {
            writeln!(stderr(), "{}", e).unwrap();
            exit(3);
        },

        Err(ref e) => {
            writeln!(stdout(), "{}", e).unwrap();
            exit(0);
        },
    };
}
<commit_msg>Make a common module of exit statuses<commit_after>extern crate exa;
use exa::Exa;

use std::env::args_os;
use std::io::{stdout, stderr, Write, ErrorKind};
use std::process::exit;

fn main() {
    let args = args_os().skip(1);
    match Exa::new(args, &mut stdout()) {
        Ok(mut exa) => {
            match exa.run() {
                Ok(exit_status) => exit(exit_status),
                Err(e) => {
                    match e.kind() {
                        ErrorKind::BrokenPipe => exit(exits::SUCCESS),
                        _ => {
                            writeln!(stderr(), "{}", e).unwrap();
                            exit(exits::RUNTIME_ERROR);
                        },
                    };
                }
            };
        },

        Err(ref e) if e.is_error() => {
            writeln!(stderr(), "{}", e).unwrap();
            exit(exits::OPTIONS_ERROR);
        },

        Err(ref e) => {
            writeln!(stdout(), "{}", e).unwrap();
            exit(exits::SUCCESS);
        },
    };
}

extern crate libc;
#[allow(trivial_numeric_casts)]
mod exits {
    use libc::{self, c_int};

    pub const SUCCESS:       c_int = libc::EXIT_SUCCESS;
    pub const RUNTIME_ERROR: c_int = libc::EXIT_FAILURE;
    pub const OPTIONS_ERROR: c_int = 3 as c_int;
}
<|endoftext|>


<commit_before> #![warn(unused, bad_style,
        unnecessary_qualification, unnecessary_typecast, unused_result)]

#![feature(slicing_syntax)]

extern crate common;
extern crate prime;

use common::Solver;
use prime::{Factorize, PrimeSet};

fn compute(max: uint) -> uint {
    let ps = PrimeSet::new();

    let abundant = range(2, max + 1)
        .filter(|&n| n.sum_of_proper_divisor(&ps) > n)
        .collect::<Vec<_>>();

    let mut sum_of_sum_abundant = 0;

    let mut is_sum_abundant = Vec::from_elem(max + 1, false);

    for (i, &a) in abundant.iter().enumerate() {
        for &b in abundant[i..].iter() {
            let s = a + b;
            if s > max { break; }
            if !is_sum_abundant[s] {
                sum_of_sum_abundant += s;
                // FIXME: rust-lang/rust#12825
                // is_sum_abundant[s] = true;
                *is_sum_abundant.get_mut(s) = true;
            }
        }
    }

    let sum_of_all_num = (1 + max) * max / 2;
    sum_of_all_num - sum_of_sum_abundant
}

fn solve() -> String {
    compute(28123).to_string()
}

fn main() { Solver::new("4179871", solve).run(); }
<commit_msg>remove FIXME: rust-lang/rust#12825<commit_after> #![warn(unused, bad_style,
        unnecessary_qualification, unnecessary_typecast, unused_result)]

#![feature(slicing_syntax)]

extern crate common;
extern crate prime;

use common::Solver;
use prime::{Factorize, PrimeSet};

fn compute(max: uint) -> uint {
    let ps = PrimeSet::new();

    let abundant = range(2, max + 1)
        .filter(|&n| n.sum_of_proper_divisor(&ps) > n)
        .collect::<Vec<_>>();

    let mut sum_of_sum_abundant = 0;

    let mut is_sum_abundant = Vec::from_elem(max + 1, false);

    for (i, &a) in abundant.iter().enumerate() {
        for &b in abundant[i..].iter() {
            let s = a + b;
            if s > max { break; }
            if !is_sum_abundant[s] {
                sum_of_sum_abundant += s;
                is_sum_abundant[s] = true;
            }
        }
    }

    let sum_of_all_num = (1 + max) * max / 2;
    sum_of_all_num - sum_of_sum_abundant
}

fn solve() -> String {
    compute(28123).to_string()
}

fn main() { Solver::new("4179871", solve).run(); }
<|endoftext|>


<commit_before>mod bxdf;
mod fresnel;
mod lambertian;
mod oren_nayar;
mod microfacet;

pub use self::bxdf::*;
pub use self::fresnel::*;
pub use self::lambertian::*;
pub use self::oren_nayar::*;
pub use self::microfacet::*;

use std::cmp;

use na::{Cross, Dot, Norm};

use ::{Vector3f, Point2f, ONE_MINUS_EPSILON};
use spectrum::Spectrum;
use interaction::SurfaceInteraction;

bitflags! {
    pub flags BxDFType: u32 {
        const BSDF_REFLECTION   = 0b_00000001,
        const BSDF_TRANSMISSION = 0b_00000010,
        const BSDF_DIFFUSE      = 0b_00000100,
        const BSDF_GLOSSY       = 0b_00001000,
        const BSDF_SPECULAR     = 0b_00010000,
    }
}

/// Represents the Bidirectional Scattering Distribution Function.
/// It represents the properties of a material at a given point.
pub struct BSDF {
    /// Index of refraction of the surface
    eta: f32,
    /// Shading normal (i.e. potentially affected by bump-mapping)
    ns: Vector3f,
    /// Geometry normal
    ng: Vector3f,
    ss: Vector3f,
    ts: Vector3f,
    bxdfs: Vec<Box<BxDF + Sync + Send>>,
}

impl BSDF {
    pub fn new(isect: &SurfaceInteraction, eta: f32, bxdfs: Vec<Box<BxDF + Sync + Send>>) -> BSDF {
        let ss = isect.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: isect.shading.n,
            ng: isect.n,
            ss: ss,
            ts: isect.shading.n.cross(&ss),
            bxdfs: bxdfs,
        }
    }

    /// Evaluate the BSDF for the given incoming light direction and outgoing light direction.
    pub fn f(&self, wo_w: &Vector3f, wi_w: &Vector3f, flags: BxDFType) -> Spectrum {
        let wi = self.world_to_local(wi_w);
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return Spectrum::black();
        }
        let reflect = wi_w.dot(&self.ng) * wo_w.dot(&self.ng) > 0.0;
        self.bxdfs
            .iter()
            .filter(|b| {
                // Make sure we only evaluate reflection or transmission based on whether wi and wo
                // lie in the same hemisphere.
                b.matches(flags) &&
                ((reflect && (b.get_type().contains(BSDF_REFLECTION))) ||
                 (!reflect && (b.get_type().contains(BSDF_TRANSMISSION))))
            })
            .fold(Spectrum::black(), |c, b| c + b.f(&wo, &wi))
    }

    pub fn pdf(&self, wo_w: &Vector3f, wi_w: &Vector3f, flags: BxDFType) -> f32 {
        if self.bxdfs.is_empty() {
            return 0.0;
        }
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return 0.0;
        }
        let wi = self.world_to_local(wi_w);

        let mut matched_comps = 0;
        let mut pdf = 0.0;
        for bxdf in &self.bxdfs {
            if bxdf.matches(flags) {
                matched_comps += 1;
                pdf += bxdf.pdf(&wo, &wi);
            }
        }
        if matched_comps == 0 {
            0.0
        } else {
            pdf / matched_comps as f32
        }
    }

    pub fn sample_f(&self,
                    wo_w: &Vector3f,
                    u: &Point2f,
                    flags: BxDFType)
                    -> (Spectrum, Vector3f, f32, BxDFType) {

        let matching_comps = self.bxdfs
            .iter()
            .filter(|b| b.matches(flags))
            .collect::<Vec<&Box<BxDF + Sync + Send>>>();
        if matching_comps.is_empty() {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
        }
        // Chose which BxDF to sample
        let comp = cmp::min((u[0] * matching_comps.len() as f32).floor() as usize,
                            matching_comps.len() - 1);
        let bxdf = matching_comps.get(comp).expect("Was expecting a BxDF with this index!");

        // Remap BxDF sample u to [0,1)^2
        let u_remapped = Point2f::new((u[0] * matching_comps.len() as f32 - comp as f32)
                                          .min(ONE_MINUS_EPSILON),
                                      u[1]);
        // Sample chosen BxDF
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, bxdf.get_type());
        }
        let (f, wi, mut pdf, sampled_type) = bxdf.sample_f(&wo, &u_remapped);
        if pdf == 0.0 {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
        }
        let wi_w = self.local_to_world(&wi);

        // Compute overall PDF with all matching BxDF
        if !bxdf.get_type().contains(BSDF_SPECULAR) && matching_comps.len() > 1 {
            for i in 0..matching_comps.len() {
                if i != comp {
                    pdf += matching_comps[i].pdf(&wo, &wi);
                }
            }
        }
        if matching_comps.len() > 1 {
            pdf /= matching_comps.len() as f32;
        }

        // Compute value of BSDF for sampled direction
        let mut f = Spectrum::black();
        if !bxdf.get_type().contains(BSDF_SPECULAR) && matching_comps.len() > 1 {
            let reflect = wi_w.dot(&self.ng) * wo_w.dot(&self.ng) > 0.0;

            f = matching_comps.iter()
                .filter(|b| {
                    (reflect && b.get_type().contains(BSDF_REFLECTION)) ||
                    (!reflect && b.get_type().contains(BSDF_TRANSMISSION))
                })
                .fold(Spectrum::black(), |f, b| f + b.f(&wo, &wi));
        }

        (f, wi, pdf, sampled_type)
    }

    fn world_to_local(&self, v: &Vector3f) -> Vector3f {
        Vector3f::new(v.dot(&self.ss), v.dot(&self.ts), v.dot(&self.ns))
    }

    fn local_to_world(&self, v: &Vector3f) -> Vector3f {
        Vector3f::new(self.ss.x * v.x + self.ts.x * v.y + self.ns.x * v.z,
                      self.ss.y * v.x + self.ts.y * v.y + self.ns.y * v.z,
                      self.ss.z * v.z + self.ts.z * v.y + self.ns.z * v.z)
    }

    /// Return the number of BxDFs matching the given flags
    fn num_components(&self, flags: BxDFType) -> usize {
        self.bxdfs.iter().filter(|b| b.matches(flags)).count()
    }
}
<commit_msg>Fix bad bug in BSDF::sample_f<commit_after>mod bxdf;
mod fresnel;
mod lambertian;
mod oren_nayar;
mod microfacet;

pub use self::bxdf::*;
pub use self::fresnel::*;
pub use self::lambertian::*;
pub use self::oren_nayar::*;
pub use self::microfacet::*;

use std::cmp;

use na::{Cross, Dot, Norm};

use ::{Vector3f, Point2f, ONE_MINUS_EPSILON};
use spectrum::Spectrum;
use interaction::SurfaceInteraction;

bitflags! {
    pub flags BxDFType: u32 {
        const BSDF_REFLECTION   = 0b_00000001,
        const BSDF_TRANSMISSION = 0b_00000010,
        const BSDF_DIFFUSE      = 0b_00000100,
        const BSDF_GLOSSY       = 0b_00001000,
        const BSDF_SPECULAR     = 0b_00010000,
    }
}

/// Represents the Bidirectional Scattering Distribution Function.
/// It represents the properties of a material at a given point.
pub struct BSDF {
    /// Index of refraction of the surface
    eta: f32,
    /// Shading normal (i.e. potentially affected by bump-mapping)
    ns: Vector3f,
    /// Geometry normal
    ng: Vector3f,
    ss: Vector3f,
    ts: Vector3f,
    bxdfs: Vec<Box<BxDF + Sync + Send>>,
}

impl BSDF {
    pub fn new(isect: &SurfaceInteraction, eta: f32, bxdfs: Vec<Box<BxDF + Sync + Send>>) -> BSDF {
        let ss = isect.dpdu.normalize();
        BSDF {
            eta: eta,
            ns: isect.shading.n,
            ng: isect.n,
            ss: ss,
            ts: isect.shading.n.cross(&ss),
            bxdfs: bxdfs,
        }
    }

    /// Evaluate the BSDF for the given incoming light direction and outgoing light direction.
    pub fn f(&self, wo_w: &Vector3f, wi_w: &Vector3f, flags: BxDFType) -> Spectrum {
        let wi = self.world_to_local(wi_w);
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return Spectrum::black();
        }
        let reflect = wi_w.dot(&self.ng) * wo_w.dot(&self.ng) > 0.0;
        self.bxdfs
            .iter()
            .filter(|b| {
                // Make sure we only evaluate reflection or transmission based on whether wi and wo
                // lie in the same hemisphere.
                b.matches(flags) &&
                ((reflect && (b.get_type().contains(BSDF_REFLECTION))) ||
                 (!reflect && (b.get_type().contains(BSDF_TRANSMISSION))))
            })
            .fold(Spectrum::black(), |c, b| c + b.f(&wo, &wi))
    }

    pub fn pdf(&self, wo_w: &Vector3f, wi_w: &Vector3f, flags: BxDFType) -> f32 {
        if self.bxdfs.is_empty() {
            return 0.0;
        }
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return 0.0;
        }
        let wi = self.world_to_local(wi_w);

        let mut matched_comps = 0;
        let mut pdf = 0.0;
        for bxdf in &self.bxdfs {
            if bxdf.matches(flags) {
                matched_comps += 1;
                pdf += bxdf.pdf(&wo, &wi);
            }
        }
        if matched_comps == 0 {
            0.0
        } else {
            pdf / matched_comps as f32
        }
    }

    pub fn sample_f(&self,
                    wo_w: &Vector3f,
                    u: &Point2f,
                    flags: BxDFType)
                    -> (Spectrum, Vector3f, f32, BxDFType) {

        let matching_comps = self.bxdfs
            .iter()
            .filter(|b| b.matches(flags))
            .collect::<Vec<&Box<BxDF + Sync + Send>>>();
        if matching_comps.is_empty() {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
        }
        // Chose which BxDF to sample
        let comp = cmp::min((u[0] * matching_comps.len() as f32).floor() as usize,
                            matching_comps.len() - 1);
        let bxdf = matching_comps.get(comp).expect("Was expecting a BxDF with this index!");

        debug!("BDDF::sample_f chose comp = {} / matching {}",
               comp,
               matching_comps.len());

        // Remap BxDF sample u to [0,1)^2
        let u_remapped = Point2f::new((u[0] * matching_comps.len() as f32 - comp as f32)
                                          .min(ONE_MINUS_EPSILON),
                                      u[1]);
        // Sample chosen BxDF
        let wo = self.world_to_local(wo_w);
        if wo.z == 0.0 {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, bxdf.get_type());
        }
        let (mut f, wi, mut pdf, sampled_type) = bxdf.sample_f(&wo, &u_remapped);
        debug!("For wo = {:?}, sampled f = {}, pdf = {}, ratio = {}, wi = {:?}",
               wo,
               f,
               pdf,
               if pdf > 0.0 {
                   f / pdf
               } else {
                   Spectrum::black()
               },
               wi);
        if pdf == 0.0 {
            return (Spectrum::black(), Vector3f::new(0.0, 0.0, 0.0), 0.0, BxDFType::empty());
        }
        let wi_w = self.local_to_world(&wi);

        // Compute overall PDF with all matching BxDF
        if !bxdf.get_type().contains(BSDF_SPECULAR) && matching_comps.len() > 1 {
            for i in 0..matching_comps.len() {
                if i != comp {
                    pdf += matching_comps[i].pdf(&wo, &wi);
                }
            }
        }
        if matching_comps.len() > 1 {
            pdf /= matching_comps.len() as f32;
        }

        // Compute value of BSDF for sampled direction
        if !bxdf.get_type().contains(BSDF_SPECULAR) && matching_comps.len() > 1 {
            let reflect = wi_w.dot(&self.ng) * wo_w.dot(&self.ng) > 0.0;
            f = matching_comps.iter()
                .filter(|b| {
                    (reflect && b.get_type().contains(BSDF_REFLECTION)) ||
                    (!reflect && b.get_type().contains(BSDF_TRANSMISSION))
                })
                .fold(Spectrum::black(), |f, b| f + b.f(&wo, &wi));
        }

        debug!("Overall f = {}, pdf = {}, ratio = {}",
               f,
               pdf,
               if pdf > 0.0 {
                   f / pdf
               } else {
                   Spectrum::black()
               });
        (f, wi, pdf, sampled_type)
    }

    fn world_to_local(&self, v: &Vector3f) -> Vector3f {
        Vector3f::new(v.dot(&self.ss), v.dot(&self.ts), v.dot(&self.ns))
    }

    fn local_to_world(&self, v: &Vector3f) -> Vector3f {
        Vector3f::new(self.ss.x * v.x + self.ts.x * v.y + self.ns.x * v.z,
                      self.ss.y * v.x + self.ts.y * v.y + self.ns.y * v.z,
                      self.ss.z * v.z + self.ts.z * v.y + self.ns.z * v.z)
    }

    /// Return the number of BxDFs matching the given flags
    fn num_components(&self, flags: BxDFType) -> usize {
        self.bxdfs.iter().filter(|b| b.matches(flags)).count()
    }
}
<|endoftext|>


<commit_before>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: usize = 8;

struct ChecksumWithPath {
    checksum: String,
    path: std::path::PathBuf,
}

impl ChecksumWithPath {
    pub fn new(checksum: String, path: std::path::PathBuf) -> Self {
        Self { checksum, path }
    }
}

type ChecksumResult = Result<ChecksumWithPath, ZakopaneError>;
type ChecksumTaskJoinHandle = tokio::task::JoinHandle<Vec<ChecksumWithPath>>;

struct ChecksumTaskDispatcherData {
    path: std::path::PathBuf,

    // Rate-limiter for spawned checksum tasks.
    semaphore: std::sync::Arc<tokio::sync::Semaphore>,

    // Counts total number of spawned checksum tasks.
    spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,

    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
}

impl ChecksumTaskDispatcherData {
    pub fn new(
        path: std::path::PathBuf,
        spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,
        sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    ) -> Self {
        Self {
            path,
            semaphore: std::sync::Arc::new(tokio::sync::Semaphore::new(MAX_TASKS)),
            spawn_counter,
            sender,
        }
    }
}

// Sends a checksum task result downstream to the collector task.
fn checksum_task_send_result(
    result: ChecksumResult,
    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
) {
    if let Err(e) = sender.blocking_send(result) {
        eprintln!("BUG: Sender::send() failed: {}", e);
    }
}

// Separated from `checksum_task()` to ensure the `add_permits()` call is
// always hit.
fn checksum_task_impl(path: std::path::PathBuf, sender: tokio::sync::mpsc::Sender<ChecksumResult>) {
    let contents = match crate::helpers::ingest_file(path.to_str().unwrap()) {
        Ok(contents) => contents,
        Err(e) => return checksum_task_send_result(Err(e), sender),
    };
    let checksum = crypto_hash::hex_digest(crypto_hash::Algorithm::SHA256, contents.as_ref());
    checksum_task_send_result(Ok(ChecksumWithPath::new(checksum, path)), sender);
}

// Represents a spawned checksum task.
fn checksum_task(
    path: std::path::PathBuf,
    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    semaphore_clone: std::sync::Arc<tokio::sync::Semaphore>,
) {
    checksum_task_impl(path, sender);

    // See comment in `ChecksumTaskManager::spawn_task()`.
    semaphore_clone.add_permits(1);
}

// Represents the spawned collection task.
async fn collector_task(
    mut receiver: tokio::sync::mpsc::Receiver<ChecksumResult>,
    spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,
) -> Vec<ChecksumWithPath> {
    let mut sums: Vec<ChecksumWithPath> = Vec::new();
    let mut errors: usize = 0;
    loop {
        while let Some(result) = receiver.recv().await {
            match result {
                Ok(digest_with_path) => sums.push(digest_with_path),
                Err(_) => errors += 1,
            }
        }
        if sums.len() + errors == spawn_counter.load(std::sync::atomic::Ordering::SeqCst) {
            return sums;
        }
    }
}

// Spawns the collector task that listens for checksum results
// provided by the checksum tasks.
async fn spawn_collector(
    path: std::path::PathBuf,
) -> (ChecksumTaskDispatcherData, ChecksumTaskJoinHandle) {
    let (sender, receiver) = tokio::sync::mpsc::channel(MAX_TASKS);
    let spawn_counter = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));
    let spawn_counter_clone = spawn_counter.clone();
    let join_handle =
        tokio::task::spawn(async move { collector_task(receiver, spawn_counter_clone).await });
    (
        ChecksumTaskDispatcherData::new(path, spawn_counter, sender),
        join_handle,
    )
}

async fn spawn_checksum_tasks(context: ChecksumTaskDispatcherData) {
    let walk_iter = walkdir::WalkDir::new(context.path).into_iter();
    for entry in walk_iter.filter_entry(|e| {
        !e.file_name()
            .to_str()
            .map(|path| path.starts_with(".")) // XXX(j39m)
            .unwrap_or(false)
    }) {
        if let Ok(direntry) = entry {
            let path = direntry.into_path();
            if !path.is_file() {
                continue;
            }

            context
                .spawn_counter
                .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
            let permit = context.semaphore.acquire().await.unwrap();

            // Icky workaround for not being able to pass `SemaphorePermit`
            // directly into a spawned task. Note that new permits are added
            // later in the checksum task.
            //
            // See also: https://github.com/tokio-rs/tokio/issues/1998
            permit.forget();

            let sender = context.sender.clone();
            let semaphore_clone = context.semaphore.clone();
            tokio::task::spawn_blocking(move || checksum_task(path, sender, semaphore_clone))
                .await
                .unwrap();
        }
    }
}

// Pretty-prints the sorted `checksums` in a format much like what the
// `sha256sum` binary outputs.
//
// Note that the standard zakopane snapshot header is not added here.
fn pretty_format_checksums(path: std::path::PathBuf, checksums: Vec<ChecksumWithPath>) -> String {
    let mut buffer: Vec<String> = Vec::new();
    for digest_line in checksums {
        buffer.push(format!(
            "{}  ./{}",
            digest_line.checksum,
            digest_line
                .path
                .strip_prefix(&path)
                .unwrap()
                .to_str()
                .unwrap()
        ));
    }
    buffer.join("\n")
}

async fn checksum_impl(path: std::path::PathBuf) -> String {
    let (dispatcher_data, join_handle) = spawn_collector(path.clone()).await;
    spawn_checksum_tasks(dispatcher_data).await;
    let mut checksums: Vec<ChecksumWithPath> = join_handle.await.unwrap();
    checksums.sort_by(|a, b| a.path.cmp(&b.path));
    pretty_format_checksums(path, checksums)
}

pub fn checksum(path: std::path::PathBuf) -> String {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl(path))
}
<commit_msg>checksum: Use `std::fs::read()`<commit_after>// Implements the `zakopane checksum` subcommand.

use crate::structs::ZakopaneError;

const MAX_TASKS: usize = 8;

struct ChecksumWithPath {
    checksum: String,
    path: std::path::PathBuf,
}

impl ChecksumWithPath {
    pub fn new(checksum: String, path: std::path::PathBuf) -> Self {
        Self { checksum, path }
    }
}

type ChecksumResult = Result<ChecksumWithPath, ZakopaneError>;
type ChecksumTaskJoinHandle = tokio::task::JoinHandle<Vec<ChecksumWithPath>>;

struct ChecksumTaskDispatcherData {
    path: std::path::PathBuf,

    // Rate-limiter for spawned checksum tasks.
    semaphore: std::sync::Arc<tokio::sync::Semaphore>,

    // Counts total number of spawned checksum tasks.
    spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,

    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
}

impl ChecksumTaskDispatcherData {
    pub fn new(
        path: std::path::PathBuf,
        spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,
        sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    ) -> Self {
        Self {
            path,
            semaphore: std::sync::Arc::new(tokio::sync::Semaphore::new(MAX_TASKS)),
            spawn_counter,
            sender,
        }
    }
}

// Sends a checksum task result downstream to the collector task.
fn checksum_task_send_result(
    result: ChecksumResult,
    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
) {
    if let Err(e) = sender.blocking_send(result) {
        eprintln!("BUG: Sender::send() failed: {}", e);
    }
}

// Separated from `checksum_task()` to ensure the `add_permits()` call is
// always hit.
fn checksum_task_impl(path: std::path::PathBuf, sender: tokio::sync::mpsc::Sender<ChecksumResult>) {
    let contents = match std::fs::read(&path).map_err(ZakopaneError::Io) {
        Ok(contents) => contents,
        Err(e) => return checksum_task_send_result(Err(e), sender),
    };
    let checksum = crypto_hash::hex_digest(crypto_hash::Algorithm::SHA256, &contents);
    checksum_task_send_result(Ok(ChecksumWithPath::new(checksum, path)), sender);
}

// Represents a spawned checksum task.
fn checksum_task(
    path: std::path::PathBuf,
    sender: tokio::sync::mpsc::Sender<ChecksumResult>,
    semaphore_clone: std::sync::Arc<tokio::sync::Semaphore>,
) {
    checksum_task_impl(path, sender);

    // See comment in `ChecksumTaskManager::spawn_task()`.
    semaphore_clone.add_permits(1);
}

// Represents the spawned collection task.
async fn collector_task(
    mut receiver: tokio::sync::mpsc::Receiver<ChecksumResult>,
    spawn_counter: std::sync::Arc<std::sync::atomic::AtomicUsize>,
) -> Vec<ChecksumWithPath> {
    let mut sums: Vec<ChecksumWithPath> = Vec::new();
    let mut errors: usize = 0;
    loop {
        while let Some(result) = receiver.recv().await {
            match result {
                Ok(digest_with_path) => sums.push(digest_with_path),
                Err(_) => errors += 1,
            }
        }
        if sums.len() + errors == spawn_counter.load(std::sync::atomic::Ordering::SeqCst) {
            return sums;
        }
    }
}

// Spawns the collector task that listens for checksum results
// provided by the checksum tasks.
async fn spawn_collector(
    path: std::path::PathBuf,
) -> (ChecksumTaskDispatcherData, ChecksumTaskJoinHandle) {
    let (sender, receiver) = tokio::sync::mpsc::channel(MAX_TASKS);
    let spawn_counter = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));
    let spawn_counter_clone = spawn_counter.clone();
    let join_handle =
        tokio::task::spawn(async move { collector_task(receiver, spawn_counter_clone).await });
    (
        ChecksumTaskDispatcherData::new(path, spawn_counter, sender),
        join_handle,
    )
}

async fn spawn_checksum_tasks(context: ChecksumTaskDispatcherData) {
    let walk_iter = walkdir::WalkDir::new(context.path).into_iter();
    for entry in walk_iter.filter_entry(|e| {
        !e.file_name()
            .to_str()
            .map(|path| path.starts_with(".")) // XXX(j39m)
            .unwrap_or(false)
    }) {
        if let Ok(direntry) = entry {
            let path = direntry.into_path();
            if !path.is_file() {
                continue;
            }

            context
                .spawn_counter
                .fetch_add(1, std::sync::atomic::Ordering::SeqCst);
            let permit = context.semaphore.acquire().await.unwrap();

            // Icky workaround for not being able to pass `SemaphorePermit`
            // directly into a spawned task. Note that new permits are added
            // later in the checksum task.
            //
            // See also: https://github.com/tokio-rs/tokio/issues/1998
            permit.forget();

            let sender = context.sender.clone();
            let semaphore_clone = context.semaphore.clone();
            tokio::task::spawn_blocking(move || checksum_task(path, sender, semaphore_clone))
                .await
                .unwrap();
        }
    }
}

// Pretty-prints the sorted `checksums` in a format much like what the
// `sha256sum` binary outputs.
//
// Note that the standard zakopane snapshot header is not added here.
fn pretty_format_checksums(path: std::path::PathBuf, checksums: Vec<ChecksumWithPath>) -> String {
    let mut buffer: Vec<String> = Vec::new();
    for digest_line in checksums {
        buffer.push(format!(
            "{}  ./{}",
            digest_line.checksum,
            digest_line
                .path
                .strip_prefix(&path)
                .unwrap()
                .to_str()
                .unwrap()
        ));
    }
    buffer.join("\n")
}

async fn checksum_impl(path: std::path::PathBuf) -> String {
    let (dispatcher_data, join_handle) = spawn_collector(path.clone()).await;
    spawn_checksum_tasks(dispatcher_data).await;
    let mut checksums: Vec<ChecksumWithPath> = join_handle.await.unwrap();
    checksums.sort_by(|a, b| a.path.cmp(&b.path));
    pretty_format_checksums(path, checksums)
}

pub fn checksum(path: std::path::PathBuf) -> String {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(checksum_impl(path))
}
<|endoftext|>


<commit_before>// Copyright 2016 Mozilla Foundation
//
// 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.

use client::{connect_to_server,connect_with_retry,ServerConnection};
use cmdline::Command;
use protocol::{
    CacheStats,
    ClientRequest,
    GetStats,
    Shutdown,
};
use server;
use std::env;
use std::io::{self,Error,ErrorKind};
use std::process;

/// The default sccache server port.
pub const DEFAULT_PORT : u16 = 4225;

fn maybe_redirect_stdio(cmd : &mut process::Command) {
    if !match env::var("SCCACHE_NO_DAEMON") {
            Ok(val) => val == "1",
            Err(_) => false,
    } {
        cmd.stdin(process::Stdio::null())
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null());
    }
}

/// Re-execute the current executable as a background server.
fn run_server_process() -> io::Result<()> {
    env::current_exe().and_then(|exe_path| {
        let mut cmd = process::Command::new(exe_path);
        maybe_redirect_stdio(&mut cmd);
        cmd.env("SCCACHE_START_SERVER", "1")
            .spawn()
    }).and(Ok(()))
}

fn result_exit_code<T : FnOnce(io::Error)>(res : io::Result<()>,
                                           else_func : T) -> i32 {
    res.and(Ok(0)).unwrap_or_else(|e| {
        else_func(e);
        1
    })
}

fn connect_or_start_server(port : u16) -> io::Result<ServerConnection> {
    connect_to_server(port).or_else(|e| {
        if e.kind() == io::ErrorKind::ConnectionRefused {
            // If the connection was refused we probably need to start
            // the server.
            run_server_process().and_then(|()| connect_with_retry(port))
        } else {
            Err(e)
        }
    })
}

fn request_stats(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_stats");
    let mut req = ClientRequest::new();
    req.set_get_stats(GetStats::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_stats() {
        Ok(response.take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn request_shutdown(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_shutdown");
    let mut req = ClientRequest::new();
    req.set_shutdown(Shutdown::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_shuttingdown() {
        Ok(response.take_shuttingdown().take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn format_size(size : u64) -> String {
    //TODO: actual nice formatting
    format!("{} {}", size, "bytes")
}

fn print_stats(stats : CacheStats) -> io::Result<()> {
    for stat in stats.get_stats().iter() {
        //TODO: properly align output
        print!("{}\t\t", stat.get_name());
        if stat.has_count() {
            print!("{}", stat.get_count());
        } else if stat.has_str() {
            print!("{}", stat.get_str());
        } else if stat.has_size() {
            print!("{}", format_size(stat.get_size()));
        }
        print!("\n");
    }
    Ok(())
}

pub fn run_command(cmd : Command) -> i32 {
    match cmd {
        // Actual usage gets printed in `cmdline::parse`.
        Command::Usage => 1,
        Command::ShowStats => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(request_stats).and_then(print_stats),
                             |e| {
                                 println!("Couldn't get stats from server: {}", e);
                             })
        },
        Command::InternalStartServer => {
            // Can't report failure here, we're already daemonized.
            result_exit_code(server::start_server(DEFAULT_PORT), |_| {})
        },
        Command::StartServer => {
            println!("Starting sccache server...");
            result_exit_code(run_server_process(), |e| {
                println!("failed to spawn server: {}", e);
            })
        },
        Command::StopServer => {
            println!("Stopping sccache server...");
            result_exit_code(connect_to_server(DEFAULT_PORT).and_then(request_shutdown).and_then(print_stats),
                             |_e| {
                                 //TODO: check if this was connection refused,
                                 // print error if not.
                                 println!("Couldn't connect to server");
                             })

        },
        Command::Compile(compile_cmdline) => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(|_conn| {
                //TODO: send Compile request
                let cmd_str = compile_cmdline.join(" ");
                println!("Command: '{}'", cmd_str);
                Ok(())
            }),
                             |e| {
                                 println!("compile failed: {}", e);
                             })
        },
    }
}
<commit_msg>debug log connect failure errors<commit_after>// Copyright 2016 Mozilla Foundation
//
// 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.

use client::{connect_to_server,connect_with_retry,ServerConnection};
use cmdline::Command;
use protocol::{
    CacheStats,
    ClientRequest,
    GetStats,
    Shutdown,
};
use server;
use std::env;
use std::io::{self,Error,ErrorKind};
use std::process;

/// The default sccache server port.
pub const DEFAULT_PORT : u16 = 4225;

fn maybe_redirect_stdio(cmd : &mut process::Command) {
    if !match env::var("SCCACHE_NO_DAEMON") {
            Ok(val) => val == "1",
            Err(_) => false,
    } {
        cmd.stdin(process::Stdio::null())
            .stdout(process::Stdio::null())
            .stderr(process::Stdio::null());
    }
}

/// Re-execute the current executable as a background server.
fn run_server_process() -> io::Result<()> {
    env::current_exe().and_then(|exe_path| {
        let mut cmd = process::Command::new(exe_path);
        maybe_redirect_stdio(&mut cmd);
        cmd.env("SCCACHE_START_SERVER", "1")
            .spawn()
    }).and(Ok(()))
}

fn result_exit_code<T : FnOnce(io::Error)>(res : io::Result<()>,
                                           else_func : T) -> i32 {
    res.and(Ok(0)).unwrap_or_else(|e| {
        else_func(e);
        1
    })
}

fn connect_or_start_server(port : u16) -> io::Result<ServerConnection> {
    connect_to_server(port).or_else(|e| {
        if e.kind() == io::ErrorKind::ConnectionRefused {
            // If the connection was refused we probably need to start
            // the server.
            run_server_process().and_then(|()| connect_with_retry(port))
        } else {
            debug!("Error: {}", e);
            Err(e)
        }
    })
}

fn request_stats(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_stats");
    let mut req = ClientRequest::new();
    req.set_get_stats(GetStats::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_stats() {
        Ok(response.take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn request_shutdown(mut conn : ServerConnection) -> io::Result<CacheStats> {
    debug!("request_shutdown");
    let mut req = ClientRequest::new();
    req.set_shutdown(Shutdown::new());
    //TODO: better error mapping
    let mut response = try!(conn.request(req).or(Err(Error::new(ErrorKind::Other, "Failed to send data to or receive data from server"))));
    if response.has_shuttingdown() {
        Ok(response.take_shuttingdown().take_stats())
    } else {
        Err(Error::new(ErrorKind::Other, "Unexpected server response!"))
    }
}

fn format_size(size : u64) -> String {
    //TODO: actual nice formatting
    format!("{} {}", size, "bytes")
}

fn print_stats(stats : CacheStats) -> io::Result<()> {
    for stat in stats.get_stats().iter() {
        //TODO: properly align output
        print!("{}\t\t", stat.get_name());
        if stat.has_count() {
            print!("{}", stat.get_count());
        } else if stat.has_str() {
            print!("{}", stat.get_str());
        } else if stat.has_size() {
            print!("{}", format_size(stat.get_size()));
        }
        print!("\n");
    }
    Ok(())
}

pub fn run_command(cmd : Command) -> i32 {
    match cmd {
        // Actual usage gets printed in `cmdline::parse`.
        Command::Usage => 1,
        Command::ShowStats => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(request_stats).and_then(print_stats),
                             |e| {
                                 println!("Couldn't get stats from server: {}", e);
                             })
        },
        Command::InternalStartServer => {
            // Can't report failure here, we're already daemonized.
            result_exit_code(server::start_server(DEFAULT_PORT), |_| {})
        },
        Command::StartServer => {
            println!("Starting sccache server...");
            result_exit_code(run_server_process(), |e| {
                println!("failed to spawn server: {}", e);
            })
        },
        Command::StopServer => {
            println!("Stopping sccache server...");
            result_exit_code(connect_to_server(DEFAULT_PORT).and_then(request_shutdown).and_then(print_stats),
                             |_e| {
                                 //TODO: check if this was connection refused,
                                 // print error if not.
                                 println!("Couldn't connect to server");
                             })

        },
        Command::Compile(compile_cmdline) => {
            result_exit_code(connect_or_start_server(DEFAULT_PORT).and_then(|_conn| {
                //TODO: send Compile request
                let cmd_str = compile_cmdline.join(" ");
                println!("Command: '{}'", cmd_str);
                Ok(())
            }),
                             |e| {
                                 println!("compile failed: {}", e);
                             })
        },
    }
}
<|endoftext|>


<commit_before><commit_msg>Bug 1441308 - Rename ForEach trait to AsyncForEach r=lsalzman<commit_after><|endoftext|>


<commit_before>use structs::Point;
use traits::HasValues;

/// Calculate the manhattan distance between two points
///
/// Distance is rounded up to the next integer.
///
/// # Example
///
/// ```
/// use hex_math::{distance, Point};
///
/// let point: Point = Point::new_2d(1, 2);
/// let other: Point = Point::new_2d(3, 4);
///
/// assert_eq!(4, distance(&point, &other));
/// ```
///
/// ```
/// use hex_math::{distance, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
///
/// assert_eq!(9, distance(&point, &other));
/// ```
pub fn distance<T: HasValues>(point: &T, other: &T) -> i32 {

  let base = distance_2d(point, other);
  let point: Point = Point::from(point.values());
  let other: Point = Point::from(other.values());
  let diff: Point = &point - &other;
  let height = diff.t.abs();
  let distance = base + height;

  distance

}

/// Calculate the manhattan distance between two points ignoring height
///
/// Distance is rounded up to the next integer.
///
/// # Example
///
/// ```
/// use hex_math::{distance_2d, Point};
///
/// let point: Point = Point::new(1, 2, 5);
/// let other: Point = Point::new(3, 4, 10);
///
/// assert_eq!(4, distance_2d(&point, &other));
/// ```
pub fn distance_2d<T: HasValues>(point: &T, other: &T) -> i32 {

  let point: Point = Point::from(point.values());
  let other: Point = Point::from(other.values());
  let diff: Point = &point - &other;
  let (q, r, s) = diff.values_cube_2d();
  let distance = (q.abs() + r.abs() + s.abs()) / 2;

  distance

}

<commit_msg>Issue #33: Refactor distance<commit_after>use structs::Point;
use traits::HasValues;

/// Calculate the manhattan distance between two points
///
/// Distance is rounded up to the next integer.
pub fn distance<T: HasValues>(point: &T, other: &T) -> i32 {

  let base = distance_2d(point, other);
  let point: Point = Point::from(point.values());
  let other: Point = Point::from(other.values());
  let diff: Point = &point - &other;
  let height = diff.t.abs();
  let distance = base + height;

  distance

}

/// Calculate the manhattan distance between two points ignoring height
///
/// Distance is rounded up to the next integer.
pub fn distance_2d<T: HasValues>(point: &T, other: &T) -> i32 {

  let point: Point = Point::from(point.values());
  let other: Point = Point::from(other.values());
  let diff: Point = &point - &other;
  let (q, r, s) = diff.values_cube_2d();
  let distance = (q.abs() + r.abs() + s.abs()) / 2;

  distance

}

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

  #[test]
  fn distance() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(3, 4, 10);

    assert!(9 == super::distance(&point, &other));
  }

  #[test]
  fn distance_2d() {
    let point: Point = Point::new(1, 2, 5);
    let other: Point = Point::new(3, 4, 10);

    assert!(4 == super::distance_2d(&point, &other));
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// TODO: Remove this when things stabilize.
#![allow(dead_code)]

use encoding::Quantifier::*;

#[derive(Copy,Eq,PartialEq)]
pub enum Type {
	Int8  = 0,
	Int16 = 1,
	Int32 = 2,
	Int64 = 3,

	UInt8  = 4,
	UInt16 = 5,
	UInt32 = 6,
	UInt64 = 7,

	Fixed32 = 8,
	Fixed64 = 9,

	Float32 = 10,
	Float64 = 11,

	Bytes  = 12,
	String = 13,

	Bool = 14,

	Enum = 15,

	FirstUnused = 16,
}

struct NoSuchType;

impl Type {
	pub fn from_usize(x: usize) -> Result<Type, NoSuchType> {
		match x {
			0 => Ok(Type::Int8),
			1 => Ok(Type::Int16),
			2 => Ok(Type::Int32),
			3 => Ok(Type::Int64),

			4 => Ok(Type::UInt8),
			5 => Ok(Type::UInt16),
			6 => Ok(Type::UInt32),
			7 => Ok(Type::UInt64),

			8 => Ok(Type::Fixed32),
			9 => Ok(Type::Fixed64),

			10 => Ok(Type::Float32),
			11 => Ok(Type::Float64),

			12 => Ok(Type::Bytes),
			13 => Ok(Type::String),

			14 => Ok(Type::Bool),

			15 => Ok(Type::Enum),

			_ => Err(NoSuchType),
		}
	}
}

// The Quantifier type gives the multiplicity of a field. A Required field has exactly 1 element, an
// Optional field has 0 or 1 elements, and a Repeated field has 0 or more elements.
#[derive(Debug,Copy,PartialEq,Eq)]
pub enum Quantifier {
	Required = 0,
	Optional = 1,
	Repeated = 2,
}

#[derive(PartialEq,Eq)]
pub struct FieldEncoding {
	// Integer id of this field within its containing record.
	pub id: u64,

	// Name of this field in the .rex file, not used in the encoding.
	pub name: String,

	// Is this field Required, Optional (opt), or Repeated (rep)?
	pub quant: Quantifier,

	// Type of this field.
	pub typ: usize,

    // The bounds field is the product of all bounds in an array field. So for example, the field
    //
    //     1 matrix : [3][3]float32
    //
    // would have a bounds field of 3*3 = 9.
    //
    // The bounds field is not present for non-array types.
	pub bounds: Option<usize>,
}

#[derive(PartialEq,Eq)]
pub struct RecordEncoding {
	// Name of the record type in the .rex file, not used in the encoding.
	pub name: String,

	// Required fields of this record type, sorted by id.
	pub req_fields: Vec<FieldEncoding>,

	// Optional and repeated fields of this record type, sorted by id.
	pub opt_rep_fields: Vec<FieldEncoding>,
}

impl RecordEncoding {
	fn sort_fields(&mut self) {
		self.req_fields.sort_by(|a, b| a.id.cmp(&b.id));
		self.opt_rep_fields.sort_by(|a, b| a.id.cmp(&b.id));
	}
}

// A CompleteEncoding provides all of the information necessary to parse a particular record type
// (and every record type that it can contain).
#[derive(PartialEq,Eq)]
pub struct CompleteEncoding {
	// The record type that this CompleteEncoding describes.
	pub target:  RecordEncoding,

	// Encodings for all dependencies of target. If a field has a type (t >= Type::FirstUnused),
	// then a RecordEncoding for that type is at depends[t - Type::FirstUnused].
	pub depends: Vec<RecordEncoding>,
}

impl CompleteEncoding {
	pub fn sort_fields(&mut self) {
		self.target.sort_fields();

		for dep in self.depends.iter_mut() {
			dep.sort_fields();
		}
	}
}

// These are indices into COMPLETE_ENC.depends, below. See docs for that field on the
// CompleteEncoding type.
const FIELD_ENCODING_TYP:  usize = 0 + (Type::FirstUnused as usize);
const RECORD_ENCODING_TYP: usize = 1 + (Type::FirstUnused as usize);

lazy_static! {

	// I apologize in advance for the confusing-ness of this comment.
	//
	// Encodings for records are themselves encoded, so we need to solve the chicken/egg problem in
	// order to be able to interpret the encodings of encodings :3.
	//
	// We do this by providing a pre-decoded encoding for encodings. That's what this lovely
	// structure is.
	pub static ref COMPLETE_ENC: CompleteEncoding = CompleteEncoding {
		target: RecordEncoding {
			name: "CompleteEncoding".to_string(),
			req_fields: vec![

				FieldEncoding {
					id:     1,
					name:   "target".to_string(),
					quant:  Required,
					typ:    RECORD_ENCODING_TYP,
					bounds: None
				},
			],

			opt_rep_fields: vec![

				FieldEncoding {
					id:     2,
					quant:  Repeated,
					name:   "depends".to_string(),
					typ:    RECORD_ENCODING_TYP,
					bounds: None
				},
			],
		},

		depends: vec![

			RecordEncoding {
				name: "FieldEncoding".to_string(),
				req_fields: vec![

					FieldEncoding {
						id:     1,
						name:   "id".to_string(),
						quant:  Required,
						typ:    Type::UInt64 as usize,
						bounds: None
					},

					FieldEncoding {
						id:     2,
						name:   "name".to_string(),
						quant:  Required,
						typ:    Type::String as usize,
						bounds: None
					},

					FieldEncoding {
						id:     3,
						name:   "quant".to_string(),
						quant:  Required,
						typ:    Type::Enum as usize,
						bounds: None
					},

					FieldEncoding {
						id:     4,
						name:   "typ".to_string(),
						quant:  Required,
						typ:    Type::Enum as usize,
						bounds: None
					},

					FieldEncoding {
						id:     5,
						name:   "bounds".to_string(),
						quant:  Required,
						typ:    Type::UInt64 as usize,
						bounds: None
					},
				],
				opt_rep_fields: vec![]
			},

			RecordEncoding {
				name: "RecordEncoding".to_string(),
				req_fields: vec![
					FieldEncoding {
						id:     1,
						name:   "name".to_string(),
						quant:  Required,
						typ:    Type::String as usize,
						bounds: None
					},
				],

				opt_rep_fields: vec![
					FieldEncoding {
						id:     2,
						name:   "req_fields".to_string(),
						quant:  Repeated,
						typ:    FIELD_ENCODING_TYP,
						bounds: None
					},

					FieldEncoding {
						id:     3,
						name:   "opt_rep_fields".to_string(),
						quant:  Repeated,
						typ:    FIELD_ENCODING_TYP,
						bounds: None
					},
				],
			},
		],
	};
}
<commit_msg>Made Types and FieldIDs strongly typed.<commit_after>// Copyright (c) 2015, Sam Payson
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
// associated documentation files (the "Software"), to deal in the Software without restriction,
// including without limitation the rights to use, copy, modify, merge, publish, distribute,
// sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// TODO: Remove this when things stabilize.
#![allow(dead_code)]

use encoding::Quantifier::*;

#[derive(Copy,Eq,PartialEq)]
pub enum Type {
	Int8,
	Int16,
	Int32,
	Int64,

	UInt8,
	UInt16,
	UInt32,
	UInt64,

	Fixed32,
	Fixed64,

	Float32,
	Float64,

	Bytes,
	String,

	Bool,

	Enum,

    // A `Record` is any type which is encoded as >= FirstUnused (as specified in encoding.rex).
    // The `index` field gives an index into the `depends` field of the CompleteEncoding which
    // provides encoding information for this type.
    Record{index: usize},
}

#[derive(Eq,PartialEq,Ord,PartialOrd,Copy)]
pub struct FieldID(u64);

impl Type {
	pub fn from_usize(x: usize) -> Type {
        let first_unused = 16;

		match x {
			 0 => Type::Int8,
			 1 => Type::Int16,
			 2 => Type::Int32,
			 3 => Type::Int64,

			 4 => Type::UInt8,
			 5 => Type::UInt16,
			 6 => Type::UInt32,
			 7 => Type::UInt64,

			 8 => Type::Fixed32,
			 9 => Type::Fixed64,

			10 => Type::Float32,
			11 => Type::Float64,

			12 => Type::Bytes,
			13 => Type::String,

			14 => Type::Bool,

			15 => Type::Enum,

            xx => Type::Record{index: xx - first_unused},
		}
	}
}

// The Quantifier type gives the multiplicity of a field. A Required field has exactly 1 element, an
// Optional field has 0 or 1 elements, and a Repeated field has 0 or more elements.
#[derive(Debug,Copy,PartialEq,Eq)]
pub enum Quantifier {
	Required = 0,
	Optional = 1,
	Repeated = 2,
}

#[derive(PartialEq,Eq)]
pub struct FieldEncoding {
	// Integer id of this field within its containing record.
	pub id: FieldID,

	// Name of this field in the .rex file, not used in the encoding.
	pub name: String,

	// Is this field Required, Optional (opt), or Repeated (rep)?
	pub quant: Quantifier,

	// Type of this field.
	pub typ: Type,

    // The bounds field is the product of all bounds in an array field. So for example, the field
    //
    //     1 matrix : [3][3]float32
    //
    // would have a bounds field of 3*3 = 9.
    //
    // The bounds field is not present for non-array types.
	pub bounds: Option<usize>,
}

#[derive(PartialEq,Eq)]
pub struct RecordEncoding {
	// Name of the record type in the .rex file, not used in the encoding.
	pub name: String,

	// Required fields of this record type, sorted by id.
	pub req_fields: Vec<FieldEncoding>,

	// Optional and repeated fields of this record type, sorted by id.
	pub opt_rep_fields: Vec<FieldEncoding>,
}

impl RecordEncoding {
	fn sort_fields(&mut self) {
		self.req_fields.sort_by(|a, b| a.id.cmp(&b.id));
		self.opt_rep_fields.sort_by(|a, b| a.id.cmp(&b.id));
	}
}

// A CompleteEncoding provides all of the information necessary to parse a particular record type
// (and every record type that it can contain).
#[derive(PartialEq,Eq)]
pub struct CompleteEncoding {
	// The record type that this CompleteEncoding describes.
	pub target:  RecordEncoding,

	// Encodings for all dependencies of target. If a field has a type (t >= Type::FirstUnused),
	// then a RecordEncoding for that type is at depends[t - Type::FirstUnused].
	pub depends: Vec<RecordEncoding>,
}

impl CompleteEncoding {
	pub fn sort_fields(&mut self) {
		self.target.sort_fields();

		for dep in self.depends.iter_mut() {
			dep.sort_fields();
		}
	}
}

// These are indices into COMPLETE_ENC.depends, below. See docs for that field on the
// CompleteEncoding type.
const FIELD_ENCODING_TYP:  Type = Type::Record{index: 0};
const RECORD_ENCODING_TYP: Type = Type::Record{index: 1};

lazy_static! {

	// I apologize in advance for the confusing-ness of this comment.
	//
	// Encodings for records are themselves encoded, so we need to solve the chicken/egg problem in
	// order to be able to interpret the encodings of encodings :3.
	//
	// We do this by providing a pre-decoded encoding for encodings. That's what this lovely
	// structure is.
	pub static ref COMPLETE_ENC: CompleteEncoding = CompleteEncoding {
		target: RecordEncoding {
			name: "CompleteEncoding".to_string(),
			req_fields: vec![

				FieldEncoding {
					id:     FieldID(1),
					name:   "target".to_string(),
					quant:  Required,
					typ:    RECORD_ENCODING_TYP,
					bounds: None
				},
			],

			opt_rep_fields: vec![

				FieldEncoding {
					id:     FieldID(2),
					quant:  Repeated,
					name:   "depends".to_string(),
					typ:    RECORD_ENCODING_TYP,
					bounds: None
				},
			],
		},

		depends: vec![

			RecordEncoding {
				name: "FieldEncoding".to_string(),
				req_fields: vec![

					FieldEncoding {
						id:     FieldID(1),
						name:   "id".to_string(),
						quant:  Required,
						typ:    Type::UInt64,
						bounds: None
					},

					FieldEncoding {
						id:     FieldID(2),
						name:   "name".to_string(),
						quant:  Required,
						typ:    Type::String,
						bounds: None
					},

					FieldEncoding {
						id:     FieldID(3),
						name:   "quant".to_string(),
						quant:  Required,
						typ:    Type::Enum,
						bounds: None
					},

					FieldEncoding {
						id:     FieldID(4),
						name:   "typ".to_string(),
						quant:  Required,
						typ:    Type::Enum,
						bounds: None
					},

					FieldEncoding {
						id:     FieldID(5),
						name:   "bounds".to_string(),
						quant:  Required,
						typ:    Type::UInt64,
						bounds: None
					},
				],
				opt_rep_fields: vec![]
			},

			RecordEncoding {
				name: "RecordEncoding".to_string(),
				req_fields: vec![
					FieldEncoding {
						id:     FieldID(1),
						name:   "name".to_string(),
						quant:  Required,
						typ:    Type::String,
						bounds: None
					},
				],

				opt_rep_fields: vec![
					FieldEncoding {
						id:     FieldID(2),
						name:   "req_fields".to_string(),
						quant:  Repeated,
						typ:    FIELD_ENCODING_TYP,
						bounds: None
					},

					FieldEncoding {
						id:     FieldID(3),
						name:   "opt_rep_fields".to_string(),
						quant:  Repeated,
						typ:    FIELD_ENCODING_TYP,
						bounds: None
					},
				],
			},
		],
	};
}
<|endoftext|>


<commit_before>
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

use serde_json::Value;
use node::Node;
use sim::NodeMeta;
use sim::RoutingAlgorithm;
use graph::{Graph, ID};
use utils::*;
use std::u16;
use std::fmt;
use std::fmt::Write;

pub fn export_json(graph: &Graph, algo: Option<&RoutingAlgorithm>) -> String {
	let mut ret = String::new();
	let mut meta = NodeMeta::new();

	write!(&mut ret, "{{").unwrap();
	write!(&mut ret, "\"nodes\": [").unwrap();
	let mut comma1 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		if comma1 {
			write!(&mut ret, ",").unwrap();
		}
		comma1 = true;
		if let Some(algo) = algo {
			meta.clear();
			algo.get_node_meta(id as ID, &mut meta);
		}
		let x = node.gpos.x();
		let y = node.gpos.y();
		write!(&mut ret,
			"{{\"mac\": \"{}\", \"x\": {}, \"y\": {}, \"node_name\": \"{}\", \"node_label\": \"{}\"}}",
			id, x, y, meta.name, meta.label).unwrap();
	}

	write!(&mut ret, "], \"links\": [").unwrap();
	let mut comma2 = false;
	//for (id, node) in graph.nodes.iter().enumerate() {
	for link in &graph.links {
		if link.from > link.to {
			continue;
		}

		if comma2 {
			write!(&mut ret, ",").unwrap();
		}
		comma2 = true;
		// how to remember
		let source_id = link.from;
		let source_tq = (link.quality() as f32) / (u16::MAX as f32);
		let target_id = link.to;
		let target_tq = if let Some(link) = graph.find_link(target_id, source_id) {
			(link.quality() as f32) / (u16::MAX as f32)
		} else {
			0.0
		};
		write!(&mut ret, "{{\"source\": \"{}\", \"target\": \"{}\", \"source_tq\": {}, \"target_tq\": {}}}",
			source_id, target_id, source_tq, target_tq
		).unwrap();
	}

	write!(&mut ret, "]}}").unwrap();

	ret
}

/*
pub fn export_netjson(graph: &Graph) -> String {
	let mut ret = String::new();

	write!(&mut ret, "{{\"type\": \"NetworkGraph\", \"protocol\": \"\", \"version\": \"\", \"metric\": \"tq\", \"directed\": false, \"multigraph\": false,").unwrap();
	//write!(&mut ret, "\"timestamp\": \"{:?}\", ", chrono::Utc::now()).unwrap();

	write!(&mut ret, "\"nodes\": [").unwrap();
	let mut comma1 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		if comma1 {
			write!(&mut ret, ",").unwrap();
		}
		comma1 = true;
		write!(&mut ret, "{{\"id\": \"{}\"}}", id).unwrap();
	}

	write!(&mut ret, "], \"links\": [").unwrap();
	let mut comma2 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		for link in &node.links {
			if comma2 {
				write!(&mut ret, ",").unwrap();
			}
			comma2 = true;
			if link.to < (id as ID) {
				// how to remember
				let source_id = id as ID;
				let source_tq = link.quality;
				let target_id = link.to;
				let target_tq = if let Some(link) = graph.nodes[link.to as usize].find_link(source_id) {
					link.quality
				} else {
					0.0
				};
				write!(&mut ret, "{{\"source\": \"{}\", \"target\": \"{}\", \"source_tq\": {}, \"target_tq\": {}}}",
					source_id, target_id, source_tq, target_tq
				).unwrap();
			}
		}
	}

	write!(&mut ret, "]}}").unwrap();

	ret
}
*/
<commit_msg>change exported format to the graph viewer format<commit_after>
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

use serde_json::Value;
use node::Node;
use sim::NodeMeta;
use sim::RoutingAlgorithm;
use graph::{Graph, ID};
use utils::*;
use std::u16;
use std::fmt;
use std::fmt::Write;

pub fn export_json(graph: &Graph, algo: Option<&RoutingAlgorithm>) -> String {
	let mut ret = String::new();
	let mut meta = NodeMeta::new();

	write!(&mut ret, "{{").unwrap();
	write!(&mut ret, "\"nodes\": [").unwrap();
	let mut comma1 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		if comma1 {
			write!(&mut ret, ",").unwrap();
		}
		comma1 = true;
		if let Some(algo) = algo {
			meta.clear();
			algo.get_node_meta(id as ID, &mut meta);
		}
		let x = node.gpos.x();
		let y = node.gpos.y();
		write!(&mut ret,
			"{{\"id\": \"{}\", \"x\": {}, \"y\": {}, \"name\": \"{}\", \"label\": \"{}\"}}",
			id, x, y, meta.name, meta.label).unwrap();
	}

	write!(&mut ret, "], \"links\": [").unwrap();
	let mut comma2 = false;
	//for (id, node) in graph.nodes.iter().enumerate() {
	for link in &graph.links {
		if link.from > link.to {
			continue;
		}

		if comma2 {
			write!(&mut ret, ",").unwrap();
		}
		comma2 = true;
		// how to remember
		let source_id = link.from;
		let source_tq = (link.quality() as f32) / (u16::MAX as f32);
		let target_id = link.to;
		let target_tq = if let Some(link) = graph.find_link(target_id, source_id) {
			(link.quality() as f32) / (u16::MAX as f32)
		} else {
			0.0
		};
		write!(&mut ret, "{{\"source\": \"{}\", \"target\": \"{}\", \"source_tq\": {}, \"target_tq\": {}}}",
			source_id, target_id, source_tq, target_tq
		).unwrap();
	}

	write!(&mut ret, "]}}").unwrap();

	ret
}

/*
pub fn export_netjson(graph: &Graph) -> String {
	let mut ret = String::new();

	write!(&mut ret, "{{\"type\": \"NetworkGraph\", \"protocol\": \"\", \"version\": \"\", \"metric\": \"tq\", \"directed\": false, \"multigraph\": false,").unwrap();
	//write!(&mut ret, "\"timestamp\": \"{:?}\", ", chrono::Utc::now()).unwrap();

	write!(&mut ret, "\"nodes\": [").unwrap();
	let mut comma1 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		if comma1 {
			write!(&mut ret, ",").unwrap();
		}
		comma1 = true;
		write!(&mut ret, "{{\"id\": \"{}\"}}", id).unwrap();
	}

	write!(&mut ret, "], \"links\": [").unwrap();
	let mut comma2 = false;
	for (id, node) in graph.nodes.iter().enumerate() {
		for link in &node.links {
			if comma2 {
				write!(&mut ret, ",").unwrap();
			}
			comma2 = true;
			if link.to < (id as ID) {
				// how to remember
				let source_id = id as ID;
				let source_tq = link.quality;
				let target_id = link.to;
				let target_tq = if let Some(link) = graph.nodes[link.to as usize].find_link(source_id) {
					link.quality
				} else {
					0.0
				};
				write!(&mut ret, "{{\"source\": \"{}\", \"target\": \"{}\", \"source_tq\": {}, \"target_tq\": {}}}",
					source_id, target_id, source_tq, target_tq
				).unwrap();
			}
		}
	}

	write!(&mut ret, "]}}").unwrap();

	ret
}
*/
<|endoftext|>