<commit_before>use std::cell::{Cell, RefCell};
use std::ptr;

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use aspect_ratio::AspectRatio;
use attributes::Attribute;
use defs::Href;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use handle::{self, RsvgHandle};
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::parse;
use property_bag::PropertyBag;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<String>>,

    // Storing this here seems hack-ish... It's required by rsvg_cairo_surface_new_from_href(). The
    // <image> element calls it in set_atts() but I don't think it belongs there.
    handle: Cell<*const RsvgHandle>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),

            handle: Cell::new(ptr::null()),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds: IRect,
        href: &str,
    ) -> Result<ImageSurface, FilterError> {
        // TODO: Port more of this to Rust.
        // Currently this is essentially a direct port of the C function.
        let acquired_drawable = draw_ctx
            .get_acquired_node(href)
            .ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds_builder: BoundsBuilder<'_>,
        uri: &str,
    ) -> Result<ImageSurface, FilterError> {
        // FIXME: translate the error better here
        let surface = handle::image_surface_new_from_href(self.handle.get() as *mut _, uri)
            .map_err(|_| FilterError::InvalidInput)?;

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let render_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.get_width()),
            f64::from(surface.get_height()),
            f64::from(render_bounds.x0),
            f64::from(render_bounds.y0),
            f64::from(render_bounds.x1 - render_bounds.x0),
            f64::from(render_bounds.y1 - render_bounds.y0),
        );

        if w != 0f64 && h != 0f64 {
            let ptn = cairo::SurfacePattern::create(&surface);
            let mut matrix = cairo::Matrix::new(
                w / f64::from(surface.get_width()),
                0f64,
                0f64,
                h / f64::from(surface.get_height()),
                x,
                y,
            );
            matrix.invert();
            ptn.set_matrix(matrix);

            let bounds = bounds_builder.into_irect(draw_ctx);
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                f64::from(bounds.x0),
                f64::from(bounds.y0),
                f64::from(bounds.x1 - bounds.x0),
                f64::from(bounds.y1 - bounds.y0),
            );
            cr.clip();
            cr.set_source(&cairo::Pattern::SurfacePattern(ptn));
            cr.paint();
        }

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    drop(self.href.replace(Some(value.to_string())))
                }
                _ => (),
            }
        }

        self.handle.set(handle);

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
    ) -> Result<FilterResult, FilterError> {
        let href_str = self.href.borrow();
        let href_str = href_str.as_ref().ok_or(FilterError::InvalidInput)?;

        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href = Href::parse(href_str).map_err(|_| FilterError::InvalidInput)?;

        let output_surface = match href {
            Href::PlainUri(ref uri) => {
                self.render_external_image(ctx, draw_ctx, bounds_builder, uri)?
            }
            _ => self.render_node(ctx, draw_ctx, bounds, href_str)?,
        };

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<commit_msg>filters/image.rs: Pass the Href to the worker functions, not a string<commit_after>use std::cell::{Cell, RefCell};
use std::ptr;

use cairo::{self, ImageSurface, MatrixTrait, PatternTrait};

use aspect_ratio::AspectRatio;
use attributes::Attribute;
use defs::Href;
use drawing_ctx::DrawingCtx;
use error::RenderingError;
use handle::{self, RsvgHandle};
use node::{CascadedValues, NodeResult, NodeTrait, RsvgNode};
use parsers::parse;
use property_bag::PropertyBag;
use surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use super::bounds::BoundsBuilder;
use super::context::{FilterContext, FilterOutput, FilterResult, IRect};
use super::{Filter, FilterError, Primitive};

/// The `feImage` filter primitive.
pub struct Image {
    base: Primitive,
    aspect: Cell<AspectRatio>,
    href: RefCell<Option<String>>,

    // Storing this here seems hack-ish... It's required by rsvg_cairo_surface_new_from_href(). The
    // <image> element calls it in set_atts() but I don't think it belongs there.
    handle: Cell<*const RsvgHandle>,
}

impl Image {
    /// Constructs a new `Image` with empty properties.
    #[inline]
    pub fn new() -> Image {
        Image {
            base: Primitive::new::<Self>(),
            aspect: Cell::new(AspectRatio::default()),
            href: RefCell::new(None),

            handle: Cell::new(ptr::null()),
        }
    }

    /// Renders the filter if the source is an existing node.
    fn render_node(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds: IRect,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let url = match *href {
            Href::FragmentId(ref f) => format!("#{}", f),
            Href::UriWithFragmentId(ref u, ref f) => format!("{}#{}", u, f),
            _ => unreachable!(),
        };

        let acquired_drawable = draw_ctx.get_acquired_node(&url).ok_or(FilterError::InvalidInput)?;
        let drawable = acquired_drawable.get();

        let surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        draw_ctx.get_cairo_context().set_matrix(ctx.paffine());

        let node_being_filtered_values = ctx.get_computed_values_from_node_being_filtered();

        let cascaded = CascadedValues::new_from_values(&drawable, node_being_filtered_values);

        draw_ctx
            .draw_node_on_surface(
                &drawable,
                &cascaded,
                &surface,
                f64::from(ctx.source_graphic().width()),
                f64::from(ctx.source_graphic().height()),
            )
            .map_err(|e| {
                if let RenderingError::Cairo(status) = e {
                    FilterError::CairoError(status)
                } else {
                    // FIXME: this is just a dummy value; we should probably have a way to indicate
                    // an error in the underlying drawing process.
                    FilterError::CairoError(cairo::Status::InvalidStatus)
                }
            })?;

        // Clip the output to bounds.
        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        let cr = cairo::Context::new(&output_surface);
        cr.rectangle(
            f64::from(bounds.x0),
            f64::from(bounds.y0),
            f64::from(bounds.x1 - bounds.x0),
            f64::from(bounds.y1 - bounds.y0),
        );
        cr.clip();
        cr.set_source_surface(&surface, 0f64, 0f64);
        cr.paint();

        Ok(output_surface)
    }

    /// Renders the filter if the source is an external image.
    fn render_external_image(
        &self,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
        bounds_builder: BoundsBuilder<'_>,
        href: &Href,
    ) -> Result<ImageSurface, FilterError> {
        let url = if let Href::PlainUri(ref url) = *href {
            url
        } else {
            unreachable!();
        };

        // FIXME: translate the error better here
        let surface = handle::image_surface_new_from_href(self.handle.get() as *mut _, url)
            .map_err(|_| FilterError::InvalidInput)?;

        let output_surface = ImageSurface::create(
            cairo::Format::ARgb32,
            ctx.source_graphic().width(),
            ctx.source_graphic().height(),
        )?;

        // TODO: this goes through a f64->i32->f64 conversion.
        let render_bounds = bounds_builder.into_irect_without_clipping(draw_ctx);
        let aspect = self.aspect.get();
        let (x, y, w, h) = aspect.compute(
            f64::from(surface.get_width()),
            f64::from(surface.get_height()),
            f64::from(render_bounds.x0),
            f64::from(render_bounds.y0),
            f64::from(render_bounds.x1 - render_bounds.x0),
            f64::from(render_bounds.y1 - render_bounds.y0),
        );

        if w != 0f64 && h != 0f64 {
            let ptn = cairo::SurfacePattern::create(&surface);
            let mut matrix = cairo::Matrix::new(
                w / f64::from(surface.get_width()),
                0f64,
                0f64,
                h / f64::from(surface.get_height()),
                x,
                y,
            );
            matrix.invert();
            ptn.set_matrix(matrix);

            let bounds = bounds_builder.into_irect(draw_ctx);
            let cr = cairo::Context::new(&output_surface);
            cr.rectangle(
                f64::from(bounds.x0),
                f64::from(bounds.y0),
                f64::from(bounds.x1 - bounds.x0),
                f64::from(bounds.y1 - bounds.y0),
            );
            cr.clip();
            cr.set_source(&cairo::Pattern::SurfacePattern(ptn));
            cr.paint();
        }

        Ok(output_surface)
    }
}

impl NodeTrait for Image {
    fn set_atts(
        &self,
        node: &RsvgNode,
        handle: *const RsvgHandle,
        pbag: &PropertyBag<'_>,
    ) -> NodeResult {
        self.base.set_atts(node, handle, pbag)?;

        for (_key, attr, value) in pbag.iter() {
            match attr {
                Attribute::PreserveAspectRatio => {
                    self.aspect.set(parse("preserveAspectRatio", value, ())?)
                }

                // "path" is used by some older Adobe Illustrator versions
                Attribute::XlinkHref | Attribute::Path => {
                    drop(self.href.replace(Some(value.to_string())))
                }
                _ => (),
            }
        }

        self.handle.set(handle);

        Ok(())
    }
}

impl Filter for Image {
    fn render(
        &self,
        _node: &RsvgNode,
        ctx: &FilterContext,
        draw_ctx: &mut DrawingCtx<'_>,
    ) -> Result<FilterResult, FilterError> {
        let href_str = self.href.borrow();
        let href_str = href_str.as_ref().ok_or(FilterError::InvalidInput)?;

        let bounds_builder = self.base.get_bounds(ctx);
        let bounds = bounds_builder.into_irect(draw_ctx);

        let href = Href::parse(href_str).map_err(|_| FilterError::InvalidInput)?;

        let output_surface = match href {
            Href::PlainUri(_) => {
                self.render_external_image(ctx, draw_ctx, bounds_builder, &href)?
            }
            _ => self.render_node(ctx, draw_ctx, bounds, &href)?,
        };

        Ok(FilterResult {
            name: self.base.result.borrow().clone(),
            output: FilterOutput {
                surface: SharedImageSurface::new(output_surface, SurfaceType::SRgb)?,
                bounds,
            },
        })
    }

    #[inline]
    fn is_affected_by_color_interpolation_filters(&self) -> bool {
        false
    }
}
<|endoftext|>


<commit_before>//! The project module takes care of muxed related initialization. Locating the
//! users home directory. Finding the desired config files, and reading the
//! configs in.
pub mod parser;

use command::{Attach, Commands, SwitchClient};
use common::project_paths::ProjectPaths;
use first_run::check_first_run;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use tmux::has_session;
use yaml_rust::{Yaml, YamlLoader};

/// Using the provided project name, locate the path to that project file. It
/// should be something similar to: `~/.muxed/my_project.yml`
/// Read in the contents of the config (which should be Yaml), and parse the
/// contents as yaml.
///
/// # Examples
///
/// Given the project name "compiler" and a project file found at:
/// `~/.muxed/compiler.yml`.
///
/// ```
/// let yaml: Result<Vec<Yaml>, String> = read("compiler".to_string());
/// ```
///
/// `project_name`: The name of the project, corresponding to the project config
/// file.
pub fn read(project_name: &str, project_paths: &ProjectPaths) -> Result<Vec<Yaml>, String> {
    check_first_run(&project_paths.project_directory)?;

    let mut file = File::open(&project_paths.project_file).map_err(|e| format!("No project configuration file was found with the name `{}` in the directory `{}`. Received error: {}", project_name, &project_paths.project_directory.display(), e.to_string()))?;
    let mut contents = String::new();

    file.read_to_string(&mut contents)
        .map_err(|e| e.to_string())?;

    let parsed_yaml = YamlLoader::load_from_str(&contents).map_err(|e| e.to_string())?;

    Ok(parsed_yaml)
}

/// Find out if a tmux session is already active with this name. If it is active
/// return `Some<Commands::Attach>` with a command to attach to the session. If a
/// session is not active return None and let the app carry on.
pub fn session_exists(project_name: &str) -> Option<Commands> {
    if has_session(project_name).success() {
        Some(open(project_name))
    } else {
        None
    }
}

/// Check to see how we want to open the project. Do we need to attach to a new
/// tmux session or can we switch the client from a running session.
pub fn open(project_name: &str) -> Commands {
    if env::var_os("TMUX").is_some() {
        SwitchClient::new(&project_name).into()
    } else {
        Attach::new(&project_name, None).into()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use common::rand_names;
    use std::fs;

    #[test]
    fn missing_file_returns_err() {
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", "");
        let result = read(&String::from("not_a_file"), &project_paths);
        assert!(result.is_err())
    }

    #[test]
    fn poorly_formatted_file_returns_err() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(b"mix: [1,2,3]: muxed");
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_err());
    }

    #[test]
    fn good_file_returns_ok() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(
            b"---
    windows: ['cargo', 'vim', 'git']
    ",
        );
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_ok());
    }
}
<commit_msg>refactor: Magic string to static variable<commit_after>//! The project module takes care of muxed related initialization. Locating the
//! users home directory. Finding the desired config files, and reading the
//! configs in.
pub mod parser;

