<commit_before>#![allow(improper_ctypes)]
#[macro_use]
extern crate neon;
extern crate ratel;
#[macro_use]
extern crate serde;

#[macro_use]
extern crate serde_json;

use neon::vm::{Call, JsResult};
use neon::js::{JsString, JsBoolean};
use neon::js::error::{JsError, Kind};
use ratel::{parser, codegen, error, transformer};
use error::{Error, ParseError};

use ratel::{module, ast};

mod serializer;

fn ast(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;

    let module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };

    let out = serializer::serialize(&module).unwrap().to_string();
    Ok(JsString::new(scope, &out).unwrap())
}

fn format_errors(errors: Vec<Error>, source: neon::mem::Handle<JsString>) -> Vec<String> {
    errors
    .into_iter()
    .map(|err| {
        match err {
            Error::UnexpectedToken { start, end } => {
               ParseError::UnexpectedToken { start, end, source: source.value() }
            },
            Error::UnexpectedEndOfProgram => {
                ParseError::UnexpectedEndOfProgram
            }
        }
    })
    .map(|err| format!("{}", err))
    .collect()
}

fn transform(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;
    let minify = call.arguments.require(scope, 1)?.check::<JsBoolean>()?;

    let mut module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };
    transformer::transform(&mut module, transformer::Settings::target_es5());
    let out = codegen::codegen(&module, minify.value());

    Ok(JsString::new(scope, &out).unwrap())
}

fn parse(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;

    let module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };

    let out = format!("{:?}", module.body());

    Ok(JsString::new(scope, &out).unwrap())
}

register_module!(m, {
    m.export("transform", transform)?;
    m.export("parse", parse)?;
    m.export("ast", ast)?;
    Ok(())
});
<commit_msg>FFI: Adapting to changes<commit_after>#![allow(improper_ctypes)]
#[macro_use]
extern crate neon;
extern crate ratel;
#[macro_use]
extern crate serde;

#[macro_use]
extern crate serde_json;

use neon::vm::{Call, JsResult};
use neon::js::{JsString, JsBoolean};
use neon::js::error::{JsError, Kind};
use ratel::{parser, codegen, error, transformer};
use error::{Error, ParseError};

use ratel::{module, ast};

mod serializer;

fn ast(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;

    let module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };

    let out = serializer::serialize(&module).unwrap().to_string();
    Ok(JsString::new(scope, &out).unwrap())
}

fn format_errors(errors: Vec<Error>, source: neon::mem::Handle<JsString>) -> Vec<String> {
    errors
    .into_iter()
    .map(|err| {
        match err {
            Error::UnexpectedToken { start, end, .. } => {
               ParseError::UnexpectedToken { start, end, source: source.value() }
            },
            Error::UnexpectedEndOfProgram => {
                ParseError::UnexpectedEndOfProgram
            }
        }
    })
    .map(|err| format!("{}", err))
    .collect()
}

fn transform(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;
    let minify = call.arguments.require(scope, 1)?.check::<JsBoolean>()?;

    let mut module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };
    transformer::transform(&mut module, transformer::Settings::target_es5());
    let out = codegen::codegen(&module, minify.value());

    Ok(JsString::new(scope, &out).unwrap())
}

fn parse(call: Call) -> JsResult<JsString> {
    let scope = call.scope;

    if call.arguments.len() == 0 {
        return JsError::throw(Kind::TypeError, "First argument must be a string")
    }

    let source = call.arguments.require(scope, 0)?.check::<JsString>()?;

    let module = match parser::parse(source.value().as_str()) {
        Err(errors) => {
            let str = format_errors(errors, source).join("\n");
            return JsError::throw(Kind::SyntaxError, &str)
        },
        Ok(module) => module,
    };

    let out = format!("{:?}", module.body());

    Ok(JsString::new(scope, &out).unwrap())
}

register_module!(m, {
    m.export("transform", transform)?;
    m.export("parse", parse)?;
    m.export("ast", ast)?;
    Ok(())
});
<|endoftext|>


<commit_before>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;
use extra::priority_queue;
use extra::md4;
use extra::sort;
use std::path;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

static MAX_CACHE_SIZE_BYTES: u64 = 50000000;
static CACHE_MANAGER_A_RATE: u64 = 2000;
static CACHE_MANAGER_B_RATE: u64 = 6000;
static CACHE_MANAGER_B_INNER_RATE: u64 = 20;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    topPriority: int,
    fileSize: u64,
    httpHeader: ~str
}

impl Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {

        let mut retVal:bool = false;

        //If self has a lower geographic priority, then it is less than
        if (self.topPriority < other.topPriority) {
            retVal = true;
        }
        else if (self.topPriority == other.topPriority) {

            //If the two have equal priorities, then we will sort by file size
            //Smaller files get a higher priority
            if (self.fileSize > other.fileSize) {
                retVal = true;
            }
        }

        retVal
    }
}

struct cache_item {
    name: ~str,
    in_use_flag: bool,
    ssi_flag: bool,
    hash: ~str,
    data: ~[u8],
    count: uint,
    size: u64
}

fn le(this: &cache_item, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(this.count <= other.count) {
            retVal = true;
        }

        retVal
    }

