<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::result::Result;
use std::path::{Path, PathBuf};
use std::convert::From;
use std::convert::Into;

use regex::Regex;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
// #[derive(Display)]
pub enum FileIDType {
    NONE,
    UUID,
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        let s = match self {
            FileIDType::UUID => "UUID",
            FileIDType::NONE => "",
        };

        String::from(s)
    }

}

#[derive(Clone)]
pub struct FileID {
    id: Option<String>,
    id_type: FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: String) -> FileID {
        FileID {
            id: Some(id),
            id_type: id_type,
        }
    }

    pub fn is_valid(&self) -> bool {
        self.id.is_some()
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        if let Some(id) = self.id {
            id.clone()
        } else {
            String::from("INVALID")
        }
    }

}

impl From<String> for FileID {

    fn from(s: String) -> FileID {
        FileID::from(&s)
    }

}

impl<'a> From<&'a String> for FileID {

    fn from(string: &'a String) -> FileID {

        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            let idtype = select_id_type_from_str(hashname);
            match idtype {
                FileIDType::NONE => hash = "INVALID",
                _ => {},
            }

            Some(FileID::new(idtype, String::from(hash)))
        }).unwrap_or({
            debug!("Did not match");
            FileID {
                id_type: FileIDType::NONE,
                id: None,
            }
        })
    }

}

impl From<PathBuf> for FileID {

    fn from(s: PathBuf) -> FileID {
        unimplemented!()
    }

}

impl<'a> From<&'a PathBuf> for FileID {

    fn from(s: &'a PathBuf) -> FileID {
        unimplemented!()
    }

}

pub struct FileIDError {
    summary: String,
    descrip: String,
}

impl FileIDError {

    pub fn new(s: String, d: String) -> FileIDError {
        FileIDError {
            summary: s,
            descrip: d,
        }
    }

}

impl<'a> Error for FileIDError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'\n{}", self.summary, self.descrip);
        Ok(())
    }

}

impl<'a> Display for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'", self.summary);
        Ok(())
    }

}

fn select_id_type_from_str(s: &str) -> FileIDType {
    match s {
        "UUID"  => FileIDType::UUID,
        _       => FileIDType::NONE,
    }
}

pub type FileIDResult = Result<FileID, FileIDError>;

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<commit_msg>Impl From<String> for FileIDType<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;
use std::result::Result;
use std::path::{Path, PathBuf};
use std::convert::From;
use std::convert::Into;

use regex::Regex;

#[derive(Debug)]
#[derive(Clone)]
#[derive(PartialEq)]
#[derive(Eq)]
// #[derive(Display)]
pub enum FileIDType {
    NONE,
    UUID,
}

impl Into<String> for FileIDType {

    fn into(self) -> String {
        let s = match self {
            FileIDType::UUID => "UUID",
            FileIDType::NONE => "",
        };

        String::from(s)
    }

}

impl From<String> for FileIDType {

    fn from(s: String) -> FileIDType {
        match &s[..] {
            "UUID"  => FileIDType::UUID,
            _       => FileIDType::NONE,
        }
    }

}

#[derive(Clone)]
pub struct FileID {
    id: Option<String>,
    id_type: FileIDType,
}

impl FileID {

    pub fn new(id_type: FileIDType, id: String) -> FileID {
        FileID {
            id: Some(id),
            id_type: id_type,
        }
    }

    pub fn is_valid(&self) -> bool {
        self.id.is_some()
    }

    pub fn get_type(&self) -> FileIDType {
        self.id_type.clone()
    }

}

impl Debug for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Display for FileID {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileID[{:?}]: {:?}",
               self.id_type,
               self.id);
        Ok(())
    }

}

impl Into<String> for FileID {

    fn into(self) -> String {
        if let Some(id) = self.id {
            id.clone()
        } else {
            String::from("INVALID")
        }
    }

}

impl From<String> for FileID {

    fn from(s: String) -> FileID {
        FileID::from(&s)
    }

}

impl<'a> From<&'a String> for FileID {

    fn from(string: &'a String) -> FileID {

        let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
        let s = string.split("/").last().unwrap_or("");

        debug!("Regex build: {:?}", regex);
        debug!("Matching string: '{}'", s);
        regex.captures(s).and_then(|capts| {
            // first one is the whole string, index 1-N are the matches.
            if capts.len() != 5 {
                debug!("Matches, but not expected number of groups");
                return None;
            }
            debug!("Matches: {}", capts.len());

            let modname     = capts.at(1).unwrap();
            let hashname    = capts.at(2).unwrap();
            let mut hash    = capts.at(3).unwrap();

            debug!("Destructure FilePath to ID:");
            debug!("                  FilePath: {:?}", s);
            debug!("               Module Name: {:?}", modname);
            debug!("                 Hash Name: {:?}", hashname);
            debug!("                      Hash: {:?}", hash);

            let idtype = select_id_type_from_str(hashname);
            match idtype {
                FileIDType::NONE => hash = "INVALID",
                _ => {},
            }

            Some(FileID::new(idtype, String::from(hash)))
        }).unwrap_or({
            debug!("Did not match");
            FileID {
                id_type: FileIDType::NONE,
                id: None,
            }
        })
    }

}

impl From<PathBuf> for FileID {

    fn from(s: PathBuf) -> FileID {
        unimplemented!()
    }

}

impl<'a> From<&'a PathBuf> for FileID {

    fn from(s: &'a PathBuf) -> FileID {
        unimplemented!()
    }

}

pub struct FileIDError {
    summary: String,
    descrip: String,
}

impl FileIDError {

    pub fn new(s: String, d: String) -> FileIDError {
        FileIDError {
            summary: s,
            descrip: d,
        }
    }

}

impl<'a> Error for FileIDError {

    fn description(&self) -> &str {
        &self.summary[..]
    }

    fn cause(&self) -> Option<&Error> {
        None
    }

}

impl<'a> Debug for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'\n{}", self.summary, self.descrip);
        Ok(())
    }

}

impl<'a> Display for FileIDError {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt, "FileIDError: '{}'", self.summary);
        Ok(())
    }

}

fn select_id_type_from_str(s: &str) -> FileIDType {
    match s {
        "UUID"  => FileIDType::UUID,
        _       => FileIDType::NONE,
    }
}

pub type FileIDResult = Result<FileID, FileIDError>;

#[cfg(test)]
mod test {

    use super::{FileID, FileIDType};

    #[test]
    fn file_id_from_string() {
        setup_logger();

        let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
        let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
        let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");

        let id1 = FileID::from(s1);
        let id2 = FileID::from(s2);
        let id3 = FileID::from(s3);

        println!("Id 1 : {:?}", id1);
        println!("Id 2 : {:?}", id2);
        println!("Id 3 : {:?}", id3);

        assert_eq!(FileIDType::UUID, id1.get_type());
        assert_eq!(FileIDType::UUID, id2.get_type());
        assert_eq!(FileIDType::NONE, id3.get_type());

        let f1 : String = id1.into();
        let f2 : String = id2.into();
        let f3 : String = id3.into();

        assert_eq!(String::from("some-id"), f1);
        assert_eq!(String::from("some-id"), f2);
        assert_eq!(String::from("INVALID"), f3);
    }

    fn setup_logger() {
        extern crate log;
        use log::{LogLevelFilter, set_logger};
        use runtime::ImagLogger;

        log::set_logger(|max_log_lvl| {
            let lvl = LogLevelFilter::Debug;
            max_log_lvl.set(lvl);
            Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
        });
        debug!("Init logger for test");
    }

}

<|endoftext|>


<commit_before>use std::collections::{HashMap};
use std::thread;
use std::sync::{Arc};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crossbeam::sync::{MsQueue};
use glium::glutin::{WindowBuilder, CursorState, get_primary_monitor};
use glium::{DisplayBuild};
use mioco;
use mioco::{Mioco, Config};
use mioco::sync::{Mutex, RwLock};
use mioco::sync::mpsc::{Receiver, Sender, channel};
use time;

use input::{InputContext, InputFrame};
use physics::{PhysicsContext, PhysicsFrame};
use render::{RenderContext, RenderFrame, RenderProcessor, RenderToken};
use scheduler::{BalancingScheduler};