use command::{Attach, Commands, SwitchClient};
use common::project_paths::ProjectPaths;
use first_run::check_first_run;
use std::env;
use std::fs::File;
use std::io::prelude::*;
use tmux::has_session;
use yaml_rust::{Yaml, YamlLoader};

static TMUX_ENV_VAR: &str = "TMUX";

/// Using the provided project name, locate the path to that project file. It
/// should be something similar to: `~/.muxed/my_project.yml`
/// Read in the contents of the config (which should be Yaml), and parse the
/// contents as yaml.
///
/// # Examples
///
/// Given the project name "compiler" and a project file found at:
/// `~/.muxed/compiler.yml`.
///
/// ```
/// let yaml: Result<Vec<Yaml>, String> = read("compiler".to_string());
/// ```
///
/// `project_name`: The name of the project, corresponding to the project config
/// file.
pub fn read(project_name: &str, project_paths: &ProjectPaths) -> Result<Vec<Yaml>, String> {
    check_first_run(&project_paths.project_directory)?;

    let mut file = File::open(&project_paths.project_file).map_err(|e| format!("No project configuration file was found with the name `{}` in the directory `{}`. Received error: {}", project_name, &project_paths.project_directory.display(), e.to_string()))?;
    let mut contents = String::new();

    file.read_to_string(&mut contents)
        .map_err(|e| e.to_string())?;

    let parsed_yaml = YamlLoader::load_from_str(&contents).map_err(|e| e.to_string())?;

    Ok(parsed_yaml)
}

/// Find out if a tmux session is already active with this name. If it is active
/// return `Some<Commands::Attach>` with a command to attach to the session. If a
/// session is not active return None and let the app carry on.
pub fn session_exists(project_name: &str) -> Option<Commands> {
    if has_session(project_name).success() {
        Some(open(project_name))
    } else {
        None
    }
}

/// Check to see how we want to open the project. Do we need to attach to a new
/// tmux session or can we switch the client from a running session.
pub fn open(project_name: &str) -> Commands {
    if env::var_os(TMUX_ENV_VAR).is_some() {
        SwitchClient::new(&project_name).into()
    } else {
        Attach::new(&project_name, None).into()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use common::rand_names;
    use std::fs;

    #[test]
    fn missing_file_returns_err() {
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", "");
        let result = read(&String::from("not_a_file"), &project_paths);
        assert!(result.is_err())
    }

    #[test]
    fn poorly_formatted_file_returns_err() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(b"mix: [1,2,3]: muxed");
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_err());
    }

    #[test]
    fn good_file_returns_ok() {
        let name = rand_names::project_file_name();
        let project_paths = ProjectPaths::from_strs("/tmp", ".muxed", &name);

        let _ = fs::create_dir(&project_paths.project_directory);
        let mut buffer = File::create(&project_paths.project_file).unwrap();
        let _ = buffer.write(
            b"---
    windows: ['cargo', 'vim', 'git']
    ",
        );
        let _ = buffer.sync_all();

        let result = read(&name, &project_paths);
        let _ = fs::remove_file(&project_paths.project_file);
        assert!(result.is_ok());
    }
}
<|endoftext|>


<commit_before>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/threads.rs
// - Thread management
use _common::*;

mod thread;
mod sleep_object;

pub use self::thread::Thread;
use self::thread::RunState;

pub use self::sleep_object::{SleepObject,SleepObjectRef};

pub type EventMask = u32;

/// A borrowed Box<Thread>, released when borrow expires
struct BorrowedThread(Option<Box<Thread>>);

pub struct WaitQueue
{
	list: ThreadList,
}
struct ThreadList
{
	first: Option<Box<Thread>>,
	last: Option<*mut Thread>
}
unsafe impl Send for ThreadList {}
const THREADLIST_INIT: ThreadList = ThreadList {first: None, last: None};
pub const WAITQUEUE_INIT: WaitQueue = WaitQueue { list: THREADLIST_INIT };

// ----------------------------------------------
// Statics
//static s_all_threads:	::sync::Mutex<Map<uint,*const Thread>> = mutex_init!(Map{});
#[allow(non_upper_case_globals)]
static s_runnable_threads: ::sync::Spinlock<ThreadList> = spinlock_init!(THREADLIST_INIT);

// ----------------------------------------------
// Code
pub fn init()
{
	let mut tid0 = Thread::new_boxed();
	tid0.set_name( String::from_str("ThreadZero") );
	tid0.cpu_state = ::arch::threads::init_tid0_state();
	::arch::threads::set_thread_ptr( tid0 )
}

pub fn yield_time()
{
	s_runnable_threads.lock().push( get_cur_thread() );
	reschedule();
}

fn reschedule()
{
	// 1. Get next thread
	let thread = get_thread_to_run();
	match thread
	{
	None => {
		// Wait? How is there nothing to run?
		log_warning!("BUGCHECK: No runnable threads");
		},
	Some(t) => {
		// 2. Switch to next thread
		log_debug!("Task switch to {:?}", t);
		::arch::threads::switch_to(t);
		}
	}
}

fn get_cur_thread() -> Box<Thread>
{
	::arch::threads::get_thread_ptr().unwrap()
}
fn rel_cur_thread(t: Box<Thread>)
{
	::arch::threads::set_thread_ptr(t)
}
fn borrow_cur_thread() -> BorrowedThread
{
	BorrowedThread( Some(get_cur_thread()) )
}

fn get_thread_to_run() -> Option<Box<Thread>>
{
        let _irq_lock = ::arch::sync::hold_interrupts();
	let mut handle = s_runnable_threads.lock();
	if handle.empty()
	{
		// WTF? At least an idle thread should be ready
		None
	}
	else
	{
		// 2. Pop off a new thread
		handle.pop()
	}
}