fn main() {
    let req_vec: ~priority_queue::PriorityQueue<sched_msg> = ~priority_queue::PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    //Variables pertaining to safe visitor counting
    let safe_count: ~[uint] = ~[0];
    let shared_visit = arc::RWArc::new(safe_count);

    //Variables pertaining to cache and cache manager
    let cache_list: ~[cache_item] = ~[];
    let shared_cache_list = arc::RWArc::new(cache_list);
    let cache_manager_a = shared_cache_list.clone();
    let cache_manager_b = shared_cache_list.clone();

    //CACHE UPDATE MANAGER (Manager B)
    //This will handle making sure that items in the cache are up-to-date in case they are changed
    do spawn {
        loop {
            do cache_manager_b.write |vec| {
                for i in range(0, (*vec).len()) {
                    //If it is in the cache and in use, we will check to see if the file has been updated
                    if((*vec)[i].in_use_flag) {
                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {
                            match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {
                                        let temp_md4 = md4::md4_str(file_data.to_owned());

                                        if(temp_md4 != (*vec)[i].hash)
                                        {
                                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                                Some(s) => s,
                                                None => fail!("Could not access file stats for cache")
                                            };

                                            println(fmt!("===== UPDATING FILE: %?", (*vec)[i].name));

                                            (*vec)[i].data = file_data;
                                            (*vec)[i].size = fileInfo.size;
                                            (*vec)[i].hash = temp_md4;
                                        }
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                        }
                    }

                    //Added so that task does not hog RW lock. Need to modifiy to out of ARC?
                    timer::sleep(CACHE_MANAGER_B_INNER_RATE);
                }
            }

            timer::sleep(CACHE_MANAGER_B_RATE);
        }
    }

    //MAIN CACHE MANAGER (Manager A)
    do spawn {
        loop {
            do cache_manager_a.write |vec| {
                //Quick sort sorts in-place, so we don't need to worry about memory overhead
                //Just time overhead
                sort::quick_sort((*vec), le);

                let mut cache_remaining = MAX_CACHE_SIZE_BYTES;

                for i in range(0, (*vec).len()) {
                    if((*vec)[i].size <= cache_remaining && !(*vec)[i].in_use_flag) {
                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {
                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats for cache")
                            };

                            if(fileInfo.size <= cache_remaining) {
                                match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        //NEED TO ADD CHECK IF IT HAS SSI
                                        //PERHAPS EXCLUDE ALL SSI FROM CACHE?
                                        //ADD TO IF: size < remaining, !in use, !ssi?

                                        (*vec)[i].data = file_data.to_owned();
                                        (*vec)[i].size = fileInfo.size;
                                        (*vec)[i].hash = md4::md4_str(file_data);
                                        (*vec)[i].in_use_flag = true;

                                        cache_remaining = cache_remaining - fileInfo.size;
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                            }
                        }
                    }
                    else if((*vec)[i].size <= cache_remaining && (*vec)[i].in_use_flag) {
                        cache_remaining = cache_remaining - (*vec)[i].size;
                    }
                    else if((*vec)[i].size > cache_remaining) {
                        (*vec)[i].in_use_flag = false;
                        (*vec)[i].data = ~[];
                    }

                }
            }

            timer::sleep(CACHE_MANAGER_A_RATE);
        }
    }

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                //Check if file is in cache
                //Will do so using RWArc
                let mut serve_from_cache: bool = false;

                do shared_cache_list.write |vec| {
                    let mut found: bool = false;

                    for i in range(0, (*vec).len()) {
                        if( (*vec)[i].name == tf.filepath.to_str() && (*vec)[i].in_use_flag) {
                            serve_from_cache = true;
                            found = true;

                            println(fmt!("===== SERVING FROM CACHE: %?", tf.filepath.to_str()));

                            tf.stream.write(tf.httpHeader.as_bytes());
                            tf.stream.write((*vec)[i].data);

                            (*vec)[i].count += 1;
                        }
                        else if( (*vec)[i].name == tf.filepath.to_str() && !(*vec)[i].in_use_flag) {
                            (*vec)[i].count += 1;
                            found = true;
                        }
                    }

                    //If it isn't found, we will create a blank entry and enter basic info, and add the
                    //data and md4 later
                    if(!found) {
                        println(fmt!("===== ADDING ITEM %?", tf.filepath.to_str()));

                        let new_cache_item: cache_item = cache_item{name: tf.filepath.to_str(), in_use_flag: false,
                            ssi_flag: false, hash: ~"", data: ~[], count: 1, size: tf.fileSize};

                        (*vec).push(new_cache_item);
                    }
                }

                if(!serve_from_cache) {
                    match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                        Ok(file_data) => {
                            tf.stream.write(tf.httpHeader.as_bytes());
                            tf.stream.write(file_data);
                            println(fmt!("===== SERVING FROM DISK: %?", tf.filepath.to_str()));

                        }
                        Err(err) => {
                            println("ERROR IN SEND");
                            println(err);
                        }
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {

                    //Since we are using a priority queue, we will use pop()
                    let tf = (*vec).pop();
                    //println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    loop {
        let stream = acceptor.accept();
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let child_arc = shared_visit.clone();

        do spawn {

            let mut actual_count:uint = 0;

            //We will use the cloned RWARC
            do child_arc.write |count_vec| {
                let prev_count = (*count_vec).pop();
                let new_count: uint = prev_count + 1;

                actual_count = new_count;
                (*count_vec).push(new_count);
            }

            let stream = stream.take();

            match stream {
                Some(s) => {

                    let mut stream = s;

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);

                    let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path = req_group[1];

                        let file_path = ~os::getcwd().push(path.replace("/../", ""));

                        if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                            let response: ~str = fmt!(
                                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                                 \r\n", actual_count);

                            stream.write(response.as_bytes());
                        }
                        else {
                            // Requests scheduling

                            let mut streamPriority: int = 0;

                            //Retrieving the requesting IP address
                            let ipStr: ~str = match (stream).peer_name() {
                                Some(pr) => pr.ip.to_str(),
                                None => ~"0.0.0.0"
                            };

                            //Split the IP address by '.' so that we can compare
                            let ipSplit: ~[~str] = ipStr.split_iter('.').filter(|&x| x != "")
                                 .map(|x| x.to_owned()).collect();

                            //Assign priority based on geography or if localhost
                            if ( (ipSplit[0] == ~"127" && ipSplit[1] == ~"0") || (ipSplit[0] == ~"128" && ipSplit[1] == ~"143")
                                || (ipSplit[0] == ~"137" && ipSplit[1] == ~"54") ) {

                                streamPriority = 1;
                            }

                            let fileName: ~str = file_path.filename().unwrap().to_owned();
                            let fileNameSplit: ~[~str] = fileName.split_iter('.').filter(|&x| x != "").map(|x| x.to_owned()).collect();

                            //In order to optimize for the benchmark, we will send the HTTP header quickly before adding to the queue
                            let httpHeader: ~str = match fileNameSplit[fileNameSplit.len()-1] {
                                ~"html" | ~"htm" | ~"php" => ~"Content-Type: text/html; charset=UTF-8\r\n\r\n",
                                _ => ~"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n"
                            };

                            //stream.write(httpHeader.as_bytes());
                            //stream.flush();

                            //Retrieve file info for additional latency fixes
                            let fileInfo = match std::rt::io::file::stat(file_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats")
                            };

                            let msg: sched_msg = sched_msg{stream: Some(stream), filepath: file_path.clone(), topPriority: streamPriority, fileSize: fileInfo.size, httpHeader: httpHeader};
                            let (sm_port, sm_chan) = std::comm::stream();
                            sm_chan.send(msg);

                            do child_add_vec.write |vec| {
                                let msg = sm_port.recv();
                                (*vec).push(msg); // enqueue new request.
                            }
                            child_chan.send(""); //notify the new arriving request.
                        }
                    }
                    println!("connection terminates")

                },
                None => ()
            }
        }
    }
}<commit_msg>Fixed early serving of HTTP header<commit_after>//
// zhtta.rs
//
// Running on Rust 0.8
//
// Starting code for PS3
//
// Note: it would be very unwise to run this server on a machine that is
// on the Internet and contains any sensitive files!
//
// University of Virginia - cs4414 Fall 2013
// Weilin Xu and David Evans
// Version 0.3

extern mod extra;

use std::rt::io::*;
use std::rt::io::net::ip::SocketAddr;
use std::io::println;
use std::cell::Cell;
use std::{os, str, io};
use extra::arc;
use std::comm::*;
use extra::priority_queue;
use extra::md4;
use extra::sort;
use std::path;

static PORT:    int = 4414;
static IP: &'static str = "127.0.0.1";

static MAX_CACHE_SIZE_BYTES: u64 = 50000000;
static CACHE_MANAGER_A_RATE: u64 = 2000;
static CACHE_MANAGER_B_RATE: u64 = 6000;
static CACHE_MANAGER_B_INNER_RATE: u64 = 20;

struct sched_msg {
    stream: Option<std::rt::io::net::tcp::TcpStream>,
    filepath: ~std::path::PosixPath,
    topPriority: int,
    fileSize: u64,
    httpHeader: ~str
}

impl Ord for sched_msg {
    fn lt(&self, other: &sched_msg) -> bool {

        let mut retVal:bool = false;

        //If self has a lower geographic priority, then it is less than
        if (self.topPriority < other.topPriority) {
            retVal = true;
        }
        else if (self.topPriority == other.topPriority) {

            //If the two have equal priorities, then we will sort by file size
            //Smaller files get a higher priority
            if (self.fileSize > other.fileSize) {
                retVal = true;
            }
        }

        retVal
    }
}

struct cache_item {
    name: ~str,
    in_use_flag: bool,
    ssi_flag: bool,
    hash: ~str,
    data: ~[u8],
    count: uint,
    size: u64
}

fn le(this: &cache_item, other: &cache_item) -> bool {
        let mut retVal:bool = false;

        if(this.count <= other.count) {
            retVal = true;
        }

        retVal
    }