// TODO: try to remove Arc dependency
//
// job should have priority
// job should have estimated length
// 		s.t. the gl thread only does short, high priority tasks
//

// --- THREADING MODEL ---
// n worker threads where n is the number of cores on the system
// 1 lightweight event processing / frame_kicking / gl thread (TODO: minimize gl tasks to actual gl calls)
//

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

pub fn init() {
	const INPUT_FREQUENCY: u64 = 120;
	const RENDER_FREQUENCY: u64 = 60;

	let window_size = get_primary_monitor().get_dimensions();
	let window_size = (window_size.0/2, window_size.1/2); // FIXME: macbook scaling bs
	let aspect_ratio = (window_size.0 as f64) / (window_size.1 as f64);

	let glium_context = WindowBuilder::new()
		.with_dimensions(window_size.0, window_size.1)
		.with_title(format!("SG"))
		.with_depth_buffer(24)
		.with_decorations(false)
		.build_glium().unwrap();

	glium_context.get_window().unwrap().set_cursor_state(CursorState::Grab).ok();

	let q = Arc::new(MsQueue::new());

	let (render_tokens_sender, render_tokens_receiver) = channel::<RenderToken>();
	let context = Arc::new(
		Context {
			exit: AtomicBool::new(false),
			input_senders: MsQueue::new(),
			last_physics_frame: RwLock::new(Arc::new(PhysicsFrame::frame_zero(aspect_ratio))),
			render_tokens_length: AtomicUsize::new(0),
			physics_continuations: Arc::new(Mutex::new(HashMap::new())),

			input:   InputContext  ::new(),
			physics: PhysicsContext::new(),
			render:  RenderContext ::new(q.clone(), window_size),
		}
	);

	{
		let context = context.clone();
		thread::spawn(move || { spawn_coroutines(context, render_tokens_receiver); });
	}

	let mut render_processor = RenderProcessor::new(q, glium_context);
	let mut last_input_time = time::precise_time_ns() / 1_000_000;
	let mut last_render_time = last_input_time;

	// TODO: may need to be refactored to handle system events more frequently/(lower max latency)
	//
	while let Some(events) = render_processor.handle_system_events() {
		if context.exit.load(Ordering::Relaxed) { break }

		context.input.post_input_events(events);

		let time = time::precise_time_ns() / 1_000_000;

		while last_input_time < time {
			if let Some(sender) = context.input_senders.try_pop() {
				sender.send(()).unwrap();
				last_input_time += 1_000 / INPUT_FREQUENCY;
			} else {
				break;
			}
		}

		while last_render_time < time {
			const FIF_RENDER: usize = 1;
			let length = context.render_tokens_length.load(Ordering::Acquire);
			if length < FIF_RENDER {
				context.render_tokens_length.fetch_add(1, Ordering::Release);
				render_tokens_sender.send(RenderToken).unwrap();
				last_render_time += 1_000 / RENDER_FREQUENCY;
			}
		}

		render_processor.handle_render_commands();

		thread::yield_now();
	}
}

struct Continuation {
	id: u64,
	req_count: AtomicUsize,
	reqs: MsQueue<Arc<Result>>,
}

enum Result { InputFrame(Arc<InputFrame>), PhysicsFrame(Arc<PhysicsFrame>) }

pub struct Context {
	exit: AtomicBool,
	input_senders: MsQueue<Sender<()>>,
	last_physics_frame: RwLock<Arc<PhysicsFrame>>,
	physics_continuations: Arc<Mutex<HashMap<u64, Arc<Continuation>>>>,
	render_tokens_length: AtomicUsize,

	pub input: InputContext,
	pub physics: PhysicsContext,
	pub render: RenderContext,
}

impl Context {
	pub fn input_signal(&self) -> Receiver<()> {
		let (sender, receiver) = channel();
		self.input_senders.push(sender);
		receiver
	}
}

fn input_entry(context: Arc<Context>, coroutine: Arc<Continuation>) {
	let start_signal = context.input_signal();
	start_signal.recv().unwrap();

	let last_input_frame = {
		match *coroutine.reqs.pop() {
			Result::InputFrame(ref data) => data.clone(),
			_ => unreachable!()
		}
	};

	let input_frame = InputFrame::new(context.clone(), last_input_frame);
	let result = Arc::new(Result::InputFrame(Arc::new(input_frame)));

	{
		let q = MsQueue::new();
		q.push(result.clone());
		let context = context.clone();
		let continuation = Arc::new(Continuation {
			id:        coroutine.id + 1,
			req_count: AtomicUsize::new(0),
			reqs:      q,
		});
		mioco::spawn(move|| input_entry(context, continuation));
	}
	{
		let continuation = {
			let mut map = context.physics_continuations.lock().unwrap();
			map.entry(coroutine.id).or_insert(Arc::new(Continuation {
				id:        coroutine.id,
				req_count: AtomicUsize::new(2),
				reqs:      MsQueue::new(),
			})).clone()
		};
		continuation.reqs.push(result.clone());
		let req_count = continuation.req_count.fetch_sub(1, Ordering::Relaxed);
		if req_count == 1 {
			let context = context.clone();
			let continuation = context.physics_continuations.lock().unwrap().remove(&coroutine.id).unwrap();

			mioco::spawn(move||physics_entry(context, continuation));
		}
	}
}

fn physics_entry(context: Arc<Context>, coroutine: Arc<Continuation>) {
	let (last_input_frame, last_physics_frame) = {
		let mut input_frame = Arc::new(InputFrame::frame_zero());
		let mut physics_frame = Arc::new(PhysicsFrame::frame_zero(context.render.aspect_ratio()));

		for _ in 0..2 {
			match *coroutine.reqs.pop() {
				Result::InputFrame(ref data) => input_frame = data.clone(),
				Result::PhysicsFrame(ref data) => physics_frame = data.clone(),
			};
		}
		(input_frame, physics_frame)
	};

	let physics_frame = Arc::new(PhysicsFrame::new(context.clone(), last_physics_frame, last_input_frame));
	let result = Arc::new(Result::PhysicsFrame(physics_frame.clone()));

	{ // TODO: do something better (that doesnt potentially block the sender)
		let latest_frame = context.last_physics_frame.read().unwrap().clone();
		if physics_frame.frame_counter > latest_frame.frame_counter {
			let mut reference = context.last_physics_frame.write().unwrap();
			*reference = physics_frame.clone();
		}
	}

	{
		let continuation = {
			let mut map = context.physics_continuations.lock().unwrap();
			map.entry(coroutine.id + 1).or_insert(Arc::new(Continuation {
				id:        coroutine.id + 1,
				req_count: AtomicUsize::new(2),
				reqs:      MsQueue::new(),
			})).clone()
		};
		continuation.reqs.push(result.clone());
		let req_count = continuation.req_count.fetch_sub(1, Ordering::Relaxed);
		if req_count == 1 {
		let context = context.clone();
		let continuation = context.physics_continuations.lock().unwrap().remove(&(coroutine.id + 1)).unwrap();
			mioco::spawn(move||physics_entry(context, continuation));
		}
	}
}

fn render_entry(context: Arc<Context>, render_tokens: Receiver<RenderToken>) {
	while !context.exit.load(Ordering::Relaxed) {
		render_tokens.recv().unwrap();

		let physics_frame = context.last_physics_frame.read().unwrap().clone();

		// TODO: don't render the same physics_frame twice

		let render_frame = {
			let context = context.clone();
			RenderFrame::new(context, physics_frame)
		};

		context.render.q.push(render_frame);
		context.render_tokens_length.fetch_sub(1, Ordering::Release);
	}
}