impl ThreadList
{
	pub fn empty(&self) -> bool
	{
		self.first.is_none()
	}
	pub fn pop(&mut self) -> Option<Box<Thread>>
	{
		match self.first.take()
		{
		Some(mut t) => {
			self.first = t.next.take();
			if self.first.is_none() {
				self.last = None;
			}
			Some(t)
			},
		None => None
		}
	}
	pub fn push(&mut self, t: Box<Thread>)
	{
		assert!(t.next.is_none());
		// Save a pointer to the allocation
		let ptr = &*t as *const Thread as *mut Thread;
		//log_debug!("Pushing thread {:?}", t);
		// 2. Tack thread onto end
		if self.first.is_some()
		{
			assert!(self.last.is_some());
			// Using unsafe and rawptr deref here is safe, because WaitQueue should be
			// locked (and nobody has any of the list items borrowed)
			unsafe {
				let last_ref = &mut *self.last.unwrap();
				assert!(last_ref.next.is_none());
				last_ref.next = Some(t);
			}
		}
		else
		{
			assert!(self.last.is_none());
			self.first = Some(t);
		}
		self.last = Some(ptr);
	}
}

impl Drop for BorrowedThread
{
	fn drop(&mut self) {
		rel_cur_thread(self.0.take().unwrap())
	}
}
impl ::core::ops::Deref for BorrowedThread
{
	type Target = Thread;
	fn deref(&self) -> &Thread { &**self.0.as_ref().unwrap() }
}

impl WaitQueue
{
	pub fn wait<'a>(&mut self, lock_handle: ::arch::sync::HeldSpinlock<'a,bool>)
	{
		// - Prevent interrupts from firing while we mess with the thread
		let _irq_lock = ::arch::sync::hold_interrupts();

		// 1. Lock global list?
		let mut cur = get_cur_thread();
		// - Keep rawptr kicking around for debug purposes
		cur.set_state( RunState::ListWait(self as *mut _ as *const _) );
		// 2. Push current thread into waiting list
		self.list.push(cur);
		// 3. Unlock protector, and allow IRQs once more
		::core::mem::drop(lock_handle);
		::core::mem::drop(_irq_lock);
		// 4. Reschedule, and should return with state changed to run
		reschedule();

		let cur = get_cur_thread();
		cur.assert_active();
		rel_cur_thread(cur);
	}
        pub fn has_waiter(&self) -> bool
        {
                ! self.list.empty()
        }
	pub fn wake_one(&mut self)
	{
		match self.list.pop()
		{
		Some(mut t) => {
			t.set_state( RunState::Runnable );
                        let _irq_lock = ::arch::sync::hold_interrupts();
			s_runnable_threads.lock().push(t);
			},
		None => {}
		}
	}
}

// vim: ft=rust

<commit_msg>(minor) Twiddling commenting in threads<commit_after>// "Tifflin" Kernel
// - By John Hodge (thePowersGang)
//
// Core/threads.rs
// - Thread management
use _common::*;

mod thread;
mod sleep_object;

pub use self::thread::Thread;
use self::thread::RunState;

pub use self::sleep_object::{SleepObject,SleepObjectRef};

pub type EventMask = u32;

/// A borrowed Box<Thread>, released when borrow expires
struct BorrowedThread(Option<Box<Thread>>);

pub struct WaitQueue
{
	list: ThreadList,
}
struct ThreadList
{
	first: Option<Box<Thread>>,
	last: Option<*mut Thread>
}
unsafe impl Send for ThreadList {}
const THREADLIST_INIT: ThreadList = ThreadList {first: None, last: None};
pub const WAITQUEUE_INIT: WaitQueue = WaitQueue { list: THREADLIST_INIT };

// ----------------------------------------------
// Statics
//static s_all_threads:	::sync::Mutex<Map<uint,*const Thread>> = mutex_init!(Map{});
#[allow(non_upper_case_globals)]
static s_runnable_threads: ::sync::Spinlock<ThreadList> = spinlock_init!(THREADLIST_INIT);

// ----------------------------------------------
// Code
pub fn init()
{
	let mut tid0 = Thread::new_boxed();
	tid0.set_name( String::from_str("ThreadZero") );
	tid0.cpu_state = ::arch::threads::init_tid0_state();
	::arch::threads::set_thread_ptr( tid0 )
}

pub fn yield_time()
{
	s_runnable_threads.lock().push( get_cur_thread() );
	reschedule();
}

fn reschedule()
{
	// 1. Get next thread
	let thread = get_thread_to_run();
	match thread
	{
	None => {
		// Wait? How is there nothing to run?
		log_warning!("BUGCHECK: No runnable threads");
		},
	Some(t) => {
		// 2. Switch to next thread
		log_debug!("Task switch to {:?}", t);
		::arch::threads::switch_to(t);
		}
	}
}

fn get_cur_thread() -> Box<Thread>
{
	::arch::threads::get_thread_ptr().unwrap()
}
fn rel_cur_thread(t: Box<Thread>)
{
	::arch::threads::set_thread_ptr(t)
}
fn borrow_cur_thread() -> BorrowedThread
{
	BorrowedThread( Some(get_cur_thread()) )
}

fn get_thread_to_run() -> Option<Box<Thread>>
{
        let _irq_lock = ::arch::sync::hold_interrupts();
	let mut handle = s_runnable_threads.lock();
	if handle.empty()
	{
		// WTF? At least an idle thread should be ready
		None
	}
	else
	{
		// 2. Pop off a new thread
		handle.pop()
	}
}

impl ThreadList
{
	pub fn empty(&self) -> bool
	{
		self.first.is_none()
	}
	pub fn pop(&mut self) -> Option<Box<Thread>>
	{
		match self.first.take()
		{
		Some(mut t) => {
			self.first = t.next.take();
			if self.first.is_none() {
				self.last = None;
			}
			Some(t)
			},
		None => None
		}
	}
	pub fn push(&mut self, t: Box<Thread>)
	{
		//log_debug!("Pushing thread {:?}", t);
		assert!(t.next.is_none());
		// Save a pointer to the allocation (for list tail)
		let ptr = &*t as *const Thread as *mut Thread;
		// 2. Tack thread onto end
		if self.first.is_some()
		{
			assert!(self.last.is_some());
			// Using unsafe and rawptr deref here is safe, because WaitQueue should be
			// locked (and nobody has any of the list items borrowed)
			unsafe {
				let last_ref = &mut *self.last.unwrap();
				assert!(last_ref.next.is_none());
				last_ref.next = Some(t);
			}
		}
		else
		{
			assert!(self.last.is_none());
			self.first = Some(t);
		}
		self.last = Some(ptr);
	}
}

impl Drop for BorrowedThread
{
	fn drop(&mut self) {
		rel_cur_thread(self.0.take().unwrap())
	}
}
impl ::core::ops::Deref for BorrowedThread
{
	type Target = Thread;
	fn deref(&self) -> &Thread { &**self.0.as_ref().unwrap() }
}

impl WaitQueue
{
	pub fn wait<'a>(&mut self, lock_handle: ::arch::sync::HeldSpinlock<'a,bool>)
	{
		// - Prevent interrupts from firing while we mess with the thread
		let _irq_lock = ::arch::sync::hold_interrupts();

		// 1. Lock global list?
		let mut cur = get_cur_thread();
		// - Keep rawptr kicking around for debug purposes
		cur.set_state( RunState::ListWait(self as *mut _ as *const _) );
		// 2. Push current thread into waiting list
		self.list.push(cur);
		// 3. Unlock protector, and allow IRQs once more
		::core::mem::drop(lock_handle);
		::core::mem::drop(_irq_lock);
		// 4. Reschedule, and should return with state changed to run
		reschedule();

		let cur = get_cur_thread();
		cur.assert_active();
		rel_cur_thread(cur);
	}
        pub fn has_waiter(&self) -> bool
        {
                ! self.list.empty()
        }
	pub fn wake_one(&mut self)
	{
		match self.list.pop()
		{
		Some(mut t) => {
			t.set_state( RunState::Runnable );
                        let _irq_lock = ::arch::sync::hold_interrupts();
			s_runnable_threads.lock().push(t);
			},
		None => {}
		}
	}
}

// vim: ft=rust

<|endoftext|>


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

fn main() {
    let x = Some(1);
    let Some(y) = x;
//      ^^^^^^^ERR pattern `None` not covered
//      ^^^^^^^ERR refutable pattern in local binding
//      ^^^^^^^MSG(>=1.39.0-beta) See Also: ↑:1
}
// Bug: https://github.com/rust-lang/rust/issues/64769
// start-msg: ERR(>=1.39.0-beta) not covered
// start-msg: MSG(>=1.39.0-beta) See Primary: ↓:14
<commit_msg>Update tests for 1.40.<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused)]

fn main() {
    let x = Some(1);
    let Some(y) = x;
//      ^^^^^^^ERR pattern `None` not covered
//      ^^^^^^^ERR refutable pattern in local binding
//      ^^^^^^^MSG(>=1.39.0-beta) See Also: ↑:1
//      ^^^^^^^NOTE(>=1.40.0-beta) `let` bindings require
//      ^^^^^^^NOTE(>=1.40.0-beta) for more information
//  ^^^^^^^^^^^^^^^^HELP(>=1.40.0-beta) you might want to use `if let`
//  ^^^^^^^^^^^^^^^^HELP(>=1.40.0-beta) /Accept Replacement:.*/
}
// Bug: https://github.com/rust-lang/rust/issues/64769
// start-msg: ERR(>=1.39.0-beta) not covered
// start-msg: MSG(>=1.39.0-beta) See Primary: ↓:14
<|endoftext|>