fn main() {
    let req_vec: ~priority_queue::PriorityQueue<sched_msg> = ~priority_queue::PriorityQueue::new();
    let shared_req_vec = arc::RWArc::new(req_vec);
    let add_vec = shared_req_vec.clone();
    let take_vec = shared_req_vec.clone();

    let (port, chan) = stream();
    let chan = SharedChan::new(chan);

    //Variables pertaining to safe visitor counting
    let safe_count: ~[uint] = ~[0];
    let shared_visit = arc::RWArc::new(safe_count);

    //Variables pertaining to cache and cache manager
    let cache_list: ~[cache_item] = ~[];
    let shared_cache_list = arc::RWArc::new(cache_list);
    let cache_manager_a = shared_cache_list.clone();
    let cache_manager_b = shared_cache_list.clone();

    //CACHE UPDATE MANAGER (Manager B)
    //This will handle making sure that items in the cache are up-to-date in case they are changed
    do spawn {
        loop {
            do cache_manager_b.write |vec| {
                for i in range(0, (*vec).len()) {
                    //If it is in the cache and in use, we will check to see if the file has been updated
                    if((*vec)[i].in_use_flag) {
                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {
                            match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {
                                        let temp_md4 = md4::md4_str(file_data.to_owned());

                                        if(temp_md4 != (*vec)[i].hash)
                                        {
                                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                                Some(s) => s,
                                                None => fail!("Could not access file stats for cache")
                                            };

                                            println(fmt!("===== UPDATING FILE: %?", (*vec)[i].name));

                                            (*vec)[i].data = file_data;
                                            (*vec)[i].size = fileInfo.size;
                                            (*vec)[i].hash = temp_md4;
                                        }
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                        }
                    }

                    //Added so that task does not hog RW lock. Need to modifiy to out of ARC?
                    timer::sleep(CACHE_MANAGER_B_INNER_RATE);
                }
            }

            timer::sleep(CACHE_MANAGER_B_RATE);
        }
    }

    //MAIN CACHE MANAGER (Manager A)
    do spawn {
        loop {
            do cache_manager_a.write |vec| {
                //Quick sort sorts in-place, so we don't need to worry about memory overhead
                //Just time overhead
                sort::quick_sort((*vec), le);

                let mut cache_remaining = MAX_CACHE_SIZE_BYTES;

                for i in range(0, (*vec).len()) {
                    if((*vec)[i].size <= cache_remaining && !(*vec)[i].in_use_flag) {
                        let curr_path = ~path::Path((*vec)[i].name);

                        if os::path_exists(curr_path) {
                            let fileInfo = match std::rt::io::file::stat(curr_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats for cache")
                            };

                            if(fileInfo.size <= cache_remaining) {
                                match io::read_whole_file(curr_path) {
                                    Ok(file_data) => {

                                        //NEED TO ADD CHECK IF IT HAS SSI
                                        //PERHAPS EXCLUDE ALL SSI FROM CACHE?
                                        //ADD TO IF: size < remaining, !in use, !ssi?

                                        (*vec)[i].data = file_data.to_owned();
                                        (*vec)[i].size = fileInfo.size;
                                        (*vec)[i].hash = md4::md4_str(file_data);
                                        (*vec)[i].in_use_flag = true;

                                        cache_remaining = cache_remaining - fileInfo.size;
                                    }
                                    Err(err) => {
                                        println("ERROR IN UPDATE CACHE");
                                        println(err);
                                    }
                                }
                            }
                        }
                    }
                    else if((*vec)[i].size <= cache_remaining && (*vec)[i].in_use_flag) {
                        cache_remaining = cache_remaining - (*vec)[i].size;
                    }
                    else if((*vec)[i].size > cache_remaining) {
                        (*vec)[i].in_use_flag = false;
                        (*vec)[i].data = ~[];
                    }

                }
            }

            timer::sleep(CACHE_MANAGER_A_RATE);
        }
    }

    // dequeue file requests, and send responses.
    // FIFO
    do spawn {
        let (sm_port, sm_chan) = stream();

        // a task for sending responses.
        do spawn {
            loop {
                let mut tf: sched_msg = sm_port.recv(); // wait for the dequeued request to handle

                //Check if file is in cache
                //Will do so using RWArc
                let mut serve_from_cache: bool = false;

                do shared_cache_list.write |vec| {
                    let mut found: bool = false;

                    for i in range(0, (*vec).len()) {
                        if( (*vec)[i].name == tf.filepath.to_str() && (*vec)[i].in_use_flag) {
                            serve_from_cache = true;
                            found = true;

                            println(fmt!("===== SERVING FROM CACHE: %?", tf.filepath.to_str()));

                            tf.stream.write(tf.httpHeader.as_bytes());
                            tf.stream.write((*vec)[i].data);

                            (*vec)[i].count += 1;
                        }
                        else if( (*vec)[i].name == tf.filepath.to_str() && !(*vec)[i].in_use_flag) {
                            (*vec)[i].count += 1;
                            found = true;
                        }
                    }

                    //If it isn't found, we will create a blank entry and enter basic info, and add the
                    //data and md4 later
                    if(!found) {
                        println(fmt!("===== ADDING ITEM %?", tf.filepath.to_str()));

                        let new_cache_item: cache_item = cache_item{name: tf.filepath.to_str(), in_use_flag: false,
                            ssi_flag: false, hash: ~"", data: ~[], count: 1, size: tf.fileSize};

                        (*vec).push(new_cache_item);
                    }
                }

                if(!serve_from_cache) {
                    match io::read_whole_file(tf.filepath) { // killed if file size is larger than memory size.
                        Ok(file_data) => {
                            tf.stream.write(tf.httpHeader.as_bytes());
                            tf.stream.write(file_data);
                            println(fmt!("===== SERVING FROM DISK: %?", tf.filepath.to_str()));

                        }
                        Err(err) => {
                            println("ERROR IN SEND");
                            println(err);
                        }
                    }
                }
            }
        }

        loop {
            port.recv(); // wait for arrving notification
            do take_vec.write |vec| {
                if ((*vec).len() > 0) {

                    //Since we are using a priority queue, we will use pop()
                    let tf = (*vec).pop();
                    //println(fmt!("shift from queue, size: %ud", (*vec).len()));
                    sm_chan.send(tf); // send the request to send-response-task to serve.
                }
            }
        }
    }

    let ip = match FromStr::from_str(IP) { Some(ip) => ip,
                                           None => { println(fmt!("Error: Invalid IP address <%s>", IP));
                                                     return;},
                                         };

    let socket = net::tcp::TcpListener::bind(SocketAddr {ip: ip, port: PORT as u16});

    println(fmt!("Listening on %s:%d ...", ip.to_str(), PORT));
    let mut acceptor = socket.listen().unwrap();

    loop {
        let stream = acceptor.accept();
        let stream = Cell::new(stream);

        // Start a new task to handle the each connection
        let child_chan = chan.clone();
        let child_add_vec = add_vec.clone();
        let child_arc = shared_visit.clone();

        do spawn {

            let mut actual_count:uint = 0;

            //We will use the cloned RWARC
            do child_arc.write |count_vec| {
                let prev_count = (*count_vec).pop();
                let new_count: uint = prev_count + 1;

                actual_count = new_count;
                (*count_vec).push(new_count);
            }

            let stream = stream.take();

            match stream {
                Some(s) => {

                    let mut stream = s;

                    let mut buf = [0, ..500];
                    stream.read(buf);
                    let request_str = str::from_utf8(buf);

                    let req_group : ~[&str]= request_str.splitn_iter(' ', 3).collect();
                    if req_group.len() > 2 {
                        let path = req_group[1];

                        let file_path = ~os::getcwd().push(path.replace("/../", ""));

                        if !os::path_exists(file_path) || os::path_is_dir(file_path) {
                            let response: ~str = fmt!(
                                "HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n
                                 <doctype !html><title>Hello, Rust!</title>

Greetings, Krusty!

Visitor count: %u

                                 \r\n", actual_count);

                            stream.write(response.as_bytes());
                        }
                        else {
                            // Requests scheduling

                            let mut streamPriority: int = 0;

                            //Retrieving the requesting IP address
                            let ipStr: ~str = match (stream).peer_name() {
                                Some(pr) => pr.ip.to_str(),
                                None => ~"0.0.0.0"
                            };

                            //Split the IP address by '.' so that we can compare
                            let ipSplit: ~[~str] = ipStr.split_iter('.').filter(|&x| x != "")
                                 .map(|x| x.to_owned()).collect();

                            //Assign priority based on geography or if localhost
                            if ( (ipSplit[0] == ~"127" && ipSplit[1] == ~"0") || (ipSplit[0] == ~"128" && ipSplit[1] == ~"143")
                                || (ipSplit[0] == ~"137" && ipSplit[1] == ~"54") ) {

                                streamPriority = 1;
                            }

                            let fileName: ~str = file_path.filename().unwrap().to_owned();
                            let fileNameSplit: ~[~str] = fileName.split_iter('.').filter(|&x| x != "").map(|x| x.to_owned()).collect();

                            //In order to optimize for the benchmark, we will send the HTTP header quickly before adding to the queue
                            let httpHeader: ~str = match fileNameSplit[fileNameSplit.len()-1] {
                                ~"html" | ~"htm" | ~"php" => ~"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n",
                                _ => ~"HTTP/1.1 200 OK\r\nContent-Type: application/octet-stream; charset=UTF-8\r\n\r\n"
                            };

                            //stream.write(httpHeader.as_bytes());
                            //stream.flush();

                            //Retrieve file info for additional latency fixes
                            let fileInfo = match std::rt::io::file::stat(file_path) {
                                Some(s) => s,
                                None => fail!("Could not access file stats")
                            };

                            let msg: sched_msg = sched_msg{stream: Some(stream), filepath: file_path.clone(), topPriority: streamPriority, fileSize: fileInfo.size, httpHeader: httpHeader};
                            let (sm_port, sm_chan) = std::comm::stream();
                            sm_chan.send(msg);

                            do child_add_vec.write |vec| {
                                let msg = sm_port.recv();
                                (*vec).push(msg); // enqueue new request.
                            }
                            child_chan.send(""); //notify the new arriving request.
                        }
                    }
                    println!("connection terminates")

                },
                None => ()
            }
        }
    }
}<|endoftext|>


<commit_before>use crate::dataset::*;
use crate::error::{Error, Result};
use dicom_core::{DataElementHeader, Length, VR};
use dicom_encoding::encode::{Encode, EncodeTo};
use dicom_encoding::text::{SpecificCharacterSet, TextCodec};
use dicom_encoding::TransferSyntax;
use std::io::Write;

/// A token representing a sequence or item start.
#[derive(Debug)]
struct SeqToken {
    /// Whether it is the start of a sequence or the start of an item.
    typ: SeqTokenType,
    /// The length of the value, as indicated by the starting element,
    /// can be unknown.
    len: Length,
}

/// A stateful device for printing a DICOM data set in sequential order.
/// This is analogous to the `DatasetReader` type for converting data
/// set tokens to bytes.
#[derive(Debug)]
pub struct DataSetWriter<W, E, T> {
    to: W,
    encoder: E,
    text: T,
    seq_tokens: Vec<SeqToken>,
}

impl<W> DataSetWriter<W, Box<dyn EncodeTo<W>>, Box<dyn TextCodec>>
where
    W: Write,
{
    pub fn with_ts_cs(to: W, ts: TransferSyntax, cs: SpecificCharacterSet) -> Result<Self> {
        let encoder = ts
            .encoder_for()
            .ok_or_else(|| Error::UnsupportedTransferSyntax)?;
        let text = cs.codec().ok_or_else(|| Error::UnsupportedCharacterSet)?;
        Ok(DataSetWriter::new(to, encoder, text))
    }
}

impl<W, E, T> DataSetWriter<W, E, T> {
    pub fn new(to: W, encoder: E, text: T) -> Self {
        DataSetWriter {
            to,
            encoder,
            text,
            seq_tokens: Vec::new(),
        }
    }
}

impl<W, E, T> DataSetWriter<W, E, T>
where
    W: Write,
    E: Encode,
    T: TextCodec,
{
    /// Feed the given sequence of tokens which are part of the same data set.
    pub fn write_sequence<I>(&mut self, tokens: I) -> Result<()>
    where
        I: IntoIterator<Item = DataToken>,
    {
        for token in tokens {
            self.write(token)?;
        }

        Ok(())
    }

    /// Feed the given data set token for writing the data set.
    #[inline]
    pub fn write(&mut self, token: DataToken) -> Result<()> {
        // TODO adjust the logic of sequence printing:
        // explicit length sequences or items should not print
        // the respective delimiter

        match token {
            DataToken::SequenceStart { tag: _, len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Sequence,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemStart { len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Item,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemEnd => {
                // only write if it's an unknown length item
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Item && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            DataToken::SequenceEnd => {
                // only write if it's an unknown length sequence
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Sequence && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            _ => self.write_stateless(token),
        }
    }

    fn write_stateless(&mut self, token: DataToken) -> Result<()> {
        use DataToken::*;
        match token {
            ElementHeader(header) => {
                self.encoder.encode_element_header(&mut self.to, header)?;
            }
            SequenceStart { tag, len } => {
                self.encoder.encode_element_header(
                    &mut self.to,
                    DataElementHeader::new(tag, VR::SQ, len),
                )?;
            }
            SequenceEnd => {
                self.encoder.encode_sequence_delimiter(&mut self.to)?;
            }
            ItemStart { len } => {
                self.encoder.encode_item_header(&mut self.to, len.0)?;
            }
            ItemEnd => {
                self.encoder.encode_item_delimiter(&mut self.to)?;
            }
            PrimitiveValue(value) => {
                // TODO handle strings properly
                self.encoder.encode_primitive(&mut self.to, &value)?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::super::DataToken;
    use super::DataSetWriter;
    use crate::printer::Printer;
    use dicom_core::header::{DataElementHeader, Length};
    use dicom_core::value::PrimitiveValue;
    use dicom_encoding::text::DefaultCharacterSetCodec;
    use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianEncoder;

    fn validate_dataset_writer<I>(tokens: I, ground_truth: &[u8])
    where
        I: IntoIterator<Item = DataToken>,
    {
        let mut raw_out: Vec<u8> = vec![];
        let encoder = ExplicitVRLittleEndianEncoder::default();
        let text = DefaultCharacterSetCodec::default();
        let mut dset_writer = DataSetWriter::new(&mut raw_out, encoder, text);

        //let mut iter = Iterator::zip(dset_writer.by_ref(), ground_truth);
    }
}
<commit_msg>[parser] add more tests to dataset writer<commit_after>use crate::dataset::*;
use crate::error::{Error, Result};
use dicom_core::{DataElementHeader, Length, VR};
use dicom_encoding::encode::{Encode, EncodeTo};
use dicom_encoding::text::{SpecificCharacterSet, TextCodec};
use dicom_encoding::TransferSyntax;
use std::io::Write;

/// A token representing a sequence or item start.
#[derive(Debug)]
struct SeqToken {
    /// Whether it is the start of a sequence or the start of an item.
    typ: SeqTokenType,
    /// The length of the value, as indicated by the starting element,
    /// can be unknown.
    len: Length,
}

/// A stateful device for printing a DICOM data set in sequential order.
/// This is analogous to the `DatasetReader` type for converting data
/// set tokens to bytes.
#[derive(Debug)]
pub struct DataSetWriter<W, E, T> {
    to: W,
    encoder: E,
    text: T,
    seq_tokens: Vec<SeqToken>,
}

impl<W> DataSetWriter<W, Box<dyn EncodeTo<W>>, Box<dyn TextCodec>>
where
    W: Write,
{
    pub fn with_ts_cs(to: W, ts: TransferSyntax, cs: SpecificCharacterSet) -> Result<Self> {
        let encoder = ts
            .encoder_for()
            .ok_or_else(|| Error::UnsupportedTransferSyntax)?;
        let text = cs.codec().ok_or_else(|| Error::UnsupportedCharacterSet)?;
        Ok(DataSetWriter::new(to, encoder, text))
    }
}

impl<W, E, T> DataSetWriter<W, E, T> {
    pub fn new(to: W, encoder: E, text: T) -> Self {
        DataSetWriter {
            to,
            encoder,
            text,
            seq_tokens: Vec::new(),
        }
    }
}

impl<W, E, T> DataSetWriter<W, E, T>
where
    W: Write,
    E: Encode,
    T: TextCodec,
{
    /// Feed the given sequence of tokens which are part of the same data set.
    pub fn write_sequence<I>(&mut self, tokens: I) -> Result<()>
    where
        I: IntoIterator<Item = DataToken>,
    {
        for token in tokens {
            self.write(token)?;
        }

        Ok(())
    }

    /// Feed the given data set token for writing the data set.
    #[inline]
    pub fn write(&mut self, token: DataToken) -> Result<()> {
        // adjust the logic of sequence printing:
        // explicit length sequences or items should not print
        // the respective delimiter

        match token {
            DataToken::SequenceStart { tag: _, len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Sequence,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemStart { len } => {
                self.seq_tokens.push(SeqToken {
                    typ: SeqTokenType::Item,
                    len,
                });
                self.write_stateless(token)?;
                Ok(())
            }
            DataToken::ItemEnd => {
                // only write if it's an unknown length item
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Item && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            DataToken::SequenceEnd => {
                // only write if it's an unknown length sequence
                if let Some(seq_start) = self.seq_tokens.pop() {
                    if seq_start.typ == SeqTokenType::Sequence && seq_start.len.is_undefined() {
                        self.write_stateless(token)?;
                    }
                }
                Ok(())
            }
            _ => self.write_stateless(token),
        }
    }

    fn write_stateless(&mut self, token: DataToken) -> Result<()> {
        use DataToken::*;
        match token {
            ElementHeader(header) => {
                self.encoder.encode_element_header(&mut self.to, header)?;
            }
            SequenceStart { tag, len } => {
                self.encoder.encode_element_header(
                    &mut self.to,
                    DataElementHeader::new(tag, VR::SQ, len),
                )?;
            }
            SequenceEnd => {
                self.encoder.encode_sequence_delimiter(&mut self.to)?;
            }
            ItemStart { len } => {
                self.encoder.encode_item_header(&mut self.to, len.0)?;
            }
            ItemEnd => {
                self.encoder.encode_item_delimiter(&mut self.to)?;
            }
            PrimitiveValue(value) => {
                // TODO handle strings properly
                self.encoder.encode_primitive(&mut self.to, &value)?;
            }
        }
        Ok(())
    }
}

#[cfg(test)]
mod tests {
    use super::super::DataToken;
    use super::DataSetWriter;
    use dicom_core::{Tag, VR, header::{DataElementHeader, Length}, value::PrimitiveValue};
    use dicom_encoding::text::DefaultCharacterSetCodec;
    use dicom_encoding::transfer_syntax::explicit_le::ExplicitVRLittleEndianEncoder;

    fn validate_dataset_writer<I>(tokens: I, ground_truth: &[u8])
    where
        I: IntoIterator<Item = DataToken>,
    {
        let mut raw_out: Vec<u8> = vec![];
        let encoder = ExplicitVRLittleEndianEncoder::default();
        let text = DefaultCharacterSetCodec::default();
        let mut dset_writer = DataSetWriter::new(&mut raw_out, encoder, text);

        dset_writer.write_sequence(tokens).unwrap();

        assert_eq!(raw_out, ground_truth);
    }

    #[test]
    fn write_sequence_explicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length(46),
            },
            DataToken::ItemStart { len: Length(20) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length(10) },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0x2e, 0x00, 0x00, 0x00, // length: 28 + 18 = 46 (#= 2)
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x14, 0x00, 0x00, 0x00, // item length: 20 (#= 2)
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0x0a, 0x00, 0x00, 0x00, // item length: 10 (#= 1)
            // -- 48 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 58 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }

    #[test]
    fn write_sequence_implicit() {
        let tokens = vec![
            DataToken::SequenceStart {
                tag: Tag(0x0018, 0x6011),
                len: Length::UNDEFINED,
            },
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6014),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::ItemStart { len: Length::UNDEFINED },
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0018, 0x6012),
                vr: VR::US,
                len: Length(2),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
            DataToken::ItemEnd,
            DataToken::SequenceEnd,
            DataToken::ElementHeader(DataElementHeader {
                tag: Tag(0x0020, 0x4000),
                vr: VR::LT,
                len: Length(4),
            }),
            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
        ];

        #[rustfmt::skip]
        static GROUND_TRUTH: &[u8] = &[
            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
            b'S', b'Q', // VR
            0x00, 0x00, // reserved
            0xff, 0xff, 0xff, 0xff, // length: undefined
            // -- 12 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 20 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
            // -- 30 --
            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
            // -- 40 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 48 --
            0xfe, 0xff, 0x00, 0xe0, // item start tag
            0xff, 0xff, 0xff, 0xff, // item length: undefined
            // -- 56 --
            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
            // -- 66 --
            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
            // -- 74 --
            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
            // -- 82 --
            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
            b'T', b'E', b'S', b'T', // value = "TEST"
        ];

        validate_dataset_writer(tokens, GROUND_TRUTH);
    }
}
<|endoftext|>


<commit_before>#![feature(step_by)]

extern crate sdl2;
extern crate sdl2_gfx;

use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use std::time::Duration;

mod primitives;
mod circle;

use circle::*;
use primitives::*;

const WIDTH: u32 = 1600;
const HEIGHT: u32 = 800;

fn main() {
    // Initialize SDL2
    let sdl_context   = sdl2::init().unwrap();
    let video_context = sdl_context.video().unwrap();

    // Create window
    let window = video_context.window("Graphics Task 1", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    // Get renderer binded to window
    let mut renderer = window.renderer().build().unwrap();

    // Create FPS manager to precisely control inter-frames delays
    let mut fps_manager = sdl2_gfx::framerate::FPSManager::new();
    fps_manager.set_framerate(10).unwrap();

    // Set draw color and clear the screen
    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    renderer.present();

    // Get event pump
    let mut events = sdl_context.event_pump().unwrap();

    // Set first circle center and radius
    let startx1 = (WIDTH / 100 * 25) as f32;
    let startx2 = (WIDTH / 100 * 75) as f32;
    let starty  = (HEIGHT / 2)       as f32;

    // Set result text coordinates
    let textx = (WIDTH - 200) as i16;
    let texty = 10;
    // Create circles
    let mut bresenham_circles = Vec::with_capacity(131);
    let mut builtin_circles   = Vec::with_capacity(131);

    for r in (4..400).step_by(2) {
        bresenham_circles.push(
            Circle::new(
                Point2D::new(startx1, starty),
                r,
                Color::RGB(0, 255, 0)
            )
        );

        builtin_circles.push(
            Circle::new(
                Point2D::new(startx2, starty),
                r,
                Color::RGB(255, 0, 0)
            )
        );
    }

    // Start main loop
    'main:
    loop {
        // If exit event passed, break the loop
        for event in events.poll_iter() {
            match event {
                Event::Quit {..} => break 'main,
                _ => ()
            }
        }

        // Clear render buffer
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();

        // Plot circles
        let builtin_duration = stopwatch(|| {
            for c in &builtin_circles {
                c.draw_builtin_circle(&renderer);
            }
        });

        let bresenham_duration = stopwatch(|| {
            for c in &bresenham_circles {
                c.draw(&renderer);
            }
        });

        let faster = if bresenham_duration.subsec_nanos() > builtin_duration.subsec_nanos() {
            "BUILTIN"
        } else {
            "MY IMPLEMENTATION"
        };

        // Draw results
        renderer.string(
            textx,
            texty,
            &format!("Bresenham: {} ms", bresenham_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 15,
            &format!("Builtin:   {} ms", builtin_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 30,
            &format!("Faster: {}", faster),
            Color::RGB(255, 255, 255)
        ).unwrap();

        // Present render buffer
        renderer.present();

        // Sleep until the next frame should be rendered
        fps_manager.delay();
    }
}

fn stopwatch<F>(mut closure: F) -> Duration
    where F: FnMut() {
    use std::time::SystemTime;
    let before_time = SystemTime::now();
    closure();
    let after_time  = SystemTime::now();
    after_time.duration_since(before_time).unwrap()
}
<commit_msg>More rusty loops, right vector capacity<commit_after>#![feature(step_by)]

extern crate sdl2;
extern crate sdl2_gfx;

use sdl2_gfx::primitives::DrawRenderer;
use sdl2::pixels::Color;
use sdl2::event::Event;
use std::time::Duration;

mod primitives;
mod circle;

use circle::*;
use primitives::*;

const WIDTH: u32 = 1600;
const HEIGHT: u32 = 800;

fn main() {
    // Initialize SDL2
    let sdl_context   = sdl2::init().unwrap();
    let video_context = sdl_context.video().unwrap();

    // Create window
    let window = video_context.window("Graphics Task 1", WIDTH, HEIGHT)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    // Get renderer binded to window
    let mut renderer = window.renderer().build().unwrap();

    // Create FPS manager to precisely control inter-frames delays
    let mut fps_manager = sdl2_gfx::framerate::FPSManager::new();
    fps_manager.set_framerate(10).unwrap();

    // Set draw color and clear the screen
    renderer.set_draw_color(Color::RGB(0, 0, 0));
    renderer.clear();
    renderer.present();

    // Get event pump
    let mut events = sdl_context.event_pump().unwrap();

    // Set first circle center and radius
    let startx1 = (WIDTH / 100 * 25) as f32;
    let startx2 = (WIDTH / 100 * 75) as f32;
    let starty  = (HEIGHT / 2)       as f32;

    // Set result text coordinates
    let textx = (WIDTH - 200) as i16;
    let texty = 10;
    // Create circles
    let mut bresenham_circles = Vec::with_capacity(200);
    let mut builtin_circles   = Vec::with_capacity(200);

    for r in (4..).step_by(2).take(198) {
        bresenham_circles.push(
            Circle::new(
                Point2D::new(startx1, starty),
                r,
                Color::RGB(0, 255, 0)
            )
        );

        builtin_circles.push(
            Circle::new(
                Point2D::new(startx2, starty),
                r,
                Color::RGB(255, 0, 0)
            )
        );
    }

    // Start main loop
    'main:
    loop {
        // If exit event passed, break the loop
        for event in events.poll_iter() {
            match event {
                Event::Quit {..} => break 'main,
                _ => ()
            }
        }

        // Clear render buffer
        renderer.set_draw_color(Color::RGB(0, 0, 0));
        renderer.clear();

        // Plot circles
        let builtin_duration = stopwatch(|| {
            for c in &builtin_circles {
                c.draw_builtin_circle(&renderer);
            }
        });

        let bresenham_duration = stopwatch(|| {
            for c in &bresenham_circles {
                c.draw(&renderer);
            }
        });

        let faster = if bresenham_duration.subsec_nanos() > builtin_duration.subsec_nanos() {
            "BUILTIN"
        } else {
            "MY IMPLEMENTATION"
        };

        // Draw results
        renderer.string(
            textx,
            texty,
            &format!("Bresenham: {} ms", bresenham_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 15,
            &format!("Builtin:   {} ms", builtin_duration.subsec_nanos() / 1000_000),
            Color::RGB(255, 255, 255)
        ).unwrap();

        renderer.string(
            textx,
            texty + 30,
            &format!("Faster: {}", faster),
            Color::RGB(255, 255, 255)
        ).unwrap();

        // Present render buffer
        renderer.present();

        // Sleep until the next frame should be rendered
        fps_manager.delay();
    }
}

fn stopwatch<F>(mut closure: F) -> Duration
    where F: FnMut() {
    use std::time::SystemTime;
    let before_time = SystemTime::now();
    closure();
    let after_time  = SystemTime::now();
    after_time.duration_since(before_time).unwrap()
}
<|endoftext|>


<commit_before>use bytes::Buf;
use futures_core::stream::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf};

pin_project! {
    /// Convert a [`Stream`] of byte chunks into an [`AsyncRead`].
    ///
    /// This type performs the inverse operation of [`ReaderStream`].
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use tokio::io::{AsyncReadExt, Result};
    /// use tokio_util::io::StreamReader;
    /// # #[tokio::main]
    /// # async fn main() -> std::io::Result<()> {
    ///
    /// // Create a stream from an iterator.
    /// let stream = tokio_stream::iter(vec![
    ///     Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
    ///     Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
    ///     Result::Ok(Bytes::from_static(&[8, 9, 10, 11])),
    /// ]);
    ///
    /// // Convert it to an AsyncRead.
    /// let mut read = StreamReader::new(stream);
    ///
    /// // Read five bytes from the stream.
    /// let mut buf = [0; 5];
    /// read.read_exact(&mut buf).await?;
    /// assert_eq!(buf, [0, 1, 2, 3, 4]);
    ///
    /// // Read the rest of the current chunk.
    /// assert_eq!(read.read(&mut buf).await?, 3);
    /// assert_eq!(&buf[..3], [5, 6, 7]);
    ///
    /// // Read the next chunk.
    /// assert_eq!(read.read(&mut buf).await?, 4);
    /// assert_eq!(&buf[..4], [8, 9, 10, 11]);
    ///
    /// // We have now reached the end.
    /// assert_eq!(read.read(&mut buf).await?, 0);
    ///
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`AsyncRead`]: tokio::io::AsyncRead
    /// [`Stream`]: futures_core::Stream
    /// [`ReaderStream`]: crate::io::ReaderStream
    #[derive(Debug)]
    pub struct StreamReader<S, B> {
        #[pin]
        inner: S,
        chunk: Option<B>,
    }
}

impl<S, B, E> StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    /// Convert a stream of byte chunks into an [`AsyncRead`](tokio::io::AsyncRead).
    ///
    /// The item should be a [`Result`] with the ok variant being something that
    /// implements the [`Buf`] trait (e.g. `Vec<u8>` or `Bytes`). The error
    /// should be convertible into an [io error].
    ///
    /// [`Result`]: std::result::Result
    /// [`Buf`]: bytes::Buf
    /// [io error]: std::io::Error
    pub fn new(stream: S) -> Self {
        Self {
            inner: stream,
            chunk: None,
        }
    }

    /// Do we have a chunk and is it non-empty?
    fn has_chunk(&self) -> bool {
        if let Some(ref chunk) = self.chunk {
            chunk.remaining() > 0
        } else {
            false
        }
    }

    /// Consumes this `StreamReader`, returning a Tuple consisting
    /// of the underlying stream and an Option of the internal buffer,
    /// which is Some in case the buffer contains elements.
    pub fn into_inner_with_chunk(self) -> (S, Option<B>) {
        if self.has_chunk() {
            (self.inner, self.chunk)
        } else {
            (self.inner, None)
        }
    }
}

impl<S, B> StreamReader<S, B> {
    /// Gets a reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_ref(&self) -> &S {
        &self.inner
    }

    /// Gets a mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_mut(&mut self) -> &mut S {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
        self.project().inner
    }

    /// Consumes this `BufWriter`, returning the underlying stream.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    /// If you additionally want access to the internal buffer use
    /// [`into_inner_with_chunk`].
    ///
    /// [`into_inner_with_chunk`]: crate::io::StreamReader::into_inner_with_chunk
    pub fn into_inner(self) -> S {
        self.inner
    }
}

impl<S, B, E> AsyncRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        if buf.remaining() == 0 {
            return Poll::Ready(Ok(()));
        }

        let inner_buf = match self.as_mut().poll_fill_buf(cx) {
            Poll::Ready(Ok(buf)) => buf,
            Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
            Poll::Pending => return Poll::Pending,
        };
        let len = std::cmp::min(inner_buf.len(), buf.remaining());
        buf.put_slice(&inner_buf[..len]);

        self.consume(len);
        Poll::Ready(Ok(()))
    }
}

impl<S, B, E> AsyncBufRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        loop {
            if self.as_mut().has_chunk() {
                // This unwrap is very sad, but it can't be avoided.
                let buf = self.project().chunk.as_ref().unwrap().chunk();
                return Poll::Ready(Ok(buf));
            } else {
                match self.as_mut().project().inner.poll_next(cx) {
                    Poll::Ready(Some(Ok(chunk))) => {
                        // Go around the loop in case the chunk is empty.
                        *self.as_mut().project().chunk = Some(chunk);
                    }
                    Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
                    Poll::Ready(None) => return Poll::Ready(Ok(&[])),
                    Poll::Pending => return Poll::Pending,
                }
            }
        }
    }
    fn consume(self: Pin<&mut Self>, amt: usize) {
        if amt > 0 {
            self.project()
                .chunk
                .as_mut()
                .expect("No chunk present")
                .advance(amt);
        }
    }
}
<commit_msg>io: add error handling example to `StreamReader` (#4975)<commit_after>use bytes::Buf;
use futures_core::stream::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf};

pin_project! {
    /// Convert a [`Stream`] of byte chunks into an [`AsyncRead`].
    ///
    /// This type performs the inverse operation of [`ReaderStream`].
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use tokio::io::{AsyncReadExt, Result};
    /// use tokio_util::io::StreamReader;
    /// # #[tokio::main]
    /// # async fn main() -> std::io::Result<()> {
    ///
    /// // Create a stream from an iterator.
    /// let stream = tokio_stream::iter(vec![
    ///     Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
    ///     Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
    ///     Result::Ok(Bytes::from_static(&[8, 9, 10, 11])),
    /// ]);
    ///
    /// // Convert it to an AsyncRead.
    /// let mut read = StreamReader::new(stream);
    ///
    /// // Read five bytes from the stream.
    /// let mut buf = [0; 5];
    /// read.read_exact(&mut buf).await?;
    /// assert_eq!(buf, [0, 1, 2, 3, 4]);
    ///
    /// // Read the rest of the current chunk.
    /// assert_eq!(read.read(&mut buf).await?, 3);
    /// assert_eq!(&buf[..3], [5, 6, 7]);
    ///
    /// // Read the next chunk.
    /// assert_eq!(read.read(&mut buf).await?, 4);
    /// assert_eq!(&buf[..4], [8, 9, 10, 11]);
    ///
    /// // We have now reached the end.
    /// assert_eq!(read.read(&mut buf).await?, 0);
    ///
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// If the stream produces errors which are not [std::io::Error],
    /// the errors can be converted using [`StreamExt`] to map each
    /// element.
    ///
    /// ```
    /// use bytes::Bytes;
    /// use tokio::io::AsyncReadExt;
    /// use tokio_util::io::StreamReader;
    /// use tokio_stream::StreamExt;
    /// # #[tokio::main]
    /// # async fn main() -> std::io::Result<()> {
    ///
    /// // Create a stream from an iterator, including an error.
    /// let stream = tokio_stream::iter(vec![
    ///     Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
    ///     Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
    ///     Result::Err("Something bad happened!")
    /// ]);
    ///
    /// // Use StreamExt to map the stream and error to a std::io::Error
    /// let stream = stream.map(|result| result.map_err(|err| {
    ///     std::io::Error::new(std::io::ErrorKind::Other, err)
    /// }));
    ///
    /// // Convert it to an AsyncRead.
    /// let mut read = StreamReader::new(stream);
    ///
    /// // Read five bytes from the stream.
    /// let mut buf = [0; 5];
    /// read.read_exact(&mut buf).await?;
    /// assert_eq!(buf, [0, 1, 2, 3, 4]);
    ///
    /// // Read the rest of the current chunk.
    /// assert_eq!(read.read(&mut buf).await?, 3);
    /// assert_eq!(&buf[..3], [5, 6, 7]);
    ///
    /// // Reading the next chunk will produce an error
    /// let error = read.read(&mut buf).await.unwrap_err();
    /// assert_eq!(error.kind(), std::io::ErrorKind::Other);
    /// assert_eq!(error.into_inner().unwrap().to_string(), "Something bad happened!");
    ///
    /// // We have now reached the end.
    /// assert_eq!(read.read(&mut buf).await?, 0);
    ///
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`AsyncRead`]: tokio::io::AsyncRead
    /// [`Stream`]: futures_core::Stream
    /// [`ReaderStream`]: crate::io::ReaderStream
    /// [`StreamExt`]: tokio_stream::StreamExt
    #[derive(Debug)]
    pub struct StreamReader<S, B> {
        #[pin]
        inner: S,
        chunk: Option<B>,
    }
}

impl<S, B, E> StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    /// Convert a stream of byte chunks into an [`AsyncRead`](tokio::io::AsyncRead).
    ///
    /// The item should be a [`Result`] with the ok variant being something that
    /// implements the [`Buf`] trait (e.g. `Vec<u8>` or `Bytes`). The error
    /// should be convertible into an [io error].
    ///
    /// [`Result`]: std::result::Result
    /// [`Buf`]: bytes::Buf
    /// [io error]: std::io::Error
    pub fn new(stream: S) -> Self {
        Self {
            inner: stream,
            chunk: None,
        }
    }

    /// Do we have a chunk and is it non-empty?
    fn has_chunk(&self) -> bool {
        if let Some(ref chunk) = self.chunk {
            chunk.remaining() > 0
        } else {
            false
        }
    }

    /// Consumes this `StreamReader`, returning a Tuple consisting
    /// of the underlying stream and an Option of the internal buffer,
    /// which is Some in case the buffer contains elements.
    pub fn into_inner_with_chunk(self) -> (S, Option<B>) {
        if self.has_chunk() {
            (self.inner, self.chunk)
        } else {
            (self.inner, None)
        }
    }
}