fn spawn_coroutines(context: Arc<Context>, render_tokens: Receiver<RenderToken>) {
	const NUM_THREADS: usize = 4;

	let mut config = Config::new();
	config.set_thread_num(NUM_THREADS);
	config.set_scheduler(Box::new(BalancingScheduler::new(NUM_THREADS)));

	{
		let result = Arc::new(Result::PhysicsFrame(Arc::new(PhysicsFrame::frame_zero(context.render.aspect_ratio()))));
		let q = MsQueue::new();
		q.push(result);
			context.physics_continuations.lock().unwrap().insert(1, Arc::new(Continuation {
			id: 1,
			req_count: AtomicUsize::new(1),
			reqs: q,
		}));
	}

	Mioco::new_configured(config).start(move|| {
		{
			let result = Arc::new(Result::InputFrame(Arc::new(InputFrame::frame_zero())));
			let q = MsQueue::new();
			q.push(result);
			let continuation = Arc::new(Continuation {
				id:        1,
				req_count: AtomicUsize::new(0),
				reqs:      q,
			});
			let context = context.clone();
			mioco::spawn(move||input_entry(context, continuation));
		}
		{ // for each render frame in flight
			let context = context.clone();
			mioco::spawn(move||render_entry(context, render_tokens));
		}
	}).unwrap();
}

<commit_msg>Disable mioco catching panics<commit_after>use std::collections::{HashMap};
use std::thread;
use std::sync::{Arc};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};

use crossbeam::sync::{MsQueue};
use glium::glutin::{WindowBuilder, CursorState, get_primary_monitor};
use glium::{DisplayBuild};
use mioco;
use mioco::{Mioco, Config};
use mioco::sync::{Mutex, RwLock};
use mioco::sync::mpsc::{Receiver, Sender, channel};
use time;

use input::{InputContext, InputFrame};
use physics::{PhysicsContext, PhysicsFrame};
use render::{RenderContext, RenderFrame, RenderProcessor, RenderToken};
use scheduler::{BalancingScheduler};

// TODO: try to remove Arc dependency
//
// job should have priority
// job should have estimated length
// 		s.t. the gl thread only does short, high priority tasks
//

// --- THREADING MODEL ---
// n worker threads where n is the number of cores on the system
// 1 lightweight event processing / frame_kicking / gl thread (TODO: minimize gl tasks to actual gl calls)
//

unsafe impl Send for Context {}
unsafe impl Sync for Context {}

pub fn init() {
	const INPUT_FREQUENCY: u64 = 120;
	const RENDER_FREQUENCY: u64 = 60;

	let window_size = get_primary_monitor().get_dimensions();
	let window_size = (window_size.0/2, window_size.1/2); // FIXME: macbook scaling bs
	let aspect_ratio = (window_size.0 as f64) / (window_size.1 as f64);

	let glium_context = WindowBuilder::new()
		.with_dimensions(window_size.0, window_size.1)
		.with_title(format!("SG"))
		.with_depth_buffer(24)
		.with_decorations(false)
		.build_glium().unwrap();

	glium_context.get_window().unwrap().set_cursor_state(CursorState::Grab).ok();

	let q = Arc::new(MsQueue::new());

	let (render_tokens_sender, render_tokens_receiver) = channel::<RenderToken>();
	let context = Arc::new(
		Context {
			exit: AtomicBool::new(false),
			input_senders: MsQueue::new(),
			last_physics_frame: RwLock::new(Arc::new(PhysicsFrame::frame_zero(aspect_ratio))),
			render_tokens_length: AtomicUsize::new(0),
			physics_continuations: Arc::new(Mutex::new(HashMap::new())),

			input:   InputContext  ::new(),
			physics: PhysicsContext::new(),
			render:  RenderContext ::new(q.clone(), window_size),
		}
	);

	{
		let context = context.clone();
		thread::spawn(move || { spawn_coroutines(context, render_tokens_receiver); });
	}

	let mut render_processor = RenderProcessor::new(q, glium_context);
	let mut last_input_time = time::precise_time_ns() / 1_000_000;
	let mut last_render_time = last_input_time;

	// TODO: may need to be refactored to handle system events more frequently/(lower max latency)
	//
	while let Some(events) = render_processor.handle_system_events() {
		if context.exit.load(Ordering::Relaxed) { break }

		context.input.post_input_events(events);

		let time = time::precise_time_ns() / 1_000_000;

		while last_input_time < time {
			if let Some(sender) = context.input_senders.try_pop() {
				sender.send(()).unwrap();
				last_input_time += 1_000 / INPUT_FREQUENCY;
			} else {
				break;
			}
		}

		while last_render_time < time {
			const FIF_RENDER: usize = 1;
			let length = context.render_tokens_length.load(Ordering::Acquire);
			if length < FIF_RENDER {
				context.render_tokens_length.fetch_add(1, Ordering::Release);
				render_tokens_sender.send(RenderToken).unwrap();
				last_render_time += 1_000 / RENDER_FREQUENCY;
			}
		}

		render_processor.handle_render_commands();

		thread::yield_now();
	}
}

struct Continuation {
	id: u64,
	req_count: AtomicUsize,
	reqs: MsQueue<Arc<Result>>,
}

enum Result { InputFrame(Arc<InputFrame>), PhysicsFrame(Arc<PhysicsFrame>) }

pub struct Context {
	exit: AtomicBool,
	input_senders: MsQueue<Sender<()>>,
	last_physics_frame: RwLock<Arc<PhysicsFrame>>,
	physics_continuations: Arc<Mutex<HashMap<u64, Arc<Continuation>>>>,
	render_tokens_length: AtomicUsize,

	pub input: InputContext,
	pub physics: PhysicsContext,
	pub render: RenderContext,
}

impl Context {
	pub fn input_signal(&self) -> Receiver<()> {
		let (sender, receiver) = channel();
		self.input_senders.push(sender);
		receiver
	}
}

fn input_entry(context: Arc<Context>, coroutine: Arc<Continuation>) {
	let start_signal = context.input_signal();
	start_signal.recv().unwrap();

	let last_input_frame = {
		match *coroutine.reqs.pop() {
			Result::InputFrame(ref data) => data.clone(),
			_ => unreachable!()
		}
	};

	let input_frame = InputFrame::new(context.clone(), last_input_frame);
	let result = Arc::new(Result::InputFrame(Arc::new(input_frame)));

	{
		let q = MsQueue::new();
		q.push(result.clone());
		let context = context.clone();
		let continuation = Arc::new(Continuation {
			id:        coroutine.id + 1,
			req_count: AtomicUsize::new(0),
			reqs:      q,
		});
		mioco::spawn(move|| input_entry(context, continuation));
	}
	{
		let continuation = {
			let mut map = context.physics_continuations.lock().unwrap();
			map.entry(coroutine.id).or_insert(Arc::new(Continuation {
				id:        coroutine.id,
				req_count: AtomicUsize::new(2),
				reqs:      MsQueue::new(),
			})).clone()
		};
		continuation.reqs.push(result.clone());
		let req_count = continuation.req_count.fetch_sub(1, Ordering::Relaxed);
		if req_count == 1 {
			let context = context.clone();
			let continuation = context.physics_continuations.lock().unwrap().remove(&coroutine.id).unwrap();

			mioco::spawn(move||physics_entry(context, continuation));
		}
	}
}

fn physics_entry(context: Arc<Context>, coroutine: Arc<Continuation>) {
	let (last_input_frame, last_physics_frame) = {
		let mut input_frame = Arc::new(InputFrame::frame_zero());
		let mut physics_frame = Arc::new(PhysicsFrame::frame_zero(context.render.aspect_ratio()));

		for _ in 0..2 {
			match *coroutine.reqs.pop() {
				Result::InputFrame(ref data) => input_frame = data.clone(),
				Result::PhysicsFrame(ref data) => physics_frame = data.clone(),
			};
		}
		(input_frame, physics_frame)
	};

	let physics_frame = Arc::new(PhysicsFrame::new(context.clone(), last_physics_frame, last_input_frame));
	let result = Arc::new(Result::PhysicsFrame(physics_frame.clone()));

	{ // TODO: do something better (that doesnt potentially block the sender)
		let latest_frame = context.last_physics_frame.read().unwrap().clone();
		if physics_frame.frame_counter > latest_frame.frame_counter {
			let mut reference = context.last_physics_frame.write().unwrap();
			*reference = physics_frame.clone();
		}
	}

	{
		let continuation = {
			let mut map = context.physics_continuations.lock().unwrap();
			map.entry(coroutine.id + 1).or_insert(Arc::new(Continuation {
				id:        coroutine.id + 1,
				req_count: AtomicUsize::new(2),
				reqs:      MsQueue::new(),
			})).clone()
		};
		continuation.reqs.push(result.clone());
		let req_count = continuation.req_count.fetch_sub(1, Ordering::Relaxed);
		if req_count == 1 {
		let context = context.clone();
		let continuation = context.physics_continuations.lock().unwrap().remove(&(coroutine.id + 1)).unwrap();
			mioco::spawn(move||physics_entry(context, continuation));
		}
	}
}