<commit_before>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::parser;
    use robin_core::ast::Expression;

    #[test]
    fn booleans_should_return_a_boolean_node() {
        assert_eq!(parser::parse("true".to_string(),), Expression::Boolean(true))
    }

    #[test]
    fn identifiers_that_look_like_booleans_should_return_identifiers() {
        assert_eq!(parser::parse("truedog".to_string(),), Expression::Identifier("truedog".to_string()))
    }

    #[test]
    fn identifiers_should_return_a_identifier_node() {
        assert_eq!(parser::parse("hello".to_string(),), Expression::Identifier("hello".to_string()))
    }

    #[test]
    fn decimals_should_return_a_number_node() {
        assert_eq!(parser::parse("47".to_string(),), Expression::Number(47.0))
    }

    #[test]
    fn exponents_should_return_a_number_node() {
        assert_eq!(parser::parse("5e1".to_string(),), Expression::Number(50.0))
    }

    #[test]
    fn binary_should_return_a_number_node() {
        assert_eq!(parser::parse("0b1".to_string(),), Expression::Number(1.0))
    }

    #[test]
    fn octal_should_return_a_number_node() {
        assert_eq!(parser::parse("0o2".to_string(),), Expression::Number(2.0))
    }

    #[test]
    fn hexadecimal_should_return_a_number_node() {
        assert_eq!(parser::parse("0xA".to_string(),), Expression::Number(10.0))
    }
}
<commit_msg>Update tests<commit_after>extern crate robin_core;

#[cfg(test)]
mod parser_tests {
    use robin_core::parser;
    use robin_core::ast::Expression;

    #[test]
    fn booleans_should_return_a_boolean_node() {
        assert_eq!(parser::parse("true".to_string(),), Ok(Expression::Boolean(true)))
    }

    #[test]
    fn identifiers_that_look_like_booleans_should_return_identifiers() {
        assert_eq!(parser::parse("truedog".to_string(),), Ok(Expression::Identifier("truedog".to_string())))
    }

    #[test]
    fn identifiers_should_return_a_identifier_node() {
        assert_eq!(parser::parse("hello".to_string(),), Ok(Expression::Identifier("hello".to_string())))
    }

    #[test]
    fn decimals_should_return_a_number_node() {
        assert_eq!(parser::parse("47".to_string(),), Ok(Expression::Number(47.0)))
    }

    #[test]
    fn exponents_should_return_a_number_node() {
        assert_eq!(parser::parse("5e1".to_string(),), Ok(Expression::Number(50.0)))
    }

    #[test]
    fn binary_should_return_a_number_node() {
        assert_eq!(parser::parse("0b1".to_string(),), Ok(Expression::Number(1.0)))
    }

    #[test]
    fn octal_should_return_a_number_node() {
        assert_eq!(parser::parse("0o2".to_string(),), Ok(Expression::Number(2.0)))
    }

    #[test]
    fn hexadecimal_should_return_a_number_node() {
        assert_eq!(parser::parse("0xA".to_string(),), Ok(Expression::Number(10.0)))
    }
}
<|endoftext|>


<commit_before>use crate::codec::{BackendMessage, BackendMessages, FrontendMessage, PostgresCodec};
use crate::copy_in::CopyInReceiver;
use crate::error::DbError;
use crate::maybe_tls_stream::MaybeTlsStream;
use crate::{AsyncMessage, Error, Notification};
use fallible_iterator::FallibleIterator;
use futures::channel::mpsc;
use futures::{ready, Sink, Stream, StreamExt};
use log::trace;
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::collections::{HashMap, VecDeque};
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::codec::Framed;
use tokio::io::{AsyncRead, AsyncWrite};

pub enum RequestMessages {
    Single(FrontendMessage),
    CopyIn(CopyInReceiver),
}

pub struct Request {
    pub messages: RequestMessages,
    pub sender: mpsc::Sender<BackendMessages>,
}

pub struct Response {
    sender: mpsc::Sender<BackendMessages>,
}

#[derive(PartialEq, Debug)]
enum State {
    Active,
    Terminating,
    Closing,
}

/// A connection to a PostgreSQL database.
///
/// This is one half of what is returned when a new connection is established. It performs the actual IO with the
/// server, and should generally be spawned off onto an executor to run in the background.
///
/// `Connection` implements `Future`, and only resolves when the connection is closed, either because a fatal error has
/// occurred, or because its associated `Client` has dropped and all outstanding work has completed.
#[must_use = "futures do nothing unless polled"]
pub struct Connection<S, T> {
    stream: Framed<MaybeTlsStream<S, T>, PostgresCodec>,
    parameters: HashMap<String, String>,
    receiver: mpsc::UnboundedReceiver<Request>,
    pending_request: Option<RequestMessages>,
    pending_response: Option<BackendMessage>,
    responses: VecDeque<Response>,
    state: State,
}

impl<S, T> Connection<S, T>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: AsyncRead + AsyncWrite + Unpin,
{
    pub(crate) fn new(
        stream: Framed<MaybeTlsStream<S, T>, PostgresCodec>,
        parameters: HashMap<String, String>,
        receiver: mpsc::UnboundedReceiver<Request>,
    ) -> Connection<S, T> {
        Connection {
            stream,
            parameters,
            receiver,
            pending_request: None,
            pending_response: None,
            responses: VecDeque::new(),
            state: State::Active,
        }
    }

    /// Returns the value of a runtime parameter for this connection.
    pub fn parameter(&self, name: &str) -> Option<&str> {
        self.parameters.get(name).map(|s| &**s)
    }

    fn poll_response(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<BackendMessage, Error>>> {
        if let Some(message) = self.pending_response.take() {
            trace!("retrying pending response");
            return Poll::Ready(Some(Ok(message)));
        }

        Pin::new(&mut self.stream)
            .poll_next(cx)
            .map(|o| o.map(|r| r.map_err(Error::io)))
    }

    fn poll_read(&mut self, cx: &mut Context<'_>) -> Result<Option<AsyncMessage>, Error> {
        if self.state != State::Active {
            trace!("poll_read: done");
            return Ok(None);
        }

        loop {
            let message = match self.poll_response(cx)? {
                Poll::Ready(Some(message)) => message,
                Poll::Ready(None) => return Err(Error::closed()),
                Poll::Pending => {
                    trace!("poll_read: waiting on response");
                    return Ok(None);
                }
            };

            let (mut messages, request_complete) = match message {
                BackendMessage::Async(Message::NoticeResponse(body)) => {
                    let error = DbError::parse(&mut body.fields()).map_err(Error::parse)?;
                    return Ok(Some(AsyncMessage::Notice(error)));
                }
                BackendMessage::Async(Message::NotificationResponse(body)) => {
                    let notification = Notification {
                        process_id: body.process_id(),
                        channel: body.channel().map_err(Error::parse)?.to_string(),
                        payload: body.message().map_err(Error::parse)?.to_string(),
                    };
                    return Ok(Some(AsyncMessage::Notification(notification)));
                }
                BackendMessage::Async(Message::ParameterStatus(body)) => {
                    self.parameters.insert(
                        body.name().map_err(Error::parse)?.to_string(),
                        body.value().map_err(Error::parse)?.to_string(),
                    );
                    continue;
                }
                BackendMessage::Async(_) => unreachable!(),
                BackendMessage::Normal {
                    messages,
                    request_complete,
                } => (messages, request_complete),
            };

            let mut response = match self.responses.pop_front() {
                Some(response) => response,
                None => match messages.next().map_err(Error::parse)? {
                    Some(Message::ErrorResponse(error)) => return Err(Error::db(error)),
                    _ => return Err(Error::unexpected_message()),
                },
            };

            match response.sender.poll_ready(cx) {
                Poll::Ready(Ok(())) => {
                    let _ = response.sender.start_send(messages);
                    if !request_complete {
                        self.responses.push_front(response);
                    }
                }
                Poll::Ready(Err(_)) => {
                    // we need to keep paging through the rest of the messages even if the receiver's hung up
                    if !request_complete {
                        self.responses.push_front(response);
                    }
                }
                Poll::Pending => {
                    self.responses.push_front(response);
                    self.pending_response = Some(BackendMessage::Normal {
                        messages,
                        request_complete,
                    });
                    trace!("poll_read: waiting on sender");
                    return Ok(None);
                }
            }
        }
    }

    fn poll_request(&mut self, cx: &mut Context<'_>) -> Poll<Option<RequestMessages>> {
        if let Some(messages) = self.pending_request.take() {
            trace!("retrying pending request");
            return Poll::Ready(Some(messages));
        }

        match self.receiver.poll_next_unpin(cx) {
            Poll::Ready(Some(request)) => {
                trace!("polled new request");
                self.responses.push_back(Response {
                    sender: request.sender,
                });
                Poll::Ready(Some(request.messages))
            }
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    fn poll_write(&mut self, cx: &mut Context<'_>) -> Result<bool, Error> {
        loop {
            if self.state == State::Closing {
                trace!("poll_write: done");
                return Ok(false);
            }

            let request = match self.poll_request(cx) {
                Poll::Ready(Some(request)) => request,
                Poll::Ready(None) if self.responses.is_empty() && self.state == State::Active => {
                    trace!("poll_write: at eof, terminating");
                    self.state = State::Terminating;
                    let mut request = vec![];
                    frontend::terminate(&mut request);
                    RequestMessages::Single(FrontendMessage::Raw(request))
                }
                Poll::Ready(None) => {
                    trace!(
                        "poll_write: at eof, pending responses {}",
                        self.responses.len()
                    );
                    return Ok(true);
                }
                Poll::Pending => {
                    trace!("poll_write: waiting on request");
                    return Ok(true);
                }
            };

            if let Poll::Pending = Pin::new(&mut self.stream)
                .poll_ready(cx)
                .map_err(Error::io)?
            {
                trace!("poll_write: waiting on socket");
                self.pending_request = Some(request);
                return Ok(false);
            }

            match request {
                RequestMessages::Single(request) => {
                    Pin::new(&mut self.stream)
                        .start_send(request)
                        .map_err(Error::io)?;
                    if self.state == State::Terminating {
                        trace!("poll_write: sent eof, closing");
                        self.state = State::Closing;
                    }
                }
                RequestMessages::CopyIn(mut receiver) => {
                    let message = match receiver.poll_next_unpin(cx) {
                        Poll::Ready(Some(message)) => message,
                        Poll::Ready(None) => {
                            trace!("poll_write: finished copy_in request");
                            continue;
                        }
                        Poll::Pending => {
                            trace!("poll_write: waiting on copy_in stream");
                            self.pending_request = Some(RequestMessages::CopyIn(receiver));
                            return Ok(true);
                        }
                    };
                    Pin::new(&mut self.stream)
                        .start_send(message)
                        .map_err(Error::io)?;
                    self.pending_request = Some(RequestMessages::CopyIn(receiver));
                }
            }
        }
    }

    fn poll_flush(&mut self, cx: &mut Context<'_>) -> Result<(), Error> {
        match Pin::new(&mut self.stream)
            .poll_flush(cx)
            .map_err(Error::io)?
        {
            Poll::Ready(()) => trace!("poll_flush: flushed"),
            Poll::Pending => trace!("poll_flush: waiting on socket"),
        }
        Ok(())
    }

    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
        if self.state != State::Closing {
            return Poll::Pending;
        }

        match Pin::new(&mut self.stream)
            .poll_close(cx)
            .map_err(Error::io)?
        {
            Poll::Ready(()) => {
                trace!("poll_shutdown: complete");
                Poll::Ready(Ok(()))
            }
            Poll::Pending => {
                trace!("poll_shutdown: waiting on socket");
                Poll::Pending
            }
        }
    }

    pub fn poll_message(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<AsyncMessage, Error>>> {
        let message = self.poll_read(cx)?;
        let want_flush = self.poll_write(cx)?;
        if want_flush {
            self.poll_flush(cx)?;
        }
        match message {
            Some(message) => Poll::Ready(Some(Ok(message))),
            None => match self.poll_shutdown(cx) {
                Poll::Ready(Ok(())) => Poll::Ready(None),
                Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))),
                Poll::Pending => Poll::Pending,
            },
        }
    }
}