impl<S, B> StreamReader<S, B> {
    /// Gets a reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_ref(&self) -> &S {
        &self.inner
    }

    /// Gets a mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_mut(&mut self) -> &mut S {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
        self.project().inner
    }

    /// Consumes this `BufWriter`, returning the underlying stream.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    /// If you additionally want access to the internal buffer use
    /// [`into_inner_with_chunk`].
    ///
    /// [`into_inner_with_chunk`]: crate::io::StreamReader::into_inner_with_chunk
    pub fn into_inner(self) -> S {
        self.inner
    }
}

impl<S, B, E> AsyncRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        if buf.remaining() == 0 {
            return Poll::Ready(Ok(()));
        }

        let inner_buf = match self.as_mut().poll_fill_buf(cx) {
            Poll::Ready(Ok(buf)) => buf,
            Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
            Poll::Pending => return Poll::Pending,
        };
        let len = std::cmp::min(inner_buf.len(), buf.remaining());
        buf.put_slice(&inner_buf[..len]);

        self.consume(len);
        Poll::Ready(Ok(()))
    }
}

impl<S, B, E> AsyncBufRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        loop {
            if self.as_mut().has_chunk() {
                // This unwrap is very sad, but it can't be avoided.
                let buf = self.project().chunk.as_ref().unwrap().chunk();
                return Poll::Ready(Ok(buf));
            } else {
                match self.as_mut().project().inner.poll_next(cx) {
                    Poll::Ready(Some(Ok(chunk))) => {
                        // Go around the loop in case the chunk is empty.
                        *self.as_mut().project().chunk = Some(chunk);
                    }
                    Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
                    Poll::Ready(None) => return Poll::Ready(Ok(&[])),
                    Poll::Pending => return Poll::Pending,
                }
            }
        }
    }
    fn consume(self: Pin<&mut Self>, amt: usize) {
        if amt > 0 {
            self.project()
                .chunk
                .as_mut()
                .expect("No chunk present")
                .advance(amt);
        }
    }
}
<|endoftext|>


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