fn render_entry(context: Arc<Context>, render_tokens: Receiver<RenderToken>) {
	while !context.exit.load(Ordering::Relaxed) {
		render_tokens.recv().unwrap();

		let physics_frame = context.last_physics_frame.read().unwrap().clone();

		// TODO: don't render the same physics_frame twice

		let render_frame = {
			let context = context.clone();
			RenderFrame::new(context, physics_frame)
		};

		context.render.q.push(render_frame);
		context.render_tokens_length.fetch_sub(1, Ordering::Release);
	}
}

fn spawn_coroutines(context: Arc<Context>, render_tokens: Receiver<RenderToken>) {
	const NUM_THREADS: usize = 4;

	let mut config = Config::new();
	config.set_thread_num(NUM_THREADS);
	config.set_scheduler(Box::new(BalancingScheduler::new(NUM_THREADS)));
	config.set_catch_panics(false);

	{
		let result = Arc::new(Result::PhysicsFrame(Arc::new(PhysicsFrame::frame_zero(context.render.aspect_ratio()))));
		let q = MsQueue::new();
		q.push(result);
			context.physics_continuations.lock().unwrap().insert(1, Arc::new(Continuation {
			id: 1,
			req_count: AtomicUsize::new(1),
			reqs: q,
		}));
	}

	Mioco::new_configured(config).start(move|| {
		{
			let result = Arc::new(Result::InputFrame(Arc::new(InputFrame::frame_zero())));
			let q = MsQueue::new();
			q.push(result);
			let continuation = Arc::new(Continuation {
				id:        1,
				req_count: AtomicUsize::new(0),
				reqs:      q,
			});
			let context = context.clone();
			mioco::spawn(move||input_entry(context, continuation));
		}
		{ // for each render frame in flight
			let context = context.clone();
			mioco::spawn(move||render_entry(context, render_tokens));
		}
	}).unwrap();
}

<|endoftext|>


<commit_before>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else if path.starts_with(b"/") {
                let mut canon = cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec();
                canon.extend_from_slice(&path);
                canon
            } else {
                let mut canon = cwd.clone();
                if ! canon.ends_with(b"/") {
                    canon.push(b'/');
                }
                canon.extend_from_slice(&path);
                // NOTE: assumes the scheme does not include anything like "../" or "./"
                let mut result = {
                    let rparts = canon.split(|&c| c == b'/')
                        .filter(|&part| part != b".")
                        .rev()
                        .scan(0, |nskip, part| {
                            if part == b".." {
                                *nskip += 1;
                                Some(None)
                            } else {
                                if *nskip > 0 {
                                    *nskip -= 1;
                                    Some(None)
                                } else {
                                    Some(Some(part))
                                }
                            }
                        })
                        .filter_map(|x| x)
                        .collect::<Vec<_>>();
                    rparts
                        .iter()
                        .rev()
                        .fold(Vec::new(), |mut vec, &part| {
                            vec.extend_from_slice(part);
                            vec.push(b'/');
                            vec
                        })
                };
                result.pop(); // remove extra '/'
                if result.len() == 0 {
                    // replace with the root of the schema if it's empty
                    let pos = canon.iter()
                                   .position(|&b| b == b':')
                                   .map_or(canon.len(), |p| p + 1);
                    canon.truncate(pos);
                    canon
                } else {
                    result
                }
            }
        } else {
            path.to_vec()
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<commit_msg>Correctly handle relative paths starting from the root directory<commit_after>use alloc::arc::Arc;
use alloc::boxed::Box;
use collections::{BTreeMap, Vec, VecDeque};
use spin::Mutex;

use arch;
use context::file::File;
use context::memory::{Grant, Memory, SharedMemory, Tls};
use scheme::{SchemeNamespace, FileHandle};
use syscall::data::Event;
use sync::{WaitMap, WaitQueue};

/// Unique identifier for a context (i.e. `pid`).
use ::core::sync::atomic::AtomicUsize;
int_like!(ContextId, AtomicContextId, usize, AtomicUsize);

/// The status of a context - used for scheduling
/// See syscall::process::waitpid and the sync module for examples of usage
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Status {
    Runnable,
    Blocked,
    Exited(usize)
}

/// A context, which identifies either a process or a thread
#[derive(Debug)]
pub struct Context {
    /// The ID of this context
    pub id: ContextId,
    /// The ID of the parent context
    pub ppid: ContextId,
    /// The real user id
    pub ruid: u32,
    /// The real group id
    pub rgid: u32,
    /// The real namespace id
    pub rns: SchemeNamespace,
    /// The effective user id
    pub euid: u32,
    /// The effective group id
    pub egid: u32,
    /// The effective namespace id
    pub ens: SchemeNamespace,
    /// Status of context
    pub status: Status,
    /// Context running or not
    pub running: bool,
    /// CPU ID, if locked
    pub cpu_id: Option<usize>,
    /// Context is halting parent
    pub vfork: bool,
    /// Context is being waited on
    pub waitpid: Arc<WaitMap<ContextId, usize>>,
    /// Context should handle pending signals
    pub pending: VecDeque<u8>,
    /// Context should wake up at specified time
    pub wake: Option<(u64, u64)>,
    /// The architecture specific context
    pub arch: arch::context::Context,
    /// Kernel FX - used to store SIMD and FPU registers on context switch
    pub kfx: Option<Box<[u8]>>,
    /// Kernel stack
    pub kstack: Option<Box<[u8]>>,
    /// Executable image
    pub image: Vec<SharedMemory>,
    /// User heap
    pub heap: Option<SharedMemory>,
    /// User stack
    pub stack: Option<Memory>,
    /// User Thread local storage
    pub tls: Option<Tls>,
    /// User grants
    pub grants: Arc<Mutex<Vec<Grant>>>,
    /// The name of the context
    pub name: Arc<Mutex<Vec<u8>>>,
    /// The current working directory
    pub cwd: Arc<Mutex<Vec<u8>>>,
    /// Kernel events
    pub events: Arc<WaitQueue<Event>>,
    /// The process environment
    pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
    /// The open files in the scheme
    pub files: Arc<Mutex<Vec<Option<File>>>>
}

impl Context {
    pub fn new(id: ContextId) -> Context {
        Context {
            id: id,
            ppid: ContextId::from(0),
            ruid: 0,
            rgid: 0,
            rns: SchemeNamespace::from(0),
            euid: 0,
            egid: 0,
            ens: SchemeNamespace::from(0),
            status: Status::Blocked,
            running: false,
            cpu_id: None,
            vfork: false,
            waitpid: Arc::new(WaitMap::new()),
            pending: VecDeque::new(),
            wake: None,
            arch: arch::context::Context::new(),
            kfx: None,
            kstack: None,
            image: Vec::new(),
            heap: None,
            stack: None,
            tls: None,
            grants: Arc::new(Mutex::new(Vec::new())),
            name: Arc::new(Mutex::new(Vec::new())),
            cwd: Arc::new(Mutex::new(Vec::new())),
            events: Arc::new(WaitQueue::new()),
            env: Arc::new(Mutex::new(BTreeMap::new())),
            files: Arc::new(Mutex::new(Vec::new()))
        }
    }

    /// Make a relative path absolute
    /// Given a cwd of "scheme:/path"
    /// This function will turn "foo" into "scheme:/path/foo"
    /// "/foo" will turn into "scheme:/foo"
    /// "bar:/foo" will be used directly, as it is already absolute
    pub fn canonicalize(&self, path: &[u8]) -> Vec<u8> {
        if path.iter().position(|&b| b == b':').is_none() {
            let cwd = self.cwd.lock();
            if path == b"." {
                cwd.clone()
            } else if path == b".." {
                cwd[..cwd[..cwd.len() - 1]
                                   .iter().rposition(|&b| b == b'/' || b == b':')
                                   .map_or(cwd.len(), |i| i + 1)]
                   .to_vec()
            } else {
                let mut canon = if !path.starts_with(b"/") {
                    let mut c = cwd.clone();
                    if ! c.ends_with(b"/") {
                        c.push(b'/');
                    }
                    c
                } else {
                    cwd[..cwd.iter().position(|&b| b == b':').map_or(1, |i| i + 1)].to_vec()
                };

                canon.extend_from_slice(&path);
                // NOTE: assumes the scheme does not include anything like "../" or "./"
                let mut result = {
                    let parts = canon.split(|&c| c == b'/')
                        .filter(|&part| part != b".")
                        .rev()
                        .scan(0, |nskip, part| {
                            if part == b".." {
                                *nskip += 1;
                                Some(None)
                            } else {
                                if *nskip > 0 {
                                    *nskip -= 1;
                                    Some(None)
                                } else {
                                    Some(Some(part))
                                }
                            }
                        })
                        .filter_map(|x| x)
                        .collect::<Vec<_>>();
                    parts
                        .iter()
                        .rev()
                        .fold(Vec::new(), |mut vec, &part| {
                            vec.extend_from_slice(part);
                            vec.push(b'/');
                            vec
                        })
                };
                result.pop(); // remove extra '/'

                // replace with the root of the schema if it's empty
                if result.len() == 0 {
                    let pos = canon.iter()
                                    .position(|&b| b == b':')
                                    .map_or(canon.len(), |p| p + 1);
                    canon.truncate(pos);
                    canon
                } else {
                    result
                }
            }
        } else {
            path.to_vec()
        }
    }

    /// Block the context, and return true if it was runnable before being blocked
    pub fn block(&mut self) -> bool {
        if self.status == Status::Runnable {
            self.status = Status::Blocked;
            true
        } else {
            false
        }
    }

    /// Unblock context, and return true if it was blocked before being marked runnable
    pub fn unblock(&mut self) -> bool {
        if self.status == Status::Blocked {
            self.status = Status::Runnable;
            if let Some(cpu_id) = self.cpu_id {
                if cpu_id != ::cpu_id() {
                    // Send IPI if not on current CPU
                    // TODO: Make this more architecture independent
                    unsafe { arch::device::local_apic::LOCAL_APIC.ipi(cpu_id) };
                }
            }
            true
        } else {
            false
        }
    }

    /// Add a file to the lowest available slot.
    /// Return the file descriptor number or None if no slot was found
    pub fn add_file(&self, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        for (i, mut file_option) in files.iter_mut().enumerate() {
            if file_option.is_none() {
                *file_option = Some(file);
                return Some(FileHandle::from(i));
            }
        }
        let len = files.len();
        if len < super::CONTEXT_MAX_FILES {
            files.push(Some(file));
            Some(FileHandle::from(len))
        } else {
            None
        }
    }

    /// Get a file
    pub fn get_file(&self, i: FileHandle) -> Option<File> {
        let files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()]
        } else {
            None
        }
    }

    /// Insert a file with a specific handle number. This is used by dup2
    /// Return the file descriptor number or None if the slot was not empty, or i was invalid
    pub fn insert_file(&self, i: FileHandle, file: File) -> Option<FileHandle> {
        let mut files = self.files.lock();
        if i.into() < super::CONTEXT_MAX_FILES {
            while i.into() >= files.len() {
                files.push(None);
            }
            if files[i.into()].is_none() {
                files[i.into()] = Some(file);
                Some(i)
            } else {
                None
            }
        } else {
            None
        }
    }

    /// Remove a file
    // TODO: adjust files vector to smaller size if possible
    pub fn remove_file(&self, i: FileHandle) -> Option<File> {
        let mut files = self.files.lock();
        if i.into() < files.len() {
            files[i.into()].take()
        } else {
            None
        }
    }
}
<|endoftext|>