impl<S, T> Future for Connection<S, T>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Output = Result<(), Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
        while let Some(_) = ready!(Pin::as_mut(&mut self).poll_message(cx)?) {}
        Poll::Ready(Ok(()))
    }
}
<commit_msg>Simplify logic a bit<commit_after>use crate::codec::{BackendMessage, BackendMessages, FrontendMessage, PostgresCodec};
use crate::copy_in::CopyInReceiver;
use crate::error::DbError;
use crate::maybe_tls_stream::MaybeTlsStream;
use crate::{AsyncMessage, Error, Notification};
use fallible_iterator::FallibleIterator;
use futures::channel::mpsc;
use futures::{ready, Sink, Stream, StreamExt};
use log::trace;
use postgres_protocol::message::backend::Message;
use postgres_protocol::message::frontend;
use std::collections::{HashMap, VecDeque};
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::codec::Framed;
use tokio::io::{AsyncRead, AsyncWrite};

pub enum RequestMessages {
    Single(FrontendMessage),
    CopyIn(CopyInReceiver),
}

pub struct Request {
    pub messages: RequestMessages,
    pub sender: mpsc::Sender<BackendMessages>,
}

pub struct Response {
    sender: mpsc::Sender<BackendMessages>,
}

#[derive(PartialEq, Debug)]
enum State {
    Active,
    Terminating,
    Closing,
}

/// A connection to a PostgreSQL database.
///
/// This is one half of what is returned when a new connection is established. It performs the actual IO with the
/// server, and should generally be spawned off onto an executor to run in the background.
///
/// `Connection` implements `Future`, and only resolves when the connection is closed, either because a fatal error has
/// occurred, or because its associated `Client` has dropped and all outstanding work has completed.
#[must_use = "futures do nothing unless polled"]
pub struct Connection<S, T> {
    stream: Framed<MaybeTlsStream<S, T>, PostgresCodec>,
    parameters: HashMap<String, String>,
    receiver: mpsc::UnboundedReceiver<Request>,
    pending_request: Option<RequestMessages>,
    pending_response: Option<BackendMessage>,
    responses: VecDeque<Response>,
    state: State,
}

impl<S, T> Connection<S, T>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: AsyncRead + AsyncWrite + Unpin,
{
    pub(crate) fn new(
        stream: Framed<MaybeTlsStream<S, T>, PostgresCodec>,
        parameters: HashMap<String, String>,
        receiver: mpsc::UnboundedReceiver<Request>,
    ) -> Connection<S, T> {
        Connection {
            stream,
            parameters,
            receiver,
            pending_request: None,
            pending_response: None,
            responses: VecDeque::new(),
            state: State::Active,
        }
    }

    /// Returns the value of a runtime parameter for this connection.
    pub fn parameter(&self, name: &str) -> Option<&str> {
        self.parameters.get(name).map(|s| &**s)
    }