use crate::message_dyn::MessageDyn;
use crate::message_field::MessageField;
use crate::message_full::MessageFull;
use crate::reflect::acc::v2::AccessorV2;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::runtime_types::RuntimeTypeWithDeref;
use crate::reflect::value::value_ref::ReflectValueMut;
use crate::reflect::ProtobufValue;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::EnumFull;
use crate::EnumOrUnknown;

pub(crate) mod oneof;

/// Option-like objects
#[doc(hidden)]
trait OptionLike<T> {
    fn as_option_ref(&self) -> Option<&T>;
    fn as_option_mut(&mut self) -> Option<&mut T>;
    fn set_value(&mut self, value: T);
}

impl<T> OptionLike<T> for Option<T> {
    fn as_option_ref(&self) -> Option<&T> {
        self.as_ref()
    }

    fn as_option_mut(&mut self) -> Option<&mut T> {
        self.as_mut()
    }

    fn set_value(&mut self, value: T) {
        *self = Some(value);
    }
}

impl<T> OptionLike<T> for MessageField<T> {
    fn as_option_ref(&self) -> Option<&T> {
        self.as_ref()
    }

    fn as_option_mut(&mut self) -> Option<&mut T> {
        self.as_mut()
    }

    fn set_value(&mut self, value: T) {
        *self = MessageField::some(value);
    }
}