<commit_before>// no-system-llvm
// only-x86_64
// only-linux
// run-pass

#![feature(asm, thread_local)]

extern "C" fn f1() -> i32 {
    111
}

// The compiler will generate a shim to hide the caller location parameter.
#[track_caller]
fn f2() -> i32 {
    222
}

macro_rules! call {
    ($func:path) => {
        unsafe {
            let result: i32;
            asm!("call {}", sym $func,
                out("rax") result,
                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
            );
            result
        }
    }
}

macro_rules! static_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            // LEA performs a RIP-relative address calculation and returns the address
            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
            result
        }
    }
}
macro_rules! static_tls_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            asm!(
                "
                    # Load TLS base address
                    mov {out}, qword ptr fs:[0]
                    # Calculate the address of sym in the TLS block. The @tpoff
                    # relocation gives the offset of the symbol from the start
                    # of the TLS block.
                    lea {out}, [{out} + {sym}@tpoff]
                ",
                out = out(reg) result,
                sym = sym $s
            );
            result
        }
    }
}

static S1: u32 = 111;
#[thread_local]
static S2: u32 = 222;

fn main() {
    assert_eq!(call!(f1), 111);
    assert_eq!(call!(f2), 222);
    assert_eq!(static_addr!(S1), &S1 as *const u32);
    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    std::thread::spawn(|| {
        assert_eq!(static_addr!(S1), &S1 as *const u32);
        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    });
}
<commit_msg>Join test thread to make assertion effective in sym.rs test case<commit_after>// no-system-llvm
// only-x86_64
// only-linux
// run-pass

#![feature(asm, thread_local)]

extern "C" fn f1() -> i32 {
    111
}

// The compiler will generate a shim to hide the caller location parameter.
#[track_caller]
fn f2() -> i32 {
    222
}

macro_rules! call {
    ($func:path) => {
        unsafe {
            let result: i32;
            asm!("call {}", sym $func,
                out("rax") result,
                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
            );
            result
        }
    }
}

macro_rules! static_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            // LEA performs a RIP-relative address calculation and returns the address
            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
            result
        }
    }
}
macro_rules! static_tls_addr {
    ($s:expr) => {
        unsafe {
            let result: *const u32;
            asm!(
                "
                    # Load TLS base address
                    mov {out}, qword ptr fs:[0]
                    # Calculate the address of sym in the TLS block. The @tpoff
                    # relocation gives the offset of the symbol from the start
                    # of the TLS block.
                    lea {out}, [{out} + {sym}@tpoff]
                ",
                out = out(reg) result,
                sym = sym $s
            );
            result
        }
    }
}

static S1: u32 = 111;
#[thread_local]
static S2: u32 = 222;

fn main() {
    assert_eq!(call!(f1), 111);
    assert_eq!(call!(f2), 222);
    assert_eq!(static_addr!(S1), &S1 as *const u32);
    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    std::thread::spawn(|| {
        assert_eq!(static_addr!(S1), &S1 as *const u32);
        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
    }).join().unwrap();
}
<|endoftext|>


<commit_before>//! Encode `Node` nodes to HTML

use super::{
    attr, attr_itemtype_str, elem, json, primitives::array_to_html, EncodeContext, ToHtml,
};
use node_dispatch::dispatch_node;
use stencila_schema::Node;

/// Encode a `Node` to HTML
///
/// All node types that have an `impl ToHtml` should be listed here. Not all node types
/// are supported, in which case this function returns HTML indicating that that is the case.
impl ToHtml for Node {
    fn to_html(&self, context: &EncodeContext) -> String {
        // Call `array_to_html` to avoid `Vec<Primitive>.to_html()` for arrays
        if let Node::Array(array) = self {
            return array_to_html(array, context);
        }

        // Wrap strings in a `<pre>` with the `itemtype` attribute.
        // This encoding will be used in places such as `CodeChunk.outputs`, `CodeExpression.output` etc
        // where pre-formatting is important and wrapping in an element is needed for patches (whitespace
        // can be lost if not wrapped in a <pre>).
        // See note under `ToHtml` for `InlineContent` for how strings are handled in that context.
        if let Node::String(string) = self {
            return elem(
                "pre",
                &[attr_itemtype_str("Text")],
                &string.to_html(context),
            );
        }

        dispatch_node!(
            self,
            elem("div", &[attr("class", "unsupported")], &json(self)),
            to_html,
            context
        )
    }
}
<commit_msg>fix(HTML encoding): Use `<span>` instead of `<pre>` for text outputs<commit_after>//! Encode `Node` nodes to HTML