    fn poll_response(
        &mut self,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<BackendMessage, Error>>> {
        if let Some(message) = self.pending_response.take() {
            trace!("retrying pending response");
            return Poll::Ready(Some(Ok(message)));
        }

        Pin::new(&mut self.stream)
            .poll_next(cx)
            .map(|o| o.map(|r| r.map_err(Error::io)))
    }

    fn poll_read(&mut self, cx: &mut Context<'_>) -> Result<Option<AsyncMessage>, Error> {
        if self.state != State::Active {
            trace!("poll_read: done");
            return Ok(None);
        }

        loop {
            let message = match self.poll_response(cx)? {
                Poll::Ready(Some(message)) => message,
                Poll::Ready(None) => return Err(Error::closed()),
                Poll::Pending => {
                    trace!("poll_read: waiting on response");
                    return Ok(None);
                }
            };

            let (mut messages, request_complete) = match message {
                BackendMessage::Async(Message::NoticeResponse(body)) => {
                    let error = DbError::parse(&mut body.fields()).map_err(Error::parse)?;
                    return Ok(Some(AsyncMessage::Notice(error)));
                }
                BackendMessage::Async(Message::NotificationResponse(body)) => {
                    let notification = Notification {
                        process_id: body.process_id(),
                        channel: body.channel().map_err(Error::parse)?.to_string(),
                        payload: body.message().map_err(Error::parse)?.to_string(),
                    };
                    return Ok(Some(AsyncMessage::Notification(notification)));
                }
                BackendMessage::Async(Message::ParameterStatus(body)) => {
                    self.parameters.insert(
                        body.name().map_err(Error::parse)?.to_string(),
                        body.value().map_err(Error::parse)?.to_string(),
                    );
                    continue;
                }
                BackendMessage::Async(_) => unreachable!(),
                BackendMessage::Normal {
                    messages,
                    request_complete,
                } => (messages, request_complete),
            };

            let mut response = match self.responses.pop_front() {
                Some(response) => response,
                None => match messages.next().map_err(Error::parse)? {
                    Some(Message::ErrorResponse(error)) => return Err(Error::db(error)),
                    _ => return Err(Error::unexpected_message()),
                },
            };

            match response.sender.poll_ready(cx) {
                Poll::Ready(Ok(())) => {
                    let _ = response.sender.start_send(messages);
                    if !request_complete {
                        self.responses.push_front(response);
                    }
                }
                Poll::Ready(Err(_)) => {
                    // we need to keep paging through the rest of the messages even if the receiver's hung up
                    if !request_complete {
                        self.responses.push_front(response);
                    }
                }
                Poll::Pending => {
                    self.responses.push_front(response);
                    self.pending_response = Some(BackendMessage::Normal {
                        messages,
                        request_complete,
                    });
                    trace!("poll_read: waiting on sender");
                    return Ok(None);
                }
            }
        }
    }

    fn poll_request(&mut self, cx: &mut Context<'_>) -> Poll<Option<RequestMessages>> {
        if let Some(messages) = self.pending_request.take() {
            trace!("retrying pending request");
            return Poll::Ready(Some(messages));
        }

        match self.receiver.poll_next_unpin(cx) {
            Poll::Ready(Some(request)) => {
                trace!("polled new request");
                self.responses.push_back(Response {
                    sender: request.sender,
                });
                Poll::Ready(Some(request.messages))
            }
            Poll::Ready(None) => Poll::Ready(None),
            Poll::Pending => Poll::Pending,
        }
    }

    fn poll_write(&mut self, cx: &mut Context<'_>) -> Result<bool, Error> {
        loop {
            if self.state == State::Closing {
                trace!("poll_write: done");
                return Ok(false);
            }

            if let Poll::Pending = Pin::new(&mut self.stream)
                .poll_ready(cx)
                .map_err(Error::io)?
            {
                trace!("poll_write: waiting on socket");
                return Ok(false);
            }

            let request = match self.poll_request(cx) {
                Poll::Ready(Some(request)) => request,
                Poll::Ready(None) if self.responses.is_empty() && self.state == State::Active => {
                    trace!("poll_write: at eof, terminating");
                    self.state = State::Terminating;
                    let mut request = vec![];
                    frontend::terminate(&mut request);
                    RequestMessages::Single(FrontendMessage::Raw(request))
                }
                Poll::Ready(None) => {
                    trace!(
                        "poll_write: at eof, pending responses {}",
                        self.responses.len()
                    );
                    return Ok(true);
                }
                Poll::Pending => {
                    trace!("poll_write: waiting on request");
                    return Ok(true);
                }
            };

            match request {
                RequestMessages::Single(request) => {
                    Pin::new(&mut self.stream)
                        .start_send(request)
                        .map_err(Error::io)?;
                    if self.state == State::Terminating {
                        trace!("poll_write: sent eof, closing");
                        self.state = State::Closing;
                    }
                }
                RequestMessages::CopyIn(mut receiver) => {
                    let message = match receiver.poll_next_unpin(cx) {
                        Poll::Ready(Some(message)) => message,
                        Poll::Ready(None) => {
                            trace!("poll_write: finished copy_in request");
                            continue;
                        }
                        Poll::Pending => {
                            trace!("poll_write: waiting on copy_in stream");
                            self.pending_request = Some(RequestMessages::CopyIn(receiver));
                            return Ok(true);
                        }
                    };
                    Pin::new(&mut self.stream)
                        .start_send(message)
                        .map_err(Error::io)?;
                    self.pending_request = Some(RequestMessages::CopyIn(receiver));
                }
            }
        }
    }

    fn poll_flush(&mut self, cx: &mut Context<'_>) -> Result<(), Error> {
        match Pin::new(&mut self.stream)
            .poll_flush(cx)
            .map_err(Error::io)?
        {
            Poll::Ready(()) => trace!("poll_flush: flushed"),
            Poll::Pending => trace!("poll_flush: waiting on socket"),
        }
        Ok(())
    }

    fn poll_shutdown(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
        if self.state != State::Closing {
            return Poll::Pending;
        }

        match Pin::new(&mut self.stream)
            .poll_close(cx)
            .map_err(Error::io)?
        {
            Poll::Ready(()) => {
                trace!("poll_shutdown: complete");
                Poll::Ready(Ok(()))
            }
            Poll::Pending => {
                trace!("poll_shutdown: waiting on socket");
                Poll::Pending
            }
        }
    }

    pub fn poll_message(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<AsyncMessage, Error>>> {
        let message = self.poll_read(cx)?;
        let want_flush = self.poll_write(cx)?;
        if want_flush {
            self.poll_flush(cx)?;
        }
        match message {
            Some(message) => Poll::Ready(Some(Ok(message))),
            None => match self.poll_shutdown(cx) {
                Poll::Ready(Ok(())) => Poll::Ready(None),
                Poll::Ready(Err(e)) => Poll::Ready(Some(Err(e))),
                Poll::Pending => Poll::Pending,
            },
        }
    }
}

impl<S, T> Future for Connection<S, T>
where
    S: AsyncRead + AsyncWrite + Unpin,
    T: AsyncRead + AsyncWrite + Unpin,
{
    type Output = Result<(), Error>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
        while let Some(_) = ready!(Pin::as_mut(&mut self).poll_message(cx)?) {}
        Poll::Ready(Ok(()))
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, hash_map::Entry};

use utils::DeterministicState;
use na::{self, Real};
use math::Isometry;
use bounding_volume::{self, BoundingVolume};
use partitioning::BoundingVolumeInterferencesCollector;
use shape::{CompositeShape, Shape};
use query::Proximity;
use pipeline::narrow_phase::{ProximityAlgorithm, ProximityDetector, ProximityDispatcher};

/// Proximity detector between a concave shape and another shape.
pub struct CompositeShapeShapeProximityDetector<N> {
    proximity: Proximity,
    sub_detectors: HashMap<usize, ProximityAlgorithm<N>, DeterministicState>,
    to_delete: Vec<usize>,
    interferences: Vec<usize>,
    intersecting_key: usize,
    flip: bool,
}

impl<N> CompositeShapeShapeProximityDetector<N> {
    /// Creates a new proximity detector between a concave shape and another shape.
    pub fn new(flip: bool) -> CompositeShapeShapeProximityDetector<N> {
        CompositeShapeShapeProximityDetector {
            proximity: Proximity::Disjoint,
            sub_detectors: HashMap::with_hasher(DeterministicState),
            to_delete: Vec::new(),
            interferences: Vec::new(),
            intersecting_key: usize::max_value(),
            flip,
        }
    }
}

impl<N: Real> CompositeShapeShapeProximityDetector<N> {
    fn do_update(
        &mut self,
        dispatcher: &ProximityDispatcher<N>,
        m1: &Isometry<N>,
        g1: &CompositeShape<N>,
        m2: &Isometry<N>,
        g2: &Shape<N>,
        margin: N,
        flip: bool,
    ) {
        // Remove outdated sub detectors.
        for key in self.to_delete.iter() {
            let _ = self.sub_detectors.remove(key);
        }

        self.to_delete.clear();
        self.interferences.clear();

        // First, test if the previously intersecting shapes are still intersecting.
        if self.proximity == Proximity::Intersecting {
            let detector = self.sub_detectors.get_mut(&self.intersecting_key).unwrap();
            g1.map_transformed_part_at(self.intersecting_key, m1, &mut |_, m1, g1| {
                assert!(
                    detector.update(dispatcher, m1, g1, m2, g2, margin),
                    "The shape was no longer valid."
                );
            });

            match detector.proximity() {
                Proximity::Intersecting => return, // Early return.
                Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                Proximity::Disjoint => {}
            }
        }

        self.proximity = Proximity::Disjoint;

        let m12 = na::inverse(m1) * m2.clone();
        let ls_aabb2 = bounding_volume::aabb(g2, &m12).loosened(margin);

        // Update all collisions
        for detector in &mut self.sub_detectors {
            let key = *detector.0;

            if key == self.intersecting_key {
                // We already dealt with that one.
                continue;
            }

            if ls_aabb2.intersects(&g1.aabb_at(key)) {
                g1.map_transformed_part_at(key, m1, &mut |_, m1, g1| {
                    assert!(
                        detector.1.update(dispatcher, m1, g1, m2, g2, margin),
                        "The shape was no longer valid."
                    );
                });

                match detector.1.proximity() {
                    Proximity::Intersecting => {
                        self.proximity = Proximity::Intersecting;
                        self.intersecting_key = *detector.0;
                        return; // No need to search any further.
                    }
                    Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                    Proximity::Disjoint => {}
                }
            } else {
                // FIXME: ask the detector if it wants to be removed or not
                self.to_delete.push(key);
            }
        }

        // Find new proximities.
        {
            let mut visitor =
                BoundingVolumeInterferencesCollector::new(&ls_aabb2, &mut self.interferences);
            g1.bvt().visit(&mut visitor);
        }

        for key in &self.interferences {
            let entry = self.sub_detectors.entry(*key);
            let detector = match entry {
                Entry::Occupied(entry) => Some(entry.into_mut()),
                Entry::Vacant(entry) => {
                    let mut new_detector = None;

                    g1.map_part_at(*key, &mut |_, _, g1| {
                        if flip {
                            new_detector = dispatcher.get_proximity_algorithm(g2, g1)
                        } else {
                            new_detector = dispatcher.get_proximity_algorithm(g1, g2)
                        }
                    });

                    if let Some(new_detector) = new_detector {
                        Some(entry.insert(new_detector))
                    } else {
                        None
                    }
                }
            };

            if let Some(sub_detector) = detector {
                g1.map_transformed_part_at(*key, m1, &mut |_, m1, g1| {
                    if flip {
                        let _ = sub_detector.update(dispatcher, m2, g2, m1, g1, margin);
                    } else {
                        let _ = sub_detector.update(dispatcher, m1, g1, m2, g2, margin);
                    }
                });

                match sub_detector.proximity() {
                    Proximity::Intersecting => {
                        self.proximity = Proximity::Intersecting;
                        self.intersecting_key = *key;
                        return; // No need to search further.
                    }
                    Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                    Proximity::Disjoint => {}
                }
            }
        }

        // Totally disjoints.
        self.intersecting_key = usize::max_value()
    }
}

impl<N: Real> ProximityDetector<N>
    for CompositeShapeShapeProximityDetector<N>
{
    fn update(
        &mut self,
        dispatcher: &ProximityDispatcher<N>,
        m1: &Isometry<N>,
        g1: &Shape<N>,
        m2: &Isometry<N>,
        g2: &Shape<N>,
        margin: N,
    ) -> bool {
        if let Some(cs1) = g1.as_composite_shape() {
            let flip = self.flip;
            self.do_update(dispatcher, m1, cs1, m2, g2, margin, flip);

            true
        } else {
            false
        }
    }

    fn proximity(&self) -> Proximity {
        self.proximity
    }
}<commit_msg>Properly handle the case where the CompositeShapeShapeProximityDetector is flipped.<commit_after>use std::collections::{HashMap, hash_map::Entry};

use utils::DeterministicState;
use na::{self, Real};
use math::Isometry;
use bounding_volume::{self, BoundingVolume};
use partitioning::BoundingVolumeInterferencesCollector;
use shape::{CompositeShape, Shape};
use query::Proximity;
use pipeline::narrow_phase::{ProximityAlgorithm, ProximityDetector, ProximityDispatcher};

/// Proximity detector between a concave shape and another shape.
pub struct CompositeShapeShapeProximityDetector<N> {
    proximity: Proximity,
    sub_detectors: HashMap<usize, ProximityAlgorithm<N>, DeterministicState>,
    to_delete: Vec<usize>,
    interferences: Vec<usize>,
    intersecting_key: usize,
    flip: bool,
}

impl<N> CompositeShapeShapeProximityDetector<N> {
    /// Creates a new proximity detector between a concave shape and another shape.
    pub fn new(flip: bool) -> CompositeShapeShapeProximityDetector<N> {
        CompositeShapeShapeProximityDetector {
            proximity: Proximity::Disjoint,
            sub_detectors: HashMap::with_hasher(DeterministicState),
            to_delete: Vec::new(),
            interferences: Vec::new(),
            intersecting_key: usize::max_value(),
            flip,
        }
    }
}

impl<N: Real> CompositeShapeShapeProximityDetector<N> {
    fn do_update(
        &mut self,
        dispatcher: &ProximityDispatcher<N>,
        m1: &Isometry<N>,
        g1: &CompositeShape<N>,
        m2: &Isometry<N>,
        g2: &Shape<N>,
        margin: N,
        flip: bool,
    ) {
        // Remove outdated sub detectors.
        for key in self.to_delete.iter() {
            let _ = self.sub_detectors.remove(key);
        }

        self.to_delete.clear();
        self.interferences.clear();

        // First, test if the previously intersecting shapes are still intersecting.
        if self.proximity == Proximity::Intersecting {
            let detector = self.sub_detectors.get_mut(&self.intersecting_key).unwrap();
            g1.map_transformed_part_at(self.intersecting_key, m1, &mut |_, m1, g1| {
                assert!(
                    detector.update(dispatcher, m1, g1, m2, g2, margin),
                    "The shape was no longer valid."
                );
            });

            match detector.proximity() {
                Proximity::Intersecting => return, // Early return.
                Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                Proximity::Disjoint => {}
            }
        }

        self.proximity = Proximity::Disjoint;

        let m12 = na::inverse(m1) * m2.clone();
        let ls_aabb2 = bounding_volume::aabb(g2, &m12).loosened(margin);

        // Update all collisions
        for detector in &mut self.sub_detectors {
            let key = *detector.0;

            if key == self.intersecting_key {
                // We already dealt with that one.
                continue;
            }

            if ls_aabb2.intersects(&g1.aabb_at(key)) {
                g1.map_transformed_part_at(key, m1, &mut |_, m1, g1| {
                    assert!(
                        detector.1.update(dispatcher, m1, g1, m2, g2, margin),
                        "The shape was no longer valid."
                    );
                });

                match detector.1.proximity() {
                    Proximity::Intersecting => {
                        self.proximity = Proximity::Intersecting;
                        self.intersecting_key = *detector.0;
                        return; // No need to search any further.
                    }
                    Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                    Proximity::Disjoint => {}
                }
            } else {
                // FIXME: ask the detector if it wants to be removed or not
                self.to_delete.push(key);
            }
        }

        // Find new proximities.
        {
            let mut visitor =
                BoundingVolumeInterferencesCollector::new(&ls_aabb2, &mut self.interferences);
            g1.bvt().visit(&mut visitor);
        }

        for key in &self.interferences {
            let entry = self.sub_detectors.entry(*key);
            let detector = match entry {
                Entry::Occupied(entry) => Some(entry.into_mut()),
                Entry::Vacant(entry) => {
                    let mut new_detector = None;

                    g1.map_part_at(*key, &mut |_, _, g1| {
                        if flip {
                            new_detector = dispatcher.get_proximity_algorithm(g2, g1)
                        } else {
                            new_detector = dispatcher.get_proximity_algorithm(g1, g2)
                        }
                    });

                    if let Some(new_detector) = new_detector {
                        Some(entry.insert(new_detector))
                    } else {
                        None
                    }
                }
            };

            if let Some(sub_detector) = detector {
                g1.map_transformed_part_at(*key, m1, &mut |_, m1, g1| {
                    if flip {
                        let _ = sub_detector.update(dispatcher, m2, g2, m1, g1, margin);
                    } else {
                        let _ = sub_detector.update(dispatcher, m1, g1, m2, g2, margin);
                    }
                });

                match sub_detector.proximity() {
                    Proximity::Intersecting => {
                        self.proximity = Proximity::Intersecting;
                        self.intersecting_key = *key;
                        return; // No need to search further.
                    }
                    Proximity::WithinMargin => self.proximity = Proximity::WithinMargin,
                    Proximity::Disjoint => {}
                }
            }
        }

        // Totally disjoints.
        self.intersecting_key = usize::max_value()
    }
}

impl<N: Real> ProximityDetector<N> for CompositeShapeShapeProximityDetector<N> {
    fn update(
        &mut self,
        dispatcher: &ProximityDispatcher<N>,
        m1: &Isometry<N>,
        g1: &Shape<N>,
        m2: &Isometry<N>,
        g2: &Shape<N>,
        margin: N,
    ) -> bool {
        if !self.flip {
            if let Some(cs) = g1.as_composite_shape() {
                self.do_update(dispatcher, m1, cs, m2, g2, margin, false);
                return true;
            }
        } else {
            if let Some(cs) = g2.as_composite_shape() {
                self.do_update(dispatcher, m2, cs, m1, g1, margin, true);
                return true;
            }
        }

        return false;
    }

    fn proximity(&self) -> Proximity {
        self.proximity
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;

#[derive(Debug)]
enum ParameterMode {
  Position,
  Immediate,
  Relative
}

#[derive(Debug)]
enum OperationType {
  Add,
  Multiply,
  Input,
  Output,
  JumpIfTrue,
  JumpIfFalse,
  LessThan,
  Equals,
  SetRelativeBase,
  Halt
}

#[derive(Debug)]
struct Instruction {
  operation: OperationType,
  inputs: Vec<(ParameterMode, i64)>
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("09.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_instruction(numbers: &[i64]) -> Instruction {
  let instruction_code = numbers[0];
  let op_code = instruction_code % 100;

  let (operation, inputs_count) = match op_code {
    1 => (OperationType::Add, 3),
    2 => (OperationType::Multiply, 3),
    3 => (OperationType::Input, 1),
    4 => (OperationType::Output, 1),
    5 => (OperationType::JumpIfTrue, 2),
    6 => (OperationType::JumpIfFalse, 2),
    7 => (OperationType::LessThan, 3),
    8 => (OperationType::Equals, 3),
    9 => (OperationType::SetRelativeBase, 1),
    99 => (OperationType::Halt, 0),
    _ => panic!()
  };

  let get_parameter_mode = |i| {
    match (instruction_code - op_code) / 10i64.pow(2 + i as u32) % 10 {
      0 => ParameterMode::Position,
      1 => ParameterMode::Immediate,
      2 => ParameterMode::Relative,
      _ => panic!()
    }
  };

  Instruction {
    operation,
    inputs: (0..inputs_count)
      .map(|i| (get_parameter_mode(i), numbers[i + 1]))
      .collect()
  }
}

fn run_program(program: &mut Vec<i64>, input: i64) -> Vec<i64> {
  let mut relative_base = 0;
  let mut result = vec![];
  let mut pointer = 0;

  fn extend_memory(program: &mut Vec<i64>, index: usize) {
    while index >= program.len() {
      program.push(0);
    }
  }

  fn get_instruction_input_index(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> usize {
    match instruction.inputs[index] {
      (ParameterMode::Relative, d) => {
        let j = (relative_base as i64 + d) as usize;
        extend_memory(program, j);
        j
      },
      (_, j) => {
        extend_memory(program, j as usize);
        j as usize
      }
    }
  }

  fn get_instruction_input(
    program: &mut Vec<i64>,
    instruction: &Instruction,
    relative_base: usize,
    index: usize
  ) -> i64 {
    match instruction.inputs[index] {
      (ParameterMode::Immediate, value) => value,
      _ => {
        let j = get_instruction_input_index(program, instruction, relative_base, index);
        program[j]
      }
    }
  }

  while pointer < program.len() {
    let init_pointer = pointer;
    let instruction = parse_instruction(&program[pointer..]);

    let (target_value, target_index) = {
      let mut get_input = |i| {
        get_instruction_input(program, &instruction, relative_base, i)
      };

      let (target_value, output_index) = match instruction.operation {
        OperationType::Add => (Some(get_input(0) + get_input(1)), Some(2)),
        OperationType::Multiply => (Some(get_input(0) * get_input(1)), Some(2)),
        OperationType::Input => (Some(input), Some(0)),
        OperationType::Output => (Some(get_input(0)), None),
        OperationType::LessThan => (Some((get_input(0) < get_input(1)) as i64), Some(2)),
        OperationType::Equals => (Some((get_input(0) == get_input(1)) as i64), Some(2)),
        OperationType::JumpIfTrue => {
          if get_input(0) != 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::JumpIfFalse => {
          if get_input(0) == 0 {
            pointer = get_input(1) as usize;
          }

          (None, None)
        },
        OperationType::SetRelativeBase => {
          relative_base = (relative_base as i64 + get_input(0)) as usize;
          (None, None)
        }
        OperationType::Halt => break
      };

      (
        target_value,
        output_index.map(|i| {
          get_instruction_input_index(program, &instruction, relative_base, i)
        })
      )
    };

    if let Some(target_value) = target_value {
      if let Some(target_index) = target_index {
        extend_memory(program, target_index);
        program[target_index] = target_value;
      } else {
        result.push(target_value);
      }
    }

    if pointer == init_pointer {
      pointer += instruction.inputs.len() + 1;
    }
  }

  result
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let output = run_program(&mut numbers.clone(), 1);
  println!("Part 1: {}", output.last().unwrap());

  let output = run_program(&mut numbers.clone(), 2);
  println!("Part 2: {}", output.last().unwrap());
}
<commit_msg>Use intcode module for day 9<commit_after>use std::fs::File;
use std::io::prelude::*;

mod intcode;
use intcode::*;

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("09.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn main() {
  let input = get_input().unwrap();
  let numbers = input.split(',')
    .filter_map(|x| x.trim().parse::<i64>().ok())
    .collect::<Vec<_>>();

  let mut state = ProgramState::new(numbers.clone());
  let (outputs, _) = run_program_with_inputs(&mut state, std::iter::once(1));
  println!("Part 1: {}", outputs.last().unwrap());

  let mut state = ProgramState::new(numbers.clone());
  let (outputs, _) = run_program_with_inputs(&mut state, std::iter::once(2));
  println!("Part 2: {}", outputs.last().unwrap());
}
<|endoftext|>


<commit_before>use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{fmt, mem, ptr, str};
use odds::char::{encode_utf8, EncodeUtf8Error};
use ::utf8::PascalStr;
use ::PASCAL_STRING_BUF_SIZE;

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length *of the number of bytes used*.
///
/// Note that because this string type is utf8 encoded, the first byte will not store the number of characters
/// in the string.
pub struct PascalString {
    /// The number of bytes used in the string.
    len: u8,
    /// The internal character buffer, encoded in utf8
    chars_buf: [u8; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Creates a new `PascalString` with the contents of `s`.
    ///
    /// # Returns
    ///
    /// If the contents of `s` can be stored in the buffer of the `PascalString`, then it returns
    /// `Ok`. Otherwise, returns `Err`.
    #[inline]
    pub fn from(s: &str) -> Result<Self, PascalStringCreateError> {
        unimplemented!()
    }

    /// Push a character onto the end of the string's internal buffer.
    ///
    /// # Panics
    ///
    /// Panics if there is no room to store the `char`.
    #[inline]
    pub fn push(&mut self, ch: char) {
        self.try_push(ch).unwrap()
    }

    /// Attempt to push a `char` onto the end of this string's internal buffer.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` if the operation succeeded, otherwise an error is returned.
    #[inline]
    pub fn try_push(&mut self, ch: char) -> Result<(), EncodeUtf8Error> {
        let num_bytes_extended = try!(encode_utf8(ch, &mut self.chars_buf[self.len as usize..]));
        self.len += num_bytes_extended as u8;
        Ok(())
    }

    /// Push a string onto the end of this string's internal buffer.
    ///
    /// # Panics
    ///
    /// Panics if there is no room to store the `str`.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap()
    }

    /// Attempt to push a string onto the end of this string's internal buffer.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` if the operation succeeded, otherwise an error is returned.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        if self.len() + s.len() > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringAppendError::NoRoom);
        }
        for ch in s.chars() {
            try!(self.try_push(ch))
        }
        Ok(())
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars_buf: [0u8; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars_buf, &mut clone.chars_buf, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(&self.chars_buf);
    }
}

impl Deref for PascalString {
    type Target = PascalStr;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.chars_buf[0..(self.len as usize)]) }
    }
}

impl DerefMut for PascalString {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.chars_buf[0..(self.len as usize)]) }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum PascalStringCreateError {
    InputTooLong
}

#[derive(Debug, Clone, Copy)]
pub enum PascalStringAppendError {
    NoRoom,
    EncodeError(EncodeUtf8Error)
}

impl fmt::Display for PascalStringAppendError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        let desc = self.description();
        match *self {
            PascalStringAppendError::NoRoom => fmtr.pad(desc),
            PascalStringAppendError::EncodeError(ref e) => write!(fmtr, "{}: {:?}", desc, e)
        }
    }
}