/// This trait should not be used directly, use `FieldDescriptor` instead
pub(crate) trait SingularFieldAccessor: Send + Sync + 'static {
    fn get_field<'a>(&self, m: &'a dyn MessageDyn) -> Option<ReflectValueRef<'a>>;
    fn mut_field_or_default<'a>(&self, m: &'a mut dyn MessageDyn) -> ReflectValueMut<'a>;
    fn set_field(&self, m: &mut dyn MessageDyn, value: ReflectValueBox);
}

pub(crate) struct SingularFieldAccessorHolder {
    pub accessor: Box<dyn SingularFieldAccessor>,
}

impl SingularFieldAccessorHolder {
    fn new<M>(
        get_field: impl for<'a> Fn(&'a M) -> Option<ReflectValueRef<'a>> + Send + Sync + 'static,
        mut_field_or_default: impl for<'a> Fn(&'a mut M) -> ReflectValueMut<'a> + Send + Sync + 'static,
        set_field: impl Fn(&mut M, ReflectValueBox) + Send + Sync + 'static,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
    {
        struct Impl<M, G, H, S> {
            get_field: G,
            mut_field_or_default: H,
            set_field: S,
            _marker: marker::PhantomData<M>,
        }

        impl<M, G, H, S> SingularFieldAccessor for Impl<M, G, H, S>
        where
            M: MessageFull,
            G: for<'a> Fn(&'a M) -> Option<ReflectValueRef<'a>> + Send + Sync + 'static,
            H: for<'a> Fn(&'a mut M) -> ReflectValueMut<'a> + Send + Sync + 'static,
            S: Fn(&mut M, ReflectValueBox) + Send + Sync + 'static,
        {
            fn get_field<'a>(&self, m: &'a dyn MessageDyn) -> Option<ReflectValueRef<'a>> {
                (self.get_field)(m.downcast_ref::<M>().unwrap())
            }

            fn mut_field_or_default<'a>(&self, m: &'a mut dyn MessageDyn) -> ReflectValueMut<'a> {
                (self.mut_field_or_default)(m.downcast_mut::<M>().unwrap())
            }

            fn set_field(&self, m: &mut dyn MessageDyn, value: ReflectValueBox) {
                (self.set_field)(m.downcast_mut::<M>().unwrap(), value);
            }
        }

        SingularFieldAccessorHolder {
            accessor: Box::new(Impl {
                get_field,
                mut_field_or_default,
                set_field,
                _marker: marker::PhantomData,
            }),
        }
    }

    fn new_get_mut<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a V,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut V,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
    {
        Self::new(
            move |m| {
                let v = (get_field)(m);
                if V::is_non_zero(v) {
                    Some(V::as_ref(v))
                } else {
                    None
                }
            },
            move |m| V::as_mut((mut_field)(m)),
            move |m, value| V::set_from_value_box((mut_field)(m), value),
        )
    }

    fn new_get_option_mut_option<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a Option<V>,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut Option<V>,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
    {
        Self::new(
            move |m| (get_field)(m).as_option_ref().map(V::as_ref),
            move |_m| unimplemented!(),
            move |m, value| (mut_field)(m).set_value(V::from_value_box(value).expect("wrong type")),
        )
    }

    fn new_get_mut_message<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a MessageField<V>,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut MessageField<V>,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: MessageFull,
    {
        Self::new(
            move |m| (get_field)(m).as_option_ref().map(V::as_ref),
            move |m| {
                let option = (mut_field)(m);
                if option.as_option_ref().is_none() {
                    option.set_value(V::default());
                }
                V::as_mut(option.as_option_mut().unwrap())
            },
            move |m, value| (mut_field)(m).set_value(V::from_value_box(value).expect("wrong type")),
        )
    }

    pub(crate) fn new_get_option_set_enum<M, E>(
        get: fn(&M) -> Option<EnumOrUnknown<E>>,
        set: fn(&mut M, EnumOrUnknown<E>),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        E: EnumFull,
    {
        Self::new(
            move |m| {
                let value = (get)(m);
                value.map(|v| ReflectValueRef::Enum(E::enum_descriptor_static(), v.value()))
            },
            |_m| panic!("cannot get mutable pointer"),
            move |m, value| match value {
                ReflectValueBox::Enum(e, v) => {
                    assert_eq!(E::enum_descriptor_static(), e);
                    (set)(m, EnumOrUnknown::from_i32(v));
                }
                _ => panic!("expecting enum value"),
            },
        )
    }

    pub(crate) fn new_has_get_set<M, V>(
        has: fn(&M) -> bool,
        get: fn(&M) -> V,
        set: fn(&mut M, V),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue + Copy,
    {
        Self::new(
            move |m| {
                if (has)(m) {
                    Some(V::into_static_value_ref((get)(m)))
                } else {
                    None
                }
            },
            |_m| unimplemented!(),
            move |m, value| (set)(m, value.downcast::<V>().expect("wrong type")),
        )
    }

    pub(crate) fn new_has_get_set_deref<M, V>(
        has: fn(&M) -> bool,
        get: for<'a> fn(&'a M) -> &'a <V::RuntimeType as RuntimeTypeWithDeref>::DerefTarget,
        set: fn(&mut M, V),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
        V::RuntimeType: RuntimeTypeWithDeref,
    {
        Self::new(
            move |m| {
                if (has)(m) {
                    Some(<V::RuntimeType as RuntimeTypeWithDeref>::deref_as_ref(
                        (get)(m),
                    ))
                } else {
                    None
                }
            },
            |_m| unimplemented!(),
            move |m, value| (set)(m, value.downcast::<V>().expect("message")),
        )
    }

    pub(crate) fn new_has_get_mut_set<M, F>(
        has_field: fn(&M) -> bool,
        get_field: for<'a> fn(&'a M) -> &'a F,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut F,
        set_field: fn(&mut M, F),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        F: MessageFull,
    {
        Self::new(
            move |m| {
                if (has_field)(m) {
                    Some(F::as_ref((get_field)(m)))
                } else {
                    None
                }
            },
            move |m| F::as_mut((mut_field)(m)),
            move |m, value| (set_field)(m, value.downcast::<F>().expect("message")),
        )
    }
}

impl<'a> fmt::Debug for SingularFieldAccessorHolder {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SingularFieldAccessorHolder").finish()
    }
}