use super::{
    attr, attr_itemtype_str, elem, json, primitives::array_to_html, EncodeContext, ToHtml,
};
use node_dispatch::dispatch_node;
use stencila_schema::Node;

/// Encode a `Node` to HTML
///
/// All node types that have an `impl ToHtml` should be listed here. Not all node types
/// are supported, in which case this function returns HTML indicating that that is the case.
impl ToHtml for Node {
    fn to_html(&self, context: &EncodeContext) -> String {
        // Call `array_to_html` to avoid `Vec<Primitive>.to_html()` for arrays
        if let Node::Array(array) = self {
            return array_to_html(array, context);
        }

        // Previously, we said:
        //   Wrap strings in a `<pre>` with the `itemtype` attribute.
        //   This encoding will be used in places such as `CodeChunk.outputs`, `CodeExpression.output` etc
        //   where pre-formatting is important and wrapping in an element is needed for patches (whitespace
        //   can be lost if not wrapped in a <pre>).
        // But..that caused problems for `CodeExpression.output` rendering. So here, it is changed back to <span>
        // and we'll see if we can find another way of dealing with the above issue.
        //
        // See note under `ToHtml` for `InlineContent` for how strings are handled in that context.
        if let Node::String(string) = self {
            return elem(
                "span",
                &[attr_itemtype_str("Text")],
                &string.to_html(context),
            );
        }

        // Fallback to default `to_html` for other `Node` variants
        dispatch_node!(
            self,
            elem("div", &[attr("class", "unsupported")], &json(self)),
            to_html,
            context
        )
    }
}
<|endoftext|>


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

pub struct Position {
    pub line: usize,
    pub column: usize,
}

pub enum Token {
    Empty,
    Invalid,
    Identifier(String),
    Literal(Literal),
    Punctuation(String),
}

pub enum Literal {
    StringLiteral(String),
    Character(char),
    Integer(String),
    FloatingPoint(String),
    Hex(String),
}

pub struct Lexer<'a> {
    pub token: Token,
    character: Option<char>,
    chars: Chars<'a>,
    previous_line: usize,
    previous_column: usize,
    pub line: usize,
    pub column: usize,
}

impl<'a> Lexer<'a> {
    pub fn new(deck: &'a str) -> Lexer {
        let mut lexer = Lexer {
            chars: deck.chars(),
            token: Token::Empty,
            character: None,
            previous_line: 1,
            previous_column: 0,
            line: 1,
            column: 0,
        };
        lexer.read_character();
        lexer
    }

    fn read_character(&mut self) {
        self.character = self.chars.next();
        match self.character {
            None => (),
            Some(c) => match c {
                '\r' => (),
                '\n' => {
                    self.column = 0;
                    self.line = self.line + 1;
                }
                '\t' => self.column = self.column + 4,
                _ => self.column = self.column + 1,
            },
        }
    }

    pub fn advance(&mut self) {
        self.skip_whitespace();
        self.previous_line = self.line;
        self.previous_column = self.column;
        match self.character {
            None => return,
            Some(c) => {
                if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
                    self.token = self.scan_identifier();
                    return;
                }

                if (c >= '1') && (c <= '9') {
                    let mut value = String::new();
                    value.push(c);
                    self.token = self.scan_numeric_literal(value);
                    return;
                }

                match c {
                    '0' => {
                        let mut value = String::new();
                        value.push(c);
                        self.token = self.scan_numeric_or_hex_literal(value);
                    }
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        let mut operation = String::new();
                        operation.push(c);
                        self.token = self.scan_operator(operation)
                    }
                    '\"' => self.token = { self.scan_string_literal() },
                    '\'' => self.token = { self.scan_character_literal() },
                    '{' | '}' | '(' | ')' | '[' | ']' | '.' | ',' | ':' | ';' | '?' | '!' | '@'
                    | '#' | '$' | '_' | '`' => {
                        let mut punctuation_string = String::new();
                        punctuation_string.push(c);
                        self.token = Token::Punctuation(punctuation_string);
                    }
                    _ => self.token = Token::Invalid,
                }
            }
        }
    }

    pub fn empty(&mut self) {
        self.token = Token::Empty;
    }

    fn scan_identifier(&mut self) -> Token {
        let mut name = String::new();
        loop {
            match self.character {
                None => {
                    if name.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(name);
                    }
                }

                Some(c) => match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {
                        name.push(c);
                        self.read_character();
                    }
                    _ => return Token::Identifier(name),
                },
            }
        }
    }

    fn scan_operator(&mut self, mut operation: String) -> Token {
        loop {
            match self.character {
                None => {
                    if operation.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(operation);
                    }
                }
                Some(c) => match c {
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        operation.push(c);
                    }

                    _ => return Token::Identifier(operation),
                },
            }
        }
    }

    fn scan_string_literal(&mut self) -> Token {
        let mut value = String::new();

        loop {
            self.read_character();

            match self.character {
                None => return Token::Invalid,
                Some(c) => match c {
                    '\"' => {
                        self.read_character();
                        return Token::Literal(Literal::StringLiteral(value));
                    }

                    '\\' => {
                        self.read_character();
                        match self.character {
                            None => return Token::Invalid,
                            Some(c) => match c {
                                '\"' | '\\' | '\'' => {
                                    value.push('\\');
                                    value.push(c);
                                }
                                'n' => {
                                    value.push('\\');
                                    value.push('n');
                                }
                                'r' => {
                                    value.push('\\');
                                    value.push('r');
                                }
                                't' => {
                                    value.push('\\');
                                    value.push('t');
                                }
                                '0' => {
                                    value.push('\\');
                                    value.push('0');
                                }
                                _ => return Token::Invalid,
                            },
                        }
                    }

                    _ => {
                        value.push(c);
                    }
                },
            }
        }
    }

    fn scan_character_literal(&mut self) -> Token {
        let value: char;
        self.read_character();

        match self.character {
            None => return Token::Invalid,
            Some(c) => match c {
                '\'' => return Token::Invalid,
                '\\' => {
                    self.read_character();
                    match self.character {
                        None => return Token::Invalid,
                        Some(c) => match c {
                            '\"' | '\\' | '\'' => value = c,
                            'n' => value = '\n',
                            'r' => value = '\r',
                            't' => value = '\t',
                            '0' => value = '\0',
                            _ => return Token::Invalid,
                        },
                    }
                }
                _ => value = c,
            },
        }
        self.read_character();
        match self.character {
            None => Token::Invalid,
            Some(c) => match c {
                '\'' => Token::Literal(Literal::Character(value)),
                _ => Token::Invalid,
            },
        }
    }

    fn scan_numeric_or_hex_literal(&mut self, mut value: String) -> Token {
        self.read_character();
        match self.character {
            None => return Token::Literal(Literal::Integer(value)),
            Some(c) => match c {
                '0'..='9' => {
                    value.push(c);
                    return self.scan_numeric_literal(value);
                }
                '.' => {
                    value.push(c);
                    return self.scan_fraction(value);
                }
                'E' | 'e' => {
                    value.push(c);
                    return self.scan_exponent(value);
                }
                'x' => {
                    return self.scan_hex_literal();
                }
                _ => return Token::Literal(Literal::Integer(value)),
            },
        }
    }

    fn scan_numeric_literal(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::Integer(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    '.' => {
                        value.push(c);
                        return self.scan_fraction(value);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::Integer(value)),
                },
            }
        }
    }

    fn scan_fraction(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_exponent(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_hex_literal(&mut self) -> Token {
        let mut value = String::new();
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' | 'a'..='f' | 'A'..='F' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::Hex(value)),
                },
            }
        }
    }

    fn skip_whitespace(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    ' ' => {
                        self.read_character();
                        continue;
                    }
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        self.read_character();
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        continue;
                    }
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    self.handle_single_line_comment()
                                }
                                '*' => {
                                    self.read_character();
                                    self.handle_multi_line_comment()
                                }
                                _ => return,
                            },
                        }
                    }

                    _ => {
                        return;
                    }
                },
            }
        }
    }

    fn handle_single_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        return;
                    }
                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    fn handle_multi_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '*' => self.handle_multi_line_comment(),
                                _ => return,
                            },
                        }
                    }

                    '*' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    return;
                                }
                                _ => (),
                            },
                        }
                    }

                    '\t' => {
                        self.read_character();
                        continue;
                    }

                    '\r' => {
                        continue;
                    }

                    '\n' => {
                        self.read_character();
                        continue;
                    }

                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    pub fn parse_keyword(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                let right_keyword = *name == fixed_string;
                if right_keyword {
                    self.empty();
                }
                return right_keyword;
            }
            _ => return false,
        }
    }

    pub fn parse_identifier(&mut self, keywords: &HashSet<String>) -> Option<String> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                if keywords.contains(name) {
                    return None;
                }
                let ret = String::from(name);
                self.empty();
                return Some(ret);
            }
            _ => return None,
        }
    }

    pub fn parse_punctuation(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Punctuation(name) => {
                let ret = *name == fixed_string;
                if ret {
                    self.empty();
                }
                return ret;
            }
            _ => return false,
        }
    }

    pub fn parse_literal(&mut self) -> Option<Literal> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Literal(Literal::StringLiteral(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::StringLiteral(ret))
            }
            Token::Literal(Literal::Character(character)) => {
                let ret = *character;
                self.empty();
                Some(Literal::Character(ret))
            }
            Token::Literal(Literal::Integer(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Integer(ret))
            }
            Token::Literal(Literal::FloatingPoint(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::FloatingPoint(ret))
            }
            Token::Literal(Literal::Hex(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Hex(ret))
            }
            _ => None,
        }
    }

    pub fn is_at_end(&mut self) -> bool {
        match self.character {
            None => true,
            Some(_) => false,
        }
    }

    pub fn get_position(&self) -> Position {
        Position {
            line: self.line,
            column: self.column,
        }
    }

    pub fn get_previous_position(&self) -> Position {
        Position {
            line: self.previous_line,
            column: self.previous_column,
        }
    }
}
<commit_msg>lexer.parse_punctuation fix<commit_after>use std::collections::HashSet;
use std::str::Chars;