impl Error for PascalStringAppendError {
    fn description(&self) -> &str {
        match *self {
            PascalStringAppendError::NoRoom => "there is no room for the string to be appended",
            PascalStringAppendError::EncodeError(_) => "there was a problem encoding the character as utf8: {:?}"
        }
    }
}

impl From<EncodeUtf8Error> for PascalStringAppendError {
    fn from(e: EncodeUtf8Error) -> Self {
        PascalStringAppendError::EncodeError(e)
    }
}
<commit_msg>impl PascalString::from(&str)<commit_after>use std::borrow::{Borrow, BorrowMut};
use std::error::Error;
use std::hash::{Hash, Hasher};
use std::ops::{Deref, DerefMut};
use std::{fmt, mem, ptr, str};
use odds::char::{encode_utf8, EncodeUtf8Error};
use ::utf8::PascalStr;
use ::PASCAL_STRING_BUF_SIZE;

/// An owned `PascalString`. This string type stores its data the stack. It is always 256 bytes long, with
/// the first byte storing the length *of the number of bytes used*.
///
/// Note that because this string type is utf8 encoded, the first byte will not store the number of characters
/// in the string.
pub struct PascalString {
    /// The number of bytes used in the string.
    len: u8,
    /// The internal character buffer, encoded in utf8
    chars_buf: [u8; PASCAL_STRING_BUF_SIZE]
}