/// Make accessor for `SingularPtrField`
pub fn make_message_field_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a MessageField<V>,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut MessageField<V>,
) -> FieldAccessor
where
    M: MessageFull,
    V: MessageFull,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_mut_message(
            get_field, mut_field,
        )),
    )
}

/// Make accessor for `Option<C>` field
pub fn make_option_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a Option<V>,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut Option<V>,
) -> FieldAccessor
where
    M: MessageFull,
    V: ProtobufValue,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_option_mut_option(
            get_field, mut_field,
        )),
    )
}

/// Make accessor for simple field
pub fn make_simpler_field_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a V,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut V,
) -> FieldAccessor
where
    M: MessageFull,
    V: ProtobufValue,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_mut(
            get_field, mut_field,
        )),
    )
}
<commit_msg>More dead code<commit_after>use std::fmt;
use std::marker;

use crate::message_dyn::MessageDyn;
use crate::message_field::MessageField;
use crate::message_full::MessageFull;
use crate::reflect::acc::v2::AccessorV2;
use crate::reflect::acc::FieldAccessor;
use crate::reflect::runtime_types::RuntimeTypeWithDeref;
use crate::reflect::value::value_ref::ReflectValueMut;
use crate::reflect::ProtobufValue;
use crate::reflect::ReflectValueBox;
use crate::reflect::ReflectValueRef;
use crate::EnumFull;
use crate::EnumOrUnknown;