pub struct Position {
    pub line: usize,
    pub column: usize,
}

pub enum Token {
    Empty,
    Invalid,
    Identifier(String),
    Literal(Literal),
    Punctuation(String),
}

pub enum Literal {
    StringLiteral(String),
    Character(char),
    Integer(String),
    FloatingPoint(String),
    Hex(String),
}

pub struct Lexer<'a> {
    pub token: Token,
    character: Option<char>,
    chars: Chars<'a>,
    previous_line: usize,
    previous_column: usize,
    pub line: usize,
    pub column: usize,
}

impl<'a> Lexer<'a> {
    pub fn new(deck: &'a str) -> Lexer {
        let mut lexer = Lexer {
            chars: deck.chars(),
            token: Token::Empty,
            character: None,
            previous_line: 1,
            previous_column: 0,
            line: 1,
            column: 0,
        };
        lexer.read_character();
        lexer
    }

    fn read_character(&mut self) {
        self.character = self.chars.next();
        match self.character {
            None => (),
            Some(c) => match c {
                '\r' => (),
                '\n' => {
                    self.column = 0;
                    self.line = self.line + 1;
                }
                '\t' => self.column = self.column + 4,
                _ => self.column = self.column + 1,
            },
        }
    }

    pub fn advance(&mut self) {
        self.skip_whitespace();
        self.previous_line = self.line;
        self.previous_column = self.column;
        match self.character {
            None => return,
            Some(c) => {
                if ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) {
                    self.token = self.scan_identifier();
                    return;
                }

                if (c >= '1') && (c <= '9') {
                    let mut value = String::new();
                    value.push(c);
                    self.token = self.scan_numeric_literal(value);
                    return;
                }

                match c {
                    '0' => {
                        let mut value = String::new();
                        value.push(c);
                        self.token = self.scan_numeric_or_hex_literal(value);
                    }
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        let mut operation = String::new();
                        operation.push(c);
                        self.token = self.scan_operator(operation)
                    }
                    '\"' => self.token = { self.scan_string_literal() },
                    '\'' => self.token = { self.scan_character_literal() },
                    '{' | '}' | '(' | ')' | '[' | ']' | '.' | ',' | ':' | ';' | '?' | '!' | '@'
                    | '#' | '$' | '_' | '`' => {
                        let mut punctuation_string = String::new();
                        punctuation_string.push(c);
                        self.read_character();
                        self.token = Token::Punctuation(punctuation_string);
                    }
                    _ => self.token = Token::Invalid,
                }
            }
        }
    }

    pub fn empty(&mut self) {
        self.token = Token::Empty;
    }

    fn scan_identifier(&mut self) -> Token {
        let mut name = String::new();
        loop {
            match self.character {
                None => {
                    if name.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(name);
                    }
                }

                Some(c) => match c {
                    'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => {
                        name.push(c);
                        self.read_character();
                    }
                    _ => return Token::Identifier(name),
                },
            }
        }
    }

    fn scan_operator(&mut self, mut operation: String) -> Token {
        loop {
            match self.character {
                None => {
                    if operation.len() == 0 {
                        return Token::Invalid;
                    } else {
                        return Token::Identifier(operation);
                    }
                }
                Some(c) => match c {
                    '+' | '-' | '*' | '/' | '=' | '%' | '&' | '|' | '^' | '~' | '<' | '>' => {
                        operation.push(c);
                    }

                    _ => return Token::Identifier(operation),
                },
            }
        }
    }

    fn scan_string_literal(&mut self) -> Token {
        let mut value = String::new();

        loop {
            self.read_character();

            match self.character {
                None => return Token::Invalid,
                Some(c) => match c {
                    '\"' => {
                        self.read_character();
                        return Token::Literal(Literal::StringLiteral(value));
                    }

                    '\\' => {
                        self.read_character();
                        match self.character {
                            None => return Token::Invalid,
                            Some(c) => match c {
                                '\"' | '\\' | '\'' => {
                                    value.push('\\');
                                    value.push(c);
                                }
                                'n' => {
                                    value.push('\\');
                                    value.push('n');
                                }
                                'r' => {
                                    value.push('\\');
                                    value.push('r');
                                }
                                't' => {
                                    value.push('\\');
                                    value.push('t');
                                }
                                '0' => {
                                    value.push('\\');
                                    value.push('0');
                                }
                                _ => return Token::Invalid,
                            },
                        }
                    }

                    _ => {
                        value.push(c);
                    }
                },
            }
        }
    }

    fn scan_character_literal(&mut self) -> Token {
        let value: char;
        self.read_character();

        match self.character {
            None => return Token::Invalid,
            Some(c) => match c {
                '\'' => return Token::Invalid,
                '\\' => {
                    self.read_character();
                    match self.character {
                        None => return Token::Invalid,
                        Some(c) => match c {
                            '\"' | '\\' | '\'' => value = c,
                            'n' => value = '\n',
                            'r' => value = '\r',
                            't' => value = '\t',
                            '0' => value = '\0',
                            _ => return Token::Invalid,
                        },
                    }
                }
                _ => value = c,
            },
        }
        self.read_character();
        match self.character {
            None => Token::Invalid,
            Some(c) => match c {
                '\'' => Token::Literal(Literal::Character(value)),
                _ => Token::Invalid,
            },
        }
    }

    fn scan_numeric_or_hex_literal(&mut self, mut value: String) -> Token {
        self.read_character();
        match self.character {
            None => return Token::Literal(Literal::Integer(value)),
            Some(c) => match c {
                '0'..='9' => {
                    value.push(c);
                    return self.scan_numeric_literal(value);
                }
                '.' => {
                    value.push(c);
                    return self.scan_fraction(value);
                }
                'E' | 'e' => {
                    value.push(c);
                    return self.scan_exponent(value);
                }
                'x' => {
                    return self.scan_hex_literal();
                }
                _ => return Token::Literal(Literal::Integer(value)),
            },
        }
    }

    fn scan_numeric_literal(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::Integer(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    '.' => {
                        value.push(c);
                        return self.scan_fraction(value);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::Integer(value)),
                },
            }
        }
    }

    fn scan_fraction(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    'E' | 'e' => {
                        value.push(c);
                        return self.scan_exponent(value);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_exponent(&mut self, mut value: String) -> Token {
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::FloatingPoint(value)),
                },
            }
        }
    }

    fn scan_hex_literal(&mut self) -> Token {
        let mut value = String::new();
        loop {
            self.read_character();
            match self.character {
                None => {
                    return Token::Literal(Literal::FloatingPoint(value));
                }
                Some(c) => match c {
                    '0'..='9' | 'a'..='f' | 'A'..='F' => {
                        value.push(c);
                    }
                    _ => return Token::Literal(Literal::Hex(value)),
                },
            }
        }
    }

    fn skip_whitespace(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    ' ' => {
                        self.read_character();
                        continue;
                    }
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        self.read_character();
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        continue;
                    }
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    self.handle_single_line_comment()
                                }
                                '*' => {
                                    self.read_character();
                                    self.handle_multi_line_comment()
                                }
                                _ => return,
                            },
                        }
                    }

                    _ => {
                        return;
                    }
                },
            }
        }
    }

    fn handle_single_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '\t' => {
                        self.read_character();
                        continue;
                    }
                    '\r' => {
                        continue;
                    }
                    '\n' => {
                        self.read_character();
                        return;
                    }
                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    fn handle_multi_line_comment(&mut self) {
        loop {
            match self.character {
                None => return,
                Some(c) => match c {
                    '/' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '*' => self.handle_multi_line_comment(),
                                _ => return,
                            },
                        }
                    }

                    '*' => {
                        self.read_character();
                        match self.character {
                            None => return,
                            Some(c) => match c {
                                '/' => {
                                    self.read_character();
                                    return;
                                }
                                _ => (),
                            },
                        }
                    }

                    '\t' => {
                        self.read_character();
                        continue;
                    }

                    '\r' => {
                        continue;
                    }

                    '\n' => {
                        self.read_character();
                        continue;
                    }

                    _ => {
                        self.read_character();
                        continue;
                    }
                },
            }
        }
    }

    pub fn parse_keyword(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                let right_keyword = *name == fixed_string;
                if right_keyword {
                    self.empty();
                }
                return right_keyword;
            }
            _ => return false,
        }
    }

    pub fn parse_identifier(&mut self, keywords: &HashSet<String>) -> Option<String> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Identifier(name) => {
                if keywords.contains(name) {
                    return None;
                }
                let ret = String::from(name);
                self.empty();
                return Some(ret);
            }
            _ => return None,
        }
    }

    pub fn parse_punctuation(&mut self, fixed_string: String) -> bool {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Punctuation(name) => {
                let ret = *name == fixed_string;
                if ret {
                    self.empty();
                }
                return ret;
            }
            _ => return false,
        }
    }

    pub fn parse_literal(&mut self) -> Option<Literal> {
        match &self.token {
            Token::Empty => self.advance(),
            _ => (),
        }
        match &self.token {
            Token::Literal(Literal::StringLiteral(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::StringLiteral(ret))
            }
            Token::Literal(Literal::Character(character)) => {
                let ret = *character;
                self.empty();
                Some(Literal::Character(ret))
            }
            Token::Literal(Literal::Integer(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Integer(ret))
            }
            Token::Literal(Literal::FloatingPoint(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::FloatingPoint(ret))
            }
            Token::Literal(Literal::Hex(name)) => {
                let ret = String::from(name);
                self.empty();
                Some(Literal::Hex(ret))
            }
            _ => None,
        }
    }

    pub fn is_at_end(&mut self) -> bool {
        match self.character {
            None => true,
            Some(_) => false,
        }
    }

    pub fn get_position(&self) -> Position {
        Position {
            line: self.line,
            column: self.column,
        }
    }

    pub fn get_previous_position(&self) -> Position {
        Position {
            line: self.previous_line,
            column: self.previous_column,
        }
    }
}
<|endoftext|>