impl PascalString {
    /// Creates a new, empty `PascalString`.
    #[inline]
    pub fn new() -> Self {
        Default::default()
    }

    /// Creates a new `PascalString` with the contents of `s`.
    ///
    /// # Returns
    ///
    /// If the contents of `s` can be stored in the buffer of the `PascalString`, then it returns
    /// `Ok`. Otherwise, returns `Err`.
    #[inline]
    pub fn from(s: &str) -> Result<Self, PascalStringCreateError> {
        if s.len() > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringCreateError::InputTooLong);
        }
        let mut pstring = PascalString::new();
        for ch in s.chars() {
            pstring.push(ch)
        }
        Ok(pstring)
    }

    /// Push a character onto the end of the string's internal buffer.
    ///
    /// # Panics
    ///
    /// Panics if there is no room to store the `char`.
    #[inline]
    pub fn push(&mut self, ch: char) {
        self.try_push(ch).unwrap()
    }

    /// Attempt to push a `char` onto the end of this string's internal buffer.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` if the operation succeeded, otherwise an error is returned.
    #[inline]
    pub fn try_push(&mut self, ch: char) -> Result<(), EncodeUtf8Error> {
        let num_bytes_extended = try!(encode_utf8(ch, &mut self.chars_buf[self.len as usize..]));
        self.len += num_bytes_extended as u8;
        Ok(())
    }

    /// Push a string onto the end of this string's internal buffer.
    ///
    /// # Panics
    ///
    /// Panics if there is no room to store the `str`.
    #[inline]
    pub fn push_str<S: AsRef<str>>(&mut self, s: S) {
        self.try_push_str(s).unwrap()
    }

    /// Attempt to push a string onto the end of this string's internal buffer.
    ///
    /// # Returns
    ///
    /// Returns `Ok(())` if the operation succeeded, otherwise an error is returned.
    #[inline]
    pub fn try_push_str<S: AsRef<str>>(&mut self, s: S) -> Result<(), PascalStringAppendError> {
        self._try_push_str(s.as_ref())
    }

    fn _try_push_str(&mut self, s: &str) -> Result<(), PascalStringAppendError> {
        if self.len() + s.len() > PASCAL_STRING_BUF_SIZE {
            return Err(PascalStringAppendError::NoRoom);
        }
        for ch in s.chars() {
            try!(self.try_push(ch))
        }
        Ok(())
    }
}

impl Default for PascalString {
    #[inline]
    fn default() -> Self {
        PascalString {
            len: 0,
            chars_buf: [0u8; PASCAL_STRING_BUF_SIZE]
        }
    }
}

impl Clone for PascalString {
    fn clone(&self) -> Self {
        let mut clone = PascalString::default();
        clone.len = self.len;
        unsafe {
            ptr::copy_nonoverlapping(&self.chars_buf, &mut clone.chars_buf, PASCAL_STRING_BUF_SIZE);
        }
        clone
    }
}

impl Hash for PascalString {
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        state.write_u8(self.len);
        state.write(&self.chars_buf);
    }
}

impl Deref for PascalString {
    type Target = PascalStr;

    #[inline]
    fn deref(&self) -> &Self::Target {
        unsafe { mem::transmute(&self.chars_buf[0..(self.len as usize)]) }
    }
}

impl DerefMut for PascalString {
    #[inline]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(&mut self.chars_buf[0..(self.len as usize)]) }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum PascalStringCreateError {
    InputTooLong
}

#[derive(Debug, Clone, Copy)]
pub enum PascalStringAppendError {
    NoRoom,
    EncodeError(EncodeUtf8Error)
}

impl fmt::Display for PascalStringAppendError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        let desc = self.description();
        match *self {
            PascalStringAppendError::NoRoom => fmtr.pad(desc),
            PascalStringAppendError::EncodeError(ref e) => write!(fmtr, "{}: {:?}", desc, e)
        }
    }
}

impl Error for PascalStringAppendError {
    fn description(&self) -> &str {
        match *self {
            PascalStringAppendError::NoRoom => "there is no room for the string to be appended",
            PascalStringAppendError::EncodeError(_) => "there was a problem encoding the character as utf8: {:?}"
        }
    }
}

impl From<EncodeUtf8Error> for PascalStringAppendError {
    fn from(e: EncodeUtf8Error) -> Self {
        PascalStringAppendError::EncodeError(e)
    }
}
<|endoftext|>