pub(crate) mod oneof;

/// This trait should not be used directly, use `FieldDescriptor` instead
pub(crate) trait SingularFieldAccessor: Send + Sync + 'static {
    fn get_field<'a>(&self, m: &'a dyn MessageDyn) -> Option<ReflectValueRef<'a>>;
    fn mut_field_or_default<'a>(&self, m: &'a mut dyn MessageDyn) -> ReflectValueMut<'a>;
    fn set_field(&self, m: &mut dyn MessageDyn, value: ReflectValueBox);
}

pub(crate) struct SingularFieldAccessorHolder {
    pub accessor: Box<dyn SingularFieldAccessor>,
}

impl SingularFieldAccessorHolder {
    fn new<M>(
        get_field: impl for<'a> Fn(&'a M) -> Option<ReflectValueRef<'a>> + Send + Sync + 'static,
        mut_field_or_default: impl for<'a> Fn(&'a mut M) -> ReflectValueMut<'a> + Send + Sync + 'static,
        set_field: impl Fn(&mut M, ReflectValueBox) + Send + Sync + 'static,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
    {
        struct Impl<M, G, H, S> {
            get_field: G,
            mut_field_or_default: H,
            set_field: S,
            _marker: marker::PhantomData<M>,
        }

        impl<M, G, H, S> SingularFieldAccessor for Impl<M, G, H, S>
        where
            M: MessageFull,
            G: for<'a> Fn(&'a M) -> Option<ReflectValueRef<'a>> + Send + Sync + 'static,
            H: for<'a> Fn(&'a mut M) -> ReflectValueMut<'a> + Send + Sync + 'static,
            S: Fn(&mut M, ReflectValueBox) + Send + Sync + 'static,
        {
            fn get_field<'a>(&self, m: &'a dyn MessageDyn) -> Option<ReflectValueRef<'a>> {
                (self.get_field)(m.downcast_ref::<M>().unwrap())
            }

            fn mut_field_or_default<'a>(&self, m: &'a mut dyn MessageDyn) -> ReflectValueMut<'a> {
                (self.mut_field_or_default)(m.downcast_mut::<M>().unwrap())
            }

            fn set_field(&self, m: &mut dyn MessageDyn, value: ReflectValueBox) {
                (self.set_field)(m.downcast_mut::<M>().unwrap(), value);
            }
        }

        SingularFieldAccessorHolder {
            accessor: Box::new(Impl {
                get_field,
                mut_field_or_default,
                set_field,
                _marker: marker::PhantomData,
            }),
        }
    }

    fn new_get_mut<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a V,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut V,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
    {
        Self::new(
            move |m| {
                let v = (get_field)(m);
                if V::is_non_zero(v) {
                    Some(V::as_ref(v))
                } else {
                    None
                }
            },
            move |m| V::as_mut((mut_field)(m)),
            move |m, value| V::set_from_value_box((mut_field)(m), value),
        )
    }

    fn new_get_option_mut_option<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a Option<V>,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut Option<V>,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
    {
        Self::new(
            move |m| (get_field)(m).as_ref().map(V::as_ref),
            move |_m| unimplemented!(),
            move |m, value| *(mut_field)(m) = Some(V::from_value_box(value).expect("wrong type")),
        )
    }

    fn new_get_mut_message<M, V>(
        get_field: for<'a> fn(&'a M) -> &'a MessageField<V>,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut MessageField<V>,
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: MessageFull,
    {
        Self::new(
            move |m| (get_field)(m).as_ref().map(V::as_ref),
            move |m| {
                let option = (mut_field)(m);
                if option.as_ref().is_none() {
                    *option = MessageField::some(V::default());
                }
                V::as_mut(option.as_mut().unwrap())
            },
            move |m, value| {
                *(mut_field)(m) = MessageField::some(V::from_value_box(value).expect("wrong type"))
            },
        )
    }

    pub(crate) fn new_get_option_set_enum<M, E>(
        get: fn(&M) -> Option<EnumOrUnknown<E>>,
        set: fn(&mut M, EnumOrUnknown<E>),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        E: EnumFull,
    {
        Self::new(
            move |m| {
                let value = (get)(m);
                value.map(|v| ReflectValueRef::Enum(E::enum_descriptor_static(), v.value()))
            },
            |_m| panic!("cannot get mutable pointer"),
            move |m, value| match value {
                ReflectValueBox::Enum(e, v) => {
                    assert_eq!(E::enum_descriptor_static(), e);
                    (set)(m, EnumOrUnknown::from_i32(v));
                }
                _ => panic!("expecting enum value"),
            },
        )
    }

    pub(crate) fn new_has_get_set<M, V>(
        has: fn(&M) -> bool,
        get: fn(&M) -> V,
        set: fn(&mut M, V),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue + Copy,
    {
        Self::new(
            move |m| {
                if (has)(m) {
                    Some(V::into_static_value_ref((get)(m)))
                } else {
                    None
                }
            },
            |_m| unimplemented!(),
            move |m, value| (set)(m, value.downcast::<V>().expect("wrong type")),
        )
    }

    pub(crate) fn new_has_get_set_deref<M, V>(
        has: fn(&M) -> bool,
        get: for<'a> fn(&'a M) -> &'a <V::RuntimeType as RuntimeTypeWithDeref>::DerefTarget,
        set: fn(&mut M, V),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        V: ProtobufValue,
        V::RuntimeType: RuntimeTypeWithDeref,
    {
        Self::new(
            move |m| {
                if (has)(m) {
                    Some(<V::RuntimeType as RuntimeTypeWithDeref>::deref_as_ref(
                        (get)(m),
                    ))
                } else {
                    None
                }
            },
            |_m| unimplemented!(),
            move |m, value| (set)(m, value.downcast::<V>().expect("message")),
        )
    }

    pub(crate) fn new_has_get_mut_set<M, F>(
        has_field: fn(&M) -> bool,
        get_field: for<'a> fn(&'a M) -> &'a F,
        mut_field: for<'a> fn(&'a mut M) -> &'a mut F,
        set_field: fn(&mut M, F),
    ) -> SingularFieldAccessorHolder
    where
        M: MessageFull,
        F: MessageFull,
    {
        Self::new(
            move |m| {
                if (has_field)(m) {
                    Some(F::as_ref((get_field)(m)))
                } else {
                    None
                }
            },
            move |m| F::as_mut((mut_field)(m)),
            move |m, value| (set_field)(m, value.downcast::<F>().expect("message")),
        )
    }
}

impl<'a> fmt::Debug for SingularFieldAccessorHolder {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("SingularFieldAccessorHolder").finish()
    }
}

/// Make accessor for `SingularPtrField`
pub fn make_message_field_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a MessageField<V>,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut MessageField<V>,
) -> FieldAccessor
where
    M: MessageFull,
    V: MessageFull,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_mut_message(
            get_field, mut_field,
        )),
    )
}

/// Make accessor for `Option<C>` field
pub fn make_option_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a Option<V>,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut Option<V>,
) -> FieldAccessor
where
    M: MessageFull,
    V: ProtobufValue,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_option_mut_option(
            get_field, mut_field,
        )),
    )
}

/// Make accessor for simple field
pub fn make_simpler_field_accessor<M, V>(
    name: &'static str,
    get_field: for<'a> fn(&'a M) -> &'a V,
    mut_field: for<'a> fn(&'a mut M) -> &'a mut V,
) -> FieldAccessor
where
    M: MessageFull,
    V: ProtobufValue,
{
    FieldAccessor::new(
        name,
        AccessorV2::Singular(SingularFieldAccessorHolder::new_get_mut(
            get_field, mut_field,
        )),
    )
}
<|endoftext|>