<commit_before>use std::io;

macro_rules! print_err {
    ($($arg:tt)*) => (
        {
            use std::io::Write;
            writeln!(&mut ::std::io::stderr(), $($arg)*).ok();
        }
    )
}

macro_rules! parse_input {
    ($x:expr, $t:ident) => ($x.trim().parse::<$t>().unwrap())
}

fn to_temperature_with_absolute_value(t: i32) -> (i32, i32) {
    (t, t.abs())
}

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
fn main() {
    print_err!("Enter the numer of temperatures that will be input: ");
    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();
    let n = parse_input!(input_line, i32); // the number of temperatures to analyse
    print_err!("The number of temperatures to input : {}", n);
    let mut input_line = String::new();
    print_err!("Enter the list of temperatures : ");
    io::stdin().read_line(&mut input_line).unwrap();
    let temps = input_line.trim_right().to_string(); // the n temperatures expressed as integers ranging from -273 to 5526
    print_err!("The line of temperatures input : {}", temps);

    let result:i32 = if n == 0 {
            0
        }
        else {
            //let vec: Vec<&str> = temps.split_whitespace().collect();

            //for s in vec {
            //    print_err!("Read temperature : {}", s);
            //}

            //let numbers: Vec<i32> = reader.read_line().unwrap().as_slice().split_whitespace().map(|s| s.parse().unwrap()).collect()
            //let my_int: i32 = my_string.parse().unwrap();
            let temperatures: Vec<(i32,i32)> = temps.split_whitespace().map(|s| to_temperature_with_absolute_value(s.parse().unwrap())).collect();
            print_err!("(Temperature,Temperature in absolute value)");
            let mut min_abs:(i32,i32) = temperatures[0];
            for t in temperatures {
                print_err!("({},{})", t.0,t.1);
                if t.1 < min_abs.1 || (t.1 == min_abs.1 && t.0 >= 0) {
                    min_abs = t;
                }
            }

            min_abs.0

            // Write an action using println!("message...");
            // To debug: print_err!("Debug message...");
        };
    println!("{}",result);
}
<commit_msg>Solution in Rust to the CG easy puzzle "Temperatures"<commit_after>use std::io;

macro_rules! print_err {
    ($($arg:tt)*) => (
        {
            use std::io::Write;
            writeln!(&mut ::std::io::stderr(), $($arg)*).ok();
        }
    )
}

macro_rules! parse_input {
    ($x:expr, $t:ident) => ($x.trim().parse::<$t>().unwrap())
}

fn to_temperature_with_absolute_value(t: i32) -> (i32, i32) {
    (t, t.abs())
}

fn main() {
    print_err!("Enter the numer of temperatures that will be input: ");
    let mut input_line = String::new();
    io::stdin().read_line(&mut input_line).unwrap();
    let n = parse_input!(input_line, i32); // the number of temperatures to analyse
    print_err!("The number of temperatures to input : {}", n);
    let mut input_line = String::new();
    print_err!("Enter the list of temperatures : ");
    io::stdin().read_line(&mut input_line).unwrap();
    let temps = input_line.trim_right().to_string(); // the n temperatures expressed as integers ranging from -273 to 5526
    print_err!("The line of temperatures input : {}", temps);

    let result:i32 = if n == 0 {
            0
        }
        else {
            let temperatures: Vec<(i32,i32)> = temps.split_whitespace().map(|s| to_temperature_with_absolute_value(s.parse().unwrap())).collect();
            print_err!("(Temperature,Temperature in absolute value)");
            let mut min_abs:(i32,i32) = temperatures[0];
            for t in temperatures {
                print_err!("({},{})", t.0,t.1);
                if t.1 < min_abs.1 || (t.1 == min_abs.1 && t.0 >= 0) {
                    min_abs = t;
                }
            }

            min_abs.0
        };
    println!("{}",result);
}
<|endoftext|>