<commit_before>use std::cast;
use std::c_str::CString;
use std::libc::*;
use std::ptr;
use std::num::Zero;
use std::i32;
use std::vec;

use core_drawing::*;
use color::*;
use bitmap::*;
use bitmap::private::*;

use ffi::*;

pub use display::display_flag::*;

flag_type!(
	mod display_flag
	{
		DisplayFlags
		{
			WINDOWED                  = ALLEGRO_WINDOWED,
			FULLSCREEN                = ALLEGRO_FULLSCREEN,
			OPENGL                    = ALLEGRO_OPENGL,
			DIRECT3D                  = ALLEGRO_DIRECT3D_INTERNAL,
			RESIZABLE                 = ALLEGRO_RESIZABLE,
			FRAMELESS                 = ALLEGRO_FRAMELESS,
			GENERATE_EXPOSE_EVENTS    = ALLEGRO_GENERATE_EXPOSE_EVENTS,
			OPENGL_3_0                = ALLEGRO_OPENGL_3_0,
			OPENGL_FORWARD_COMPATIBLE = ALLEGRO_OPENGL_FORWARD_COMPATIBLE,
			FULLSCREEN_WINDOW         = ALLEGRO_FULLSCREEN_WINDOW,
			MINIMIZED                 = ALLEGRO_MINIMIZED
		}
	}
)

enum DisplayOption
{
	RedSize = ALLEGRO_RED_SIZE,
	GreenSize = ALLEGRO_GREEN_SIZE,
	BlueSize = ALLEGRO_BLUE_SIZE,
	AlphaSize = ALLEGRO_ALPHA_SIZE,
	RedShift = ALLEGRO_RED_SHIFT,
	GreenShift = ALLEGRO_GREEN_SHIFT,
	BlueShift = ALLEGRO_BLUE_SHIFT,
	AlphaShift = ALLEGRO_ALPHA_SHIFT,
	AccRedSize = ALLEGRO_ACC_RED_SIZE,
	AccGreenSize = ALLEGRO_ACC_GREEN_SIZE,
	AccBlueSize = ALLEGRO_ACC_BLUE_SIZE,
	AccAlphaSize = ALLEGRO_ACC_ALPHA_SIZE,
	Stereo = ALLEGRO_STEREO,
	AuxBuffers = ALLEGRO_AUX_BUFFERS,
	ColorSize = ALLEGRO_COLOR_SIZE,
	DepthSize = ALLEGRO_DEPTH_SIZE,
	StencilSize = ALLEGRO_STENCIL_SIZE,
	SampleBuffers = ALLEGRO_SAMPLE_BUFFERS,
	Samples = ALLEGRO_SAMPLES,
	RenderMethod = ALLEGRO_RENDER_METHOD,
	FloatColor = ALLEGRO_FLOAT_COLOR,
	FloatDepth = ALLEGRO_FLOAT_DEPTH,
	SingleBuffer = ALLEGRO_SINGLE_BUFFER,
	SwapMethod = ALLEGRO_SWAP_METHOD,
	CompatibleDisplay = ALLEGRO_COMPATIBLE_DISPLAY,
	UpdateDisplayRegion = ALLEGRO_UPDATE_DISPLAY_REGION,
	Vsync = ALLEGRO_VSYNC,
	MaxBitmapSize = ALLEGRO_MAX_BITMAP_SIZE,
	SupportNpotBitmap = ALLEGRO_SUPPORT_NPOT_BITMAP,
	CanDrawIntoBitmap = ALLEGRO_CAN_DRAW_INTO_BITMAP,
	SupportSeparateAlpha = ALLEGRO_SUPPORT_SEPARATE_ALPHA,
}

enum DisplayOptionImportance
{
	DontCare = ALLEGRO_DONTCARE,
	Require = ALLEGRO_REQUIRE,
	Suggest = ALLEGRO_SUGGEST,
}

enum DisplayOrientation
{
	DisplayOrientation0Degrees = ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES,
	DisplayOrientation90Degrees = ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES,
	DisplayOrientation180Degrees = ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES,
	DisplayOrientation270Degrees = ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES,
	DisplayOrientationFaceUp = ALLEGRO_DISPLAY_ORIENTATION_FACE_UP,
	DisplayOrientationFaceDown = ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN,
}

struct DisplayOptions<'self>
{
	flags: DisplayFlags,
	refresh_rate: Option<int>,
	adapter: Option<int>,
	window_position: Option<[int, ..2]>,
	options: Option<&'self [(DisplayOption, i32, DisplayOptionImportance)]>
}

impl<'self> DisplayOptions<'self>
{
	fn new() -> DisplayOptions
	{
		DisplayOptions{ flags: Zero::zero(), refresh_rate: None, adapter: None, window_position: None, options: None }
	}
}

struct Display
{
	priv allegro_display: *mut ALLEGRO_DISPLAY,
	priv backbuffer: Bitmap
}

impl Display
{
	fn select_this_display(&self)
	{
		unsafe
		{
			if self.allegro_display != al_get_current_display()
			{
				al_set_target_bitmap(al_get_backbuffer(self.allegro_display))
			}
		}
	}

	pub fn new(w: int, h: int) -> Option<Display>
	{
		unsafe
		{
			let d = al_create_display(w as c_int, h as c_int);
			if ptr::is_null(d)
			{
				None
			}
			else
			{
				Some(Display{ allegro_display: d, backbuffer: bitmap_ref(al_get_backbuffer(d)) })
			}
		}
	}

	pub fn new_with_options(w: int, h: int, opt: &DisplayOptions) -> Option<Display>
	{
		unsafe
		{
			al_set_new_display_flags(opt.flags.get() as c_int);

			match opt.refresh_rate
			{
				Some(r) => al_set_new_display_refresh_rate(r as c_int),
				None => al_set_new_display_refresh_rate(0)
			}

			match opt.adapter
			{
				Some(a) => al_set_new_display_adapter(a as c_int),
				None => al_set_new_display_adapter(ALLEGRO_DEFAULT_DISPLAY_ADAPTER),
			}

			match opt.window_position
			{
				Some([x, y]) =>	al_set_new_window_position(x as c_int, y as c_int),
				None =>	al_set_new_window_position(i32::max_value, i32::max_value)
			}

			al_reset_new_display_options();

			match opt.options
			{
				Some(options) =>
				{
					for &(option, value, importance) in options.iter()
					{
						al_set_new_display_option(option as c_int, value as c_int, importance as c_int);
					}
				},
				None => ()
			}
		}

		Display::new(w, h)
	}

	pub fn get_width(&self) -> float
	{
		unsafe
		{
			al_get_display_width(self.allegro_display) as float
		}
	}

	pub fn get_height(&self) -> float
	{
		unsafe
		{
			al_get_display_height(self.allegro_display) as float
		}
	}

	pub fn get_format(&self) -> PixelFormat
	{
		unsafe
		{
			cast::transmute(al_get_display_format(self.allegro_display) as int)
		}
	}

	pub fn get_refresh_rate(&self) -> int
	{
		unsafe
		{
			al_get_display_refresh_rate(self.allegro_display) as int
		}
	}

	pub fn get_flags(&self) -> DisplayFlags
	{
		unsafe
		{
			cast::transmute(al_get_display_flags(self.allegro_display))
		}
	}

	pub fn set_flag(&self, flag: DisplayFlags, onoff: bool) -> bool
	{
		unsafe
		{
			al_set_display_flag(self.allegro_display, flag.get(), onoff as u8) != 0
		}
	}

	pub fn get_backbuffer<'l>(&'l self) -> &'l Bitmap
	{
		&self.backbuffer
	}

	pub fn acknowledge_resize(&self) -> bool
	{
		unsafe
		{
			al_acknowledge_resize(self.allegro_display) != 0
		}
	}

	pub fn resize(&self, w: int, h: int) -> bool
	{
		unsafe
		{
			al_resize_display(self.allegro_display, w as c_int, h as c_int) != 0
		}
	}

	pub fn flip(&self)
	{
		self.select_this_display();
		unsafe
		{
			al_flip_display();
		}
	}

	pub fn update_region(&self, x: int, y: int, width: int, height: int)
	{
		self.select_this_display();
		unsafe
		{
			al_update_display_region(x as c_int, y as c_int, width as c_int, height as c_int);
		}
	}

	pub fn is_compatible_bitmap<T: BitmapLike>(&self, bitmap: &T) -> bool
	{
		self.select_this_display();
		unsafe
		{
			al_is_compatible_bitmap(bitmap.get_bitmap()) != 0
		}
	}

	pub fn wait_for_vsync(&self) -> bool
	{
		self.select_this_display();
		unsafe
		{
			al_wait_for_vsync() != 0
		}
	}

	pub fn set_icon<T: BitmapLike>(&self, icon: &T)
	{
		unsafe
		{
			al_set_display_icon(self.allegro_display, icon.get_bitmap());
		}
	}

	pub fn set_icons<T: BitmapLike, U: Iterator<T>>(&self, mut icons: U)
	{
		let mut c_icons: ~[*mut ALLEGRO_BITMAP] = ~[];
		for icon in icons
		{
			c_icons.push(icon.get_bitmap());
		}
		unsafe
		{
			al_set_display_icons(self.allegro_display, c_icons.len() as c_int, vec::raw::to_mut_ptr(c_icons));
		}
	}

	pub fn set_window_position(&self, x: int, y: int)
	{
		unsafe
		{
			al_set_window_position(self.allegro_display, x as c_int, y as c_int);
		}
	}

	pub fn get_window_position(&self) -> [int, ..2]
	{
		unsafe
		{
			let mut x = 0 as c_int;
			let mut y = 0 as c_int;
			al_get_window_position(self.allegro_display, &mut x, &mut y);
			[x as int, y as int]
		}
	}

	pub fn set_window_title(&self, title: &CString)
	{
		unsafe
		{
			do title.with_ref |c_str|
			{
				al_set_window_title(self.allegro_display, c_str);
			}
		}
	}
}

impl Drop for Display
{
	fn drop(&self)
	{
		unsafe
		{
			al_destroy_display(self.allegro_display);
		}
	}
}

impl DrawTarget for Display
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		unsafe
		{
			al_get_backbuffer(self.allegro_display)
		}
	}
}

impl CoreDrawing for Display;
<commit_msg>Bind most of the remaining display functions<commit_after>use std::cast;
use std::c_str::CString;
use std::libc::*;
use std::ptr;
use std::num::Zero;
use std::i32;
use std::vec;

use core_drawing::*;
use color::*;
use bitmap::*;
use bitmap::private::*;

use ffi::*;

pub use display::display_flag::*;
pub use rust_util::c_bool;

flag_type!(
	mod display_flag
	{
		DisplayFlags
		{
			WINDOWED                  = ALLEGRO_WINDOWED,
			FULLSCREEN                = ALLEGRO_FULLSCREEN,
			OPENGL                    = ALLEGRO_OPENGL,
			DIRECT3D                  = ALLEGRO_DIRECT3D_INTERNAL,
			RESIZABLE                 = ALLEGRO_RESIZABLE,
			FRAMELESS                 = ALLEGRO_FRAMELESS,
			GENERATE_EXPOSE_EVENTS    = ALLEGRO_GENERATE_EXPOSE_EVENTS,
			OPENGL_3_0                = ALLEGRO_OPENGL_3_0,
			OPENGL_FORWARD_COMPATIBLE = ALLEGRO_OPENGL_FORWARD_COMPATIBLE,
			FULLSCREEN_WINDOW         = ALLEGRO_FULLSCREEN_WINDOW,
			MINIMIZED                 = ALLEGRO_MINIMIZED
		}
	}
)

enum DisplayOption
{
	RedSize = ALLEGRO_RED_SIZE,
	GreenSize = ALLEGRO_GREEN_SIZE,
	BlueSize = ALLEGRO_BLUE_SIZE,
	AlphaSize = ALLEGRO_ALPHA_SIZE,
	RedShift = ALLEGRO_RED_SHIFT,
	GreenShift = ALLEGRO_GREEN_SHIFT,
	BlueShift = ALLEGRO_BLUE_SHIFT,
	AlphaShift = ALLEGRO_ALPHA_SHIFT,
	AccRedSize = ALLEGRO_ACC_RED_SIZE,
	AccGreenSize = ALLEGRO_ACC_GREEN_SIZE,
	AccBlueSize = ALLEGRO_ACC_BLUE_SIZE,
	AccAlphaSize = ALLEGRO_ACC_ALPHA_SIZE,
	Stereo = ALLEGRO_STEREO,
	AuxBuffers = ALLEGRO_AUX_BUFFERS,
	ColorSize = ALLEGRO_COLOR_SIZE,
	DepthSize = ALLEGRO_DEPTH_SIZE,
	StencilSize = ALLEGRO_STENCIL_SIZE,
	SampleBuffers = ALLEGRO_SAMPLE_BUFFERS,
	Samples = ALLEGRO_SAMPLES,
	RenderMethod = ALLEGRO_RENDER_METHOD,
	FloatColor = ALLEGRO_FLOAT_COLOR,
	FloatDepth = ALLEGRO_FLOAT_DEPTH,
	SingleBuffer = ALLEGRO_SINGLE_BUFFER,
	SwapMethod = ALLEGRO_SWAP_METHOD,
	CompatibleDisplay = ALLEGRO_COMPATIBLE_DISPLAY,
	UpdateDisplayRegion = ALLEGRO_UPDATE_DISPLAY_REGION,
	Vsync = ALLEGRO_VSYNC,
	MaxBitmapSize = ALLEGRO_MAX_BITMAP_SIZE,
	SupportNpotBitmap = ALLEGRO_SUPPORT_NPOT_BITMAP,
	CanDrawIntoBitmap = ALLEGRO_CAN_DRAW_INTO_BITMAP,
	SupportSeparateAlpha = ALLEGRO_SUPPORT_SEPARATE_ALPHA,
}

enum DisplayOptionImportance
{
	DontCare = ALLEGRO_DONTCARE,
	Require = ALLEGRO_REQUIRE,
	Suggest = ALLEGRO_SUGGEST,
}

enum DisplayOrientation
{
	DisplayOrientation0Degrees = ALLEGRO_DISPLAY_ORIENTATION_0_DEGREES,
	DisplayOrientation90Degrees = ALLEGRO_DISPLAY_ORIENTATION_90_DEGREES,
	DisplayOrientation180Degrees = ALLEGRO_DISPLAY_ORIENTATION_180_DEGREES,
	DisplayOrientation270Degrees = ALLEGRO_DISPLAY_ORIENTATION_270_DEGREES,
	DisplayOrientationFaceUp = ALLEGRO_DISPLAY_ORIENTATION_FACE_UP,
	DisplayOrientationFaceDown = ALLEGRO_DISPLAY_ORIENTATION_FACE_DOWN,
}

struct DisplayOptions<'self>
{
	flags: DisplayFlags,
	refresh_rate: Option<int>,
	adapter: Option<int>,
	window_position: Option<[int, ..2]>,
	options: Option<&'self [(DisplayOption, i32, DisplayOptionImportance)]>
}

impl<'self> DisplayOptions<'self>
{
	fn new() -> DisplayOptions
	{
		DisplayOptions{ flags: Zero::zero(), refresh_rate: None, adapter: None, window_position: None, options: None }
	}
}

struct Display
{
	priv allegro_display: *mut ALLEGRO_DISPLAY,
	priv backbuffer: Bitmap
}

impl Display
{
	fn select_this_display(&self)
	{
		unsafe
		{
			if self.allegro_display != al_get_current_display()
			{
				al_set_target_bitmap(al_get_backbuffer(self.allegro_display))
			}
		}
	}

	pub fn new(w: int, h: int) -> Option<Display>
	{
		unsafe
		{
			let d = al_create_display(w as c_int, h as c_int);
			if ptr::is_null(d)
			{
				None
			}
			else
			{
				Some(Display{ allegro_display: d, backbuffer: bitmap_ref(al_get_backbuffer(d)) })
			}
		}
	}

	pub fn new_with_options(w: int, h: int, opt: &DisplayOptions) -> Option<Display>
	{
		unsafe
		{
			al_set_new_display_flags(opt.flags.get() as c_int);

			match opt.refresh_rate
			{
				Some(r) => al_set_new_display_refresh_rate(r as c_int),
				None => al_set_new_display_refresh_rate(0)
			}

			match opt.adapter
			{
				Some(a) => al_set_new_display_adapter(a as c_int),
				None => al_set_new_display_adapter(ALLEGRO_DEFAULT_DISPLAY_ADAPTER),
			}

			match opt.window_position
			{
				Some([x, y]) =>	al_set_new_window_position(x as c_int, y as c_int),
				None =>	al_set_new_window_position(i32::max_value, i32::max_value)
			}

			al_reset_new_display_options();

			match opt.options
			{
				Some(options) =>
				{
					for &(option, value, importance) in options.iter()
					{
						al_set_new_display_option(option as c_int, value as c_int, importance as c_int);
					}
				},
				None => ()
			}
		}

		Display::new(w, h)
	}

	pub fn get_width(&self) -> float
	{
		unsafe
		{
			al_get_display_width(self.allegro_display) as float
		}
	}

	pub fn get_height(&self) -> float
	{
		unsafe
		{
			al_get_display_height(self.allegro_display) as float
		}
	}

	pub fn get_format(&self) -> PixelFormat
	{
		unsafe
		{
			cast::transmute(al_get_display_format(self.allegro_display) as int)
		}
	}

	pub fn get_refresh_rate(&self) -> int
	{
		unsafe
		{
			al_get_display_refresh_rate(self.allegro_display) as int
		}
	}

	pub fn get_flags(&self) -> DisplayFlags
	{
		unsafe
		{
			cast::transmute(al_get_display_flags(self.allegro_display))
		}
	}

	pub fn set_flag(&self, flag: DisplayFlags, onoff: bool) -> bool
	{
		unsafe
		{
			al_set_display_flag(self.allegro_display, flag.get(), onoff as u8) != 0
		}
	}

	pub fn get_backbuffer<'l>(&'l self) -> &'l Bitmap
	{
		&self.backbuffer
	}

	pub fn acknowledge_resize(&self) -> bool
	{
		unsafe
		{
			al_acknowledge_resize(self.allegro_display) != 0
		}
	}

	pub fn resize(&self, w: int, h: int) -> bool
	{
		unsafe
		{
			al_resize_display(self.allegro_display, w as c_int, h as c_int) != 0
		}
	}

	pub fn flip(&self)
	{
		self.select_this_display();
		unsafe
		{
			al_flip_display();
		}
	}

	pub fn update_region(&self, x: int, y: int, width: int, height: int)
	{
		self.select_this_display();
		unsafe
		{
			al_update_display_region(x as c_int, y as c_int, width as c_int, height as c_int);
		}
	}

	pub fn is_compatible_bitmap<T: BitmapLike>(&self, bitmap: &T) -> bool
	{
		self.select_this_display();
		unsafe
		{
			al_is_compatible_bitmap(bitmap.get_bitmap()) != 0
		}
	}

	pub fn wait_for_vsync(&self) -> bool
	{
		self.select_this_display();
		unsafe
		{
			al_wait_for_vsync() != 0
		}
	}

	pub fn set_icon<T: BitmapLike>(&self, icon: &T)
	{
		unsafe
		{
			al_set_display_icon(self.allegro_display, icon.get_bitmap());
		}
	}

	pub fn set_icons<T: BitmapLike, U: Iterator<T>>(&self, mut icons: U)
	{
		let mut c_icons: ~[*mut ALLEGRO_BITMAP] = ~[];
		for icon in icons
		{
			c_icons.push(icon.get_bitmap());
		}
		unsafe
		{
			al_set_display_icons(self.allegro_display, c_icons.len() as c_int, vec::raw::to_mut_ptr(c_icons));
		}
	}

	pub fn set_window_position(&self, x: int, y: int)
	{
		unsafe
		{
			al_set_window_position(self.allegro_display, x as c_int, y as c_int);
		}
	}

	pub fn get_window_position(&self) -> [int, ..2]
	{
		unsafe
		{
			let mut x = 0 as c_int;
			let mut y = 0 as c_int;
			al_get_window_position(self.allegro_display, &mut x, &mut y);
			[x as int, y as int]
		}
	}

	pub fn set_window_title(&self, title: &CString)
	{
		unsafe
		{
			do title.with_ref |c_str|
			{
				al_set_window_title(self.allegro_display, c_str);
			}
		}
	}

	pub fn get_option(&self, option: DisplayOption) -> i32
	{
		unsafe
		{
			al_get_display_option(self.allegro_display, option as c_int) as i32
		}
	}

	pub fn hold_bitmap_drawing(&self, hold: bool)
	{
		self.select_this_display();
		unsafe
		{
			al_hold_bitmap_drawing(hold as c_bool);
		}
	}

	pub fn is_bitmap_drawing_held(&self) -> bool
	{
		self.select_this_display();
		unsafe
		{
			al_is_bitmap_drawing_held() != 0
		}
	}
}

impl Drop for Display
{
	fn drop(&self)
	{
		unsafe
		{
			al_destroy_display(self.allegro_display);
		}
	}
}

impl DrawTarget for Display
{
	fn get_target_bitmap(&self) -> *mut ALLEGRO_BITMAP
	{
		unsafe
		{
			al_get_backbuffer(self.allegro_display)
		}
	}
}

impl CoreDrawing for Display;
<|endoftext|>


<commit_before>use futures::{Async, AsyncSink, Future, Poll};
use futures::stream::Stream;
use futures::sink::Sink;
use state_machine_future::RentToOwn;
use tokio_core::reactor::Handle;
use tokio_retry::{self, Retry};
use tokio_retry::strategy::{FibonacciBackoff, jitter};
use std::io;
use std::error;
use std::time::Duration;
use std::fmt;

pub type ConnectionError = io::Error;

pub struct Message<Item> {
    pub session_id: u32,
    pub content: Item
}

impl <Item> Message<Item> {
    pub fn new(session_id: u32, item: Item) -> Message<Item> {
        Message {
            session_id: session_id,
            content: item,
        }
    }
}

impl <Item> Clone for Message<Item> where Item: Clone {
    fn clone(&self) -> Message<Item> {
        Message::new(self.session_id, self.content.clone())
    }
}

impl <Item> fmt::Debug for Message<Item> where Item: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Message<session_id={}, content={:?}>", self.session_id, self.content)
    }
}

pub trait NewTransport {
    type Future: Future<Item=Self::Transport,Error=Self::Error>;
    type Transport;
    type Error: error::Error + Sync + Send;

    fn new_transport(&self) -> Self::Future;
}

#[derive(StateMachineFuture)]
pub enum Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    #[state_machine_future(start, transitions(Connecting, Finished, Error))]
    NotConnected {
        handle: Handle,
        stream: S,
        sink: K,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(NotConnected, Connected, Finished, Error))]
    Connecting {
        handle: Handle,
        stream: S,
        sink: K,
        tcp_future: Box<Future<Item=T,Error=io::Error>>,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(Connected, NotConnected, Finished, Error))]
    Connected {
        handle: Handle,
        stream: S,
        sink: K,
        tcp: T,
        outbound: Option<Item>,
        outbound_inflight: u32,
        inbound: Option<Message<Item>>,
        inbound_inflight: u32,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(ready)]
    Finished(()),

    #[state_machine_future(error)]
    Error(ConnectionError),
}

impl <Item, S, K, T, N> Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    pub fn new(handle: Handle, stream: S, sink: K, new_transport: N) -> ConnectionFuture<Item, S, K, T, N> {
        debug!("constructing new connection future");
        Connection::start(handle, stream, sink, 0, 0, new_transport)
    }
}

impl <Item, S, K, T, N> PollConnection<Item, S, K, T, N> for Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    fn poll_not_connected<'a>(not_connected: &'a mut RentToOwn<'a, NotConnected<Item, S, K, T, N>>) -> Poll<AfterNotConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("not connected");

        let retry_strategy = FibonacciBackoff ::from_millis(1)
            .max_delay(Duration::from_millis(2000))
            .map(jitter);

        let handle = not_connected.handle.clone();
        let new_transport = not_connected.new_transport.clone();

        let tcp_future = Box::new(Retry::spawn(handle, retry_strategy, move || {
            new_transport.new_transport()
        }).map_err(|e| {
            match e {
                tokio_retry::Error::OperationError(e) => io::Error::new(io::ErrorKind::Other, e),
                tokio_retry::Error::TimerError(e) => e,
            }
        })) as (Box<Future<Item=T,Error=io::Error>>);

        let not_connected = not_connected.take();
        Ok(Async::Ready(Connecting {
            handle: not_connected.handle,
            stream: not_connected.stream,
            sink: not_connected.sink,
            tcp_future: tcp_future,
            error_count: not_connected.error_count,
            session_id: not_connected.session_id,
            new_transport: not_connected.new_transport,
        }.into()))
    }

    fn poll_connecting<'a>(connecting: &'a mut RentToOwn<'a, Connecting<Item, S, K, T, N>>) -> Poll<AfterConnecting<Item, S, K, T, N>, ConnectionError> {
        trace!("connecting");

        let tcp = try_ready!(connecting.tcp_future.poll());

        let connecting = connecting.take();
        Ok(Async::Ready(Connected {
            handle: connecting.handle,
            stream: connecting.stream,
            sink: connecting.sink,
            tcp: tcp,
            inbound: None,
            inbound_inflight: 0,
            outbound: None,
            outbound_inflight: 0,
            error_count: connecting.error_count,
            session_id: connecting.session_id,
            new_transport: connecting.new_transport,
        }.into()))
    }

    fn poll_connected<'a>(connected: &'a mut RentToOwn<'a, Connected<Item, S, K, T, N>>) -> Poll<AfterConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("connected");

        // we make progress if any poll returns Ready
        // if we make progress then we return a state or state change
        // otherwise return NotReady
        let mut progress = false;

        let mut received = connected.inbound.take();
        if received.is_none() && connected.inbound_inflight == 0 {
            received = match connected.tcp.poll() {
                Ok(Async::Ready(Some(msg))) => {
                    trace!("transport received msg");
                    progress = true;
                    Some(Message::new(connected.session_id, msg))
                },
                Ok(Async::Ready(None)) => {
                    trace!("transport returned end of stream");

                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                },
                Ok(Async::NotReady) => {
                    trace!("transport not ready to read");
                    None
                },
                Err(e) => {
                    trace!("transport read error: {:?}", e);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            };
        }

        let mut sending = connected.outbound.take();
        if sending.is_none() {
            sending = match try!(connected.stream.poll()) {
                Async::Ready(Some(msg)) => {
                    progress = true;

                    Some(msg)
                },
                Async::Ready(None) => {
                    trace!("stream finished");
                    return Ok(Async::Ready(Finished(()).into()));
                },
                Async::NotReady => {
                    trace!("stream not ready to read");
                    None
                }
            };
        }

        if let Some(sending) = sending {
            match connected.tcp.start_send(sending) {
                Ok(AsyncSink::Ready) => {
                    trace!("transport wrote message");
                    progress = true;
                    connected.outbound_inflight += 1;
                },
                Ok(AsyncSink::NotReady(sending)) => {
                    trace!("tcpstream not ready to write");
                    connected.outbound = Some(sending);
                },
                Err(err) => {
                    trace!("transport write error: {:?}", err);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            }
        }

        if let Some(msg) = received {
            match try!(connected.sink.start_send(msg)) {
                AsyncSink::Ready => {
                    trace!("sink started send");
                    progress = true;
                    connected.inbound_inflight += 1;
                },
                AsyncSink::NotReady(msg) => {
                    trace!("sink not ready");
                    connected.inbound = Some(msg);
                },
            }
        }

        if connected.inbound_inflight != 0 {
            match try!(connected.sink.poll_complete()) {
                Async::Ready(()) => {
                    trace!("sink polled complete");
                    progress = true;
                    connected.inbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("sink polled not ready");
                    // do nothing
                }
            }
        }

        if connected.outbound_inflight != 0 {
            match try!(connected.tcp.poll_complete()) {
                Async::Ready(()) => {
                    trace!("transport poll complete");
                    progress = true;
                    connected.outbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("transport sink polled not ready");
                    // do nothing
                }
            }
        }

        if progress {
            trace!("made progress");

            let connected = connected.take();

            return Ok(Async::Ready(Connected {
                handle: connected.handle,
                stream: connected.stream,
                sink: connected.sink,
                tcp: connected.tcp,
                inbound: connected.inbound,
                inbound_inflight: connected.inbound_inflight,
                outbound: connected.outbound,
                outbound_inflight: connected.outbound_inflight,
                error_count: connected.error_count,
                session_id: connected.session_id,
                new_transport: connected.new_transport,
            }.into()));
        } else {
            trace!("did not make progress");

            return Ok(Async::NotReady);
        }
    }
}
<commit_msg>add control messages from link to signal state change to local sink<commit_after>use futures::{Async, AsyncSink, Future, Poll};
use futures::stream::Stream;
use futures::sink::Sink;
use state_machine_future::RentToOwn;
use tokio_core::reactor::Handle;
use tokio_retry::{self, Retry};
use tokio_retry::strategy::{FibonacciBackoff, jitter};
use std::io;
use std::error;
use std::time::Duration;
use std::fmt;

pub type ConnectionError = io::Error;
pub type SessionId = u32;

#[derive(Debug, Clone, PartialEq)]
pub enum Event {
    Connected {
        session_id: SessionId,
    }
}

pub enum Message<Item> {
    Packet {
        session_id: SessionId,
        content: Item,
    },
    Control {
        event: Event,
    }
}

impl <Item> Clone for Message<Item> where Item: Clone {
    fn clone(&self) -> Message<Item> {
        match self {
            &Message::Packet { session_id, ref content } => {
                Message::Packet {
                    session_id: session_id,
                    content: content.clone()
                }
            },
            &Message::Control { ref event } => {
                Message::Control {
                    event: event.clone()
                }
            }
        }
    }
}

impl <Item> fmt::Debug for Message<Item> where Item: fmt::Debug {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Message::Packet { session_id, ref content } => {
                write!(f, "Message::Packet<session_id={:?}, content={:?}>", session_id, content)
            },
            &Message::Control { ref event } => {
                write!(f, "Message::Control<event={:?}>", event)
            }
        }
    }
}

pub trait NewTransport {
    type Future: Future<Item=Self::Transport,Error=Self::Error>;
    type Transport;
    type Error: error::Error + Sync + Send;

    fn new_transport(&self) -> Self::Future;
}

#[derive(StateMachineFuture)]
pub enum Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    #[state_machine_future(start, transitions(Connecting, Finished, Error))]
    NotConnected {
        handle: Handle,
        stream: S,
        sink: K,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(NotConnected, Connected, Finished, Error))]
    Connecting {
        handle: Handle,
        stream: S,
        sink: K,
        tcp_future: Box<Future<Item=T,Error=io::Error>>,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(transitions(Connected, NotConnected, Finished, Error))]
    Connected {
        handle: Handle,
        stream: S,
        sink: K,
        tcp: T,
        outbound: Option<Item>,
        outbound_inflight: u32,
        inbound: Option<Message<Item>>,
        inbound_inflight: u32,
        error_count: u32,
        session_id: u32,
        new_transport: N,
    },

    #[state_machine_future(ready)]
    Finished(()),

    #[state_machine_future(error)]
    Error(ConnectionError),
}

impl <Item, S, K, T, N> Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    pub fn new(handle: Handle, stream: S, sink: K, new_transport: N) -> ConnectionFuture<Item, S, K, T, N> {
        debug!("constructing new connection future");
        Connection::start(handle, stream, sink, 0, 0, new_transport)
    }
}

impl <Item, S, K, T, N> PollConnection<Item, S, K, T, N> for Connection<Item, S, K, T, N> where S: Stream<Item=Item,Error=io::Error>, K: Sink<SinkItem=Message<Item>,SinkError=io::Error>, T: Stream<Item=Item,Error=io::Error>+Sink<SinkItem=Item,SinkError=io::Error>, N: NewTransport<Transport=T>+Clone+'static {
    fn poll_not_connected<'a>(not_connected: &'a mut RentToOwn<'a, NotConnected<Item, S, K, T, N>>) -> Poll<AfterNotConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("not connected");

        let retry_strategy = FibonacciBackoff ::from_millis(1)
            .max_delay(Duration::from_millis(2000))
            .map(jitter);

        let handle = not_connected.handle.clone();
        let new_transport = not_connected.new_transport.clone();

        let tcp_future = Box::new(Retry::spawn(handle, retry_strategy, move || {
            new_transport.new_transport()
        }).map_err(|e| {
            match e {
                tokio_retry::Error::OperationError(e) => io::Error::new(io::ErrorKind::Other, e),
                tokio_retry::Error::TimerError(e) => e,
            }
        })) as (Box<Future<Item=T,Error=io::Error>>);

        let not_connected = not_connected.take();
        Ok(Async::Ready(Connecting {
            handle: not_connected.handle,
            stream: not_connected.stream,
            sink: not_connected.sink,
            tcp_future: tcp_future,
            error_count: not_connected.error_count,
            session_id: not_connected.session_id,
            new_transport: not_connected.new_transport,
        }.into()))
    }

    fn poll_connecting<'a>(connecting: &'a mut RentToOwn<'a, Connecting<Item, S, K, T, N>>) -> Poll<AfterConnecting<Item, S, K, T, N>, ConnectionError> {
        trace!("connecting");

        let tcp = try_ready!(connecting.tcp_future.poll());

        let connecting = connecting.take();
        Ok(Async::Ready(Connected {
            handle: connecting.handle,
            stream: connecting.stream,
            sink: connecting.sink,
            tcp: tcp,
            inbound: None,
            inbound_inflight: 0,
            outbound: None,
            outbound_inflight: 0,
            error_count: connecting.error_count,
            session_id: connecting.session_id,
            new_transport: connecting.new_transport,
        }.into()))
    }

    fn poll_connected<'a>(connected: &'a mut RentToOwn<'a, Connected<Item, S, K, T, N>>) -> Poll<AfterConnected<Item, S, K, T, N>, ConnectionError> {
        trace!("connected");

        // we make progress if any poll returns Ready
        // if we make progress then we return a state or state change
        // otherwise return NotReady
        let mut progress = false;

        let mut received = connected.inbound.take();
        if received.is_none() && connected.inbound_inflight == 0 {
            received = match connected.tcp.poll() {
                Ok(Async::Ready(Some(msg))) => {
                    trace!("transport received msg");
                    progress = true;
                    Some(Message::Packet{session_id: connected.session_id, content: msg})
                },
                Ok(Async::Ready(None)) => {
                    trace!("transport returned end of stream");

                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                },
                Ok(Async::NotReady) => {
                    trace!("transport not ready to read");
                    None
                },
                Err(e) => {
                    trace!("transport read error: {:?}", e);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            };
        }

        let mut sending = connected.outbound.take();
        if sending.is_none() {
            sending = match try!(connected.stream.poll()) {
                Async::Ready(Some(msg)) => {
                    progress = true;

                    Some(msg)
                },
                Async::Ready(None) => {
                    trace!("stream finished");
                    return Ok(Async::Ready(Finished(()).into()));
                },
                Async::NotReady => {
                    trace!("stream not ready to read");
                    None
                }
            };
        }

        if let Some(sending) = sending {
            match connected.tcp.start_send(sending) {
                Ok(AsyncSink::Ready) => {
                    trace!("transport wrote message");
                    progress = true;
                    connected.outbound_inflight += 1;
                },
                Ok(AsyncSink::NotReady(sending)) => {
                    trace!("tcpstream not ready to write");
                    connected.outbound = Some(sending);
                },
                Err(err) => {
                    trace!("transport write error: {:?}", err);
                    let connected = connected.take();

                    return Ok(Async::Ready(NotConnected {
                        handle: connected.handle,
                        stream: connected.stream,
                        sink: connected.sink,
                        error_count: connected.error_count + 1,
                        session_id: connected.session_id + 1,
                        new_transport: connected.new_transport,
                    }.into()));
                }
            }
        }

        if let Some(msg) = received {
            match try!(connected.sink.start_send(msg)) {
                AsyncSink::Ready => {
                    trace!("sink started send");
                    progress = true;
                    connected.inbound_inflight += 1;
                },
                AsyncSink::NotReady(msg) => {
                    trace!("sink not ready");
                    connected.inbound = Some(msg);
                },
            }
        }

        if connected.inbound_inflight != 0 {
            match try!(connected.sink.poll_complete()) {
                Async::Ready(()) => {
                    trace!("sink polled complete");
                    progress = true;
                    connected.inbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("sink polled not ready");
                    // do nothing
                }
            }
        }

        if connected.outbound_inflight != 0 {
            match try!(connected.tcp.poll_complete()) {
                Async::Ready(()) => {
                    trace!("transport poll complete");
                    progress = true;
                    connected.outbound_inflight = 0;
                },
                Async::NotReady => {
                    trace!("transport sink polled not ready");
                    // do nothing
                }
            }
        }

        if progress {
            trace!("made progress");

            let connected = connected.take();

            return Ok(Async::Ready(Connected {
                handle: connected.handle,
                stream: connected.stream,
                sink: connected.sink,
                tcp: connected.tcp,
                inbound: connected.inbound,
                inbound_inflight: connected.inbound_inflight,
                outbound: connected.outbound,
                outbound_inflight: connected.outbound_inflight,
                error_count: connected.error_count,
                session_id: connected.session_id,
                new_transport: connected.new_transport,
            }.into()));
        } else {
            trace!("did not make progress");

            return Ok(Async::NotReady);
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{iter_input_pats, snippet, span_lint, type_is_unsafe_function};
use matches::matches;
use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::intravisit;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_target::spec::abi::Abi;
use syntax::ast;
use syntax::source_map::Span;

/// **What it does:** Checks for functions with too many parameters.
///
/// **Why is this bad?** Functions with lots of parameters are considered bad
/// style and reduce readability (“what does the 5th parameter mean?”). Consider
/// grouping some parameters into a new type.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
///     ..
/// }
/// ```
declare_clippy_lint! {
    pub TOO_MANY_ARGUMENTS,
    complexity,
    "functions with too many arguments"
}

/// **What it does:** Checks for functions with a large amount of lines.
///
/// **Why is this bad?** Functions with a lot of lines are harder to understand
/// due to having to look at a larger amount of code to understand what the
/// function is doing. Consider splitting the body of the function into
/// multiple functions.
///
/// **Known problems:** None.
///
/// **Example:**
/// ``` rust
/// fn im_too_long() {
/// println!("");
/// // ... 100 more LoC
/// println!("");
/// }
/// ```
declare_clippy_lint! {
    pub TOO_MANY_LINES,
    pedantic,
    "functions with too many lines"
}

/// **What it does:** Checks for public functions that dereferences raw pointer
/// arguments but are not marked unsafe.
///
/// **Why is this bad?** The function should probably be marked `unsafe`, since
/// for an arbitrary raw pointer, there is no way of telling for sure if it is
/// valid.
///
/// **Known problems:**
///
/// * It does not check functions recursively so if the pointer is passed to a
/// private non-`unsafe` function which does the dereferencing, the lint won't
/// trigger.
/// * It only checks for arguments whose type are raw pointers, not raw pointers
/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
/// `some_argument.get_raw_ptr()`).
///
/// **Example:**
/// ```rust
/// pub fn foo(x: *const u8) {
///     println!("{}", unsafe { *x });
/// }
/// ```
declare_clippy_lint! {
    pub NOT_UNSAFE_PTR_ARG_DEREF,
    correctness,
    "public functions dereferencing raw pointer arguments but not marked `unsafe`"
}

#[derive(Copy, Clone)]
pub struct Functions {
    threshold: u64,
    max_lines: u64,
}

impl Functions {
    pub fn new(threshold: u64, max_lines: u64) -> Self {
        Self { threshold, max_lines }
    }
}

impl LintPass for Functions {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF)
    }

    fn name(&self) -> &'static str {
        "Functions"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: intravisit::FnKind<'tcx>,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        span: Span,
        nodeid: ast::NodeId,
    ) {
        let is_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(nodeid)) {
            matches!(item.node, hir::ItemKind::Impl(_, _, _, _, Some(_), _, _))
        } else {
            false
        };

        let unsafety = match kind {
            hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _, _) => unsafety,
            hir::intravisit::FnKind::Method(_, sig, _, _) => sig.header.unsafety,
            hir::intravisit::FnKind::Closure(_) => return,
        };

        // don't warn for implementations, it's not their fault
        if !is_impl {
            // don't lint extern functions decls, it's not their fault either
            match kind {
                hir::intravisit::FnKind::Method(
                    _,
                    &hir::MethodSig {
                        header: hir::FnHeader { abi: Abi::Rust, .. },
                        ..
                    },
                    _,
                    _,
                )
                | hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
                    self.check_arg_number(cx, decl, span)
                },
                _ => {},
            }
        }

        self.check_raw_ptr(cx, unsafety, decl, body, nodeid);
        self.check_line_number(cx, span);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
        if let hir::TraitItemKind::Method(ref sig, ref eid) = item.node {
            // don't lint extern functions decls, it's not their fault
            if sig.header.abi == Abi::Rust {
                self.check_arg_number(cx, &sig.decl, item.span);
            }

            if let hir::TraitMethod::Provided(eid) = *eid {
                let body = cx.tcx.hir().body(eid);
                self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.id);
            }
        }
    }
}

impl<'a, 'tcx> Functions {
    fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) {
        let args = decl.inputs.len() as u64;
        if args > self.threshold {
            span_lint(
                cx,
                TOO_MANY_ARGUMENTS,
                span,
                &format!("this function has too many arguments ({}/{})", args, self.threshold),
            );
        }
    }

    fn check_line_number(self, cx: &LateContext<'_, '_>, span: Span) {
        if in_external_macro(cx.sess(), span) {
            return;
        }

        let code_snippet = snippet(cx, span, "..");
        let mut line_count: u64 = 0;
        let mut in_comment = false;
        let mut code_in_line;

        // Skip the surrounding function decl.
        let start_brace_idx = match code_snippet.find("{") {
            Some(i) => i + 1,
            None => 0,
        };
        let end_brace_idx = match code_snippet.find("}") {
            Some(i) => i,
            None => code_snippet.len(),
        };
        let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();

        for mut line in function_lines {
            code_in_line = false;
            loop {
                line = line.trim_start();
                if line.is_empty() {
                    break;
                }
                if in_comment {
                    match line.find("*/") {
                        Some(i) => {
                            line = &line[i + 2..];
                            in_comment = false;
                            continue;
                        },
                        None => break,
                    }
                } else {
                    let multi_idx = match line.find("/*") {
                        Some(i) => i,
                        None => line.len(),
                    };
                    let single_idx = match line.find("//") {
                        Some(i) => i,
                        None => line.len(),
                    };
                    code_in_line |= multi_idx > 0 && single_idx > 0;
                    // Implies multi_idx is below line.len()
                    if multi_idx < single_idx {
                        line = &line[multi_idx + 2..];
                        in_comment = true;
                        continue;
                    }
                    break;
                }
            }
            if code_in_line {
                line_count += 1;
            }
        }

        if line_count > self.max_lines {
            span_lint(cx, TOO_MANY_LINES, span, "This function has a large number of lines.")
        }
    }

    fn check_raw_ptr(
        self,
        cx: &LateContext<'a, 'tcx>,
        unsafety: hir::Unsafety,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        nodeid: ast::NodeId,
    ) {
        let expr = &body.value;
        if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
            let raw_ptrs = iter_input_pats(decl, body)
                .zip(decl.inputs.iter())
                .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
                .collect::<FxHashSet<_>>();

            if !raw_ptrs.is_empty() {
                let tables = cx.tcx.body_tables(body.id());
                let mut v = DerefVisitor {
                    cx,
                    ptrs: raw_ptrs,
                    tables,
                };

                hir::intravisit::walk_expr(&mut v, expr);
            }
        }
    }
}

fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<ast::NodeId> {
    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.node, &ty.node) {
        Some(id)
    } else {
        None
    }
}

struct DerefVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    ptrs: FxHashSet<ast::NodeId>,
    tables: &'a ty::TypeckTables<'tcx>,
}

impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        match expr.node {
            hir::ExprKind::Call(ref f, ref args) => {
                let ty = self.tables.expr_ty(f);

                if type_is_unsafe_function(self.cx, ty) {
                    for arg in args {
                        self.check_arg(arg);
                    }
                }
            },
            hir::ExprKind::MethodCall(_, _, ref args) => {
                let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id();
                let base_type = self.cx.tcx.type_of(def_id);

                if type_is_unsafe_function(self.cx, base_type) {
                    for arg in args {
                        self.check_arg(arg);
                    }
                }
            },
            hir::ExprKind::Unary(hir::UnDeref, ref ptr) => self.check_arg(ptr),
            _ => (),
        }

        hir::intravisit::walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
        intravisit::NestedVisitorMap::None
    }
}

impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> {
    fn check_arg(&self, ptr: &hir::Expr) {
        if let hir::ExprKind::Path(ref qpath) = ptr.node {
            if let Def::Local(id) = self.cx.tables.qpath_def(qpath, ptr.hir_id) {
                if self.ptrs.contains(&id) {
                    span_lint(
                        self.cx,
                        NOT_UNSAFE_PTR_ARG_DEREF,
                        ptr.span,
                        "this public function dereferences a raw pointer but is not marked `unsafe`",
                    );
                }
            }
        }
    }
}
<commit_msg>Changing single character string to a character match.<commit_after>use crate::utils::{iter_input_pats, snippet, span_lint, type_is_unsafe_function};
use matches::matches;
use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::intravisit;
use rustc::lint::{in_external_macro, LateContext, LateLintPass, LintArray, LintContext, LintPass};
use rustc::ty;
use rustc::{declare_tool_lint, lint_array};
use rustc_data_structures::fx::FxHashSet;
use rustc_target::spec::abi::Abi;
use syntax::ast;
use syntax::source_map::Span;

/// **What it does:** Checks for functions with too many parameters.
///
/// **Why is this bad?** Functions with lots of parameters are considered bad
/// style and reduce readability (“what does the 5th parameter mean?”). Consider
/// grouping some parameters into a new type.
///
/// **Known problems:** None.
///
/// **Example:**
/// ```rust
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
///     ..
/// }
/// ```
declare_clippy_lint! {
    pub TOO_MANY_ARGUMENTS,
    complexity,
    "functions with too many arguments"
}

/// **What it does:** Checks for functions with a large amount of lines.
///
/// **Why is this bad?** Functions with a lot of lines are harder to understand
/// due to having to look at a larger amount of code to understand what the
/// function is doing. Consider splitting the body of the function into
/// multiple functions.
///
/// **Known problems:** None.
///
/// **Example:**
/// ``` rust
/// fn im_too_long() {
/// println!("");
/// // ... 100 more LoC
/// println!("");
/// }
/// ```
declare_clippy_lint! {
    pub TOO_MANY_LINES,
    pedantic,
    "functions with too many lines"
}

/// **What it does:** Checks for public functions that dereferences raw pointer
/// arguments but are not marked unsafe.
///
/// **Why is this bad?** The function should probably be marked `unsafe`, since
/// for an arbitrary raw pointer, there is no way of telling for sure if it is
/// valid.
///
/// **Known problems:**
///
/// * It does not check functions recursively so if the pointer is passed to a
/// private non-`unsafe` function which does the dereferencing, the lint won't
/// trigger.
/// * It only checks for arguments whose type are raw pointers, not raw pointers
/// got from an argument in some other way (`fn foo(bar: &[*const u8])` or
/// `some_argument.get_raw_ptr()`).
///
/// **Example:**
/// ```rust
/// pub fn foo(x: *const u8) {
///     println!("{}", unsafe { *x });
/// }
/// ```
declare_clippy_lint! {
    pub NOT_UNSAFE_PTR_ARG_DEREF,
    correctness,
    "public functions dereferencing raw pointer arguments but not marked `unsafe`"
}

#[derive(Copy, Clone)]
pub struct Functions {
    threshold: u64,
    max_lines: u64,
}

impl Functions {
    pub fn new(threshold: u64, max_lines: u64) -> Self {
        Self { threshold, max_lines }
    }
}

impl LintPass for Functions {
    fn get_lints(&self) -> LintArray {
        lint_array!(TOO_MANY_ARGUMENTS, TOO_MANY_LINES, NOT_UNSAFE_PTR_ARG_DEREF)
    }

    fn name(&self) -> &'static str {
        "Functions"
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Functions {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        kind: intravisit::FnKind<'tcx>,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        span: Span,
        nodeid: ast::NodeId,
    ) {
        let is_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find(cx.tcx.hir().get_parent_node(nodeid)) {
            matches!(item.node, hir::ItemKind::Impl(_, _, _, _, Some(_), _, _))
        } else {
            false
        };

        let unsafety = match kind {
            hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }, _, _) => unsafety,
            hir::intravisit::FnKind::Method(_, sig, _, _) => sig.header.unsafety,
            hir::intravisit::FnKind::Closure(_) => return,
        };

        // don't warn for implementations, it's not their fault
        if !is_impl {
            // don't lint extern functions decls, it's not their fault either
            match kind {
                hir::intravisit::FnKind::Method(
                    _,
                    &hir::MethodSig {
                        header: hir::FnHeader { abi: Abi::Rust, .. },
                        ..
                    },
                    _,
                    _,
                )
                | hir::intravisit::FnKind::ItemFn(_, _, hir::FnHeader { abi: Abi::Rust, .. }, _, _) => {
                    self.check_arg_number(cx, decl, span)
                },
                _ => {},
            }
        }

        self.check_raw_ptr(cx, unsafety, decl, body, nodeid);
        self.check_line_number(cx, span);
    }

    fn check_trait_item(&mut self, cx: &LateContext<'a, 'tcx>, item: &'tcx hir::TraitItem) {
        if let hir::TraitItemKind::Method(ref sig, ref eid) = item.node {
            // don't lint extern functions decls, it's not their fault
            if sig.header.abi == Abi::Rust {
                self.check_arg_number(cx, &sig.decl, item.span);
            }

            if let hir::TraitMethod::Provided(eid) = *eid {
                let body = cx.tcx.hir().body(eid);
                self.check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.id);
            }
        }
    }
}

impl<'a, 'tcx> Functions {
    fn check_arg_number(self, cx: &LateContext<'_, '_>, decl: &hir::FnDecl, span: Span) {
        let args = decl.inputs.len() as u64;
        if args > self.threshold {
            span_lint(
                cx,
                TOO_MANY_ARGUMENTS,
                span,
                &format!("this function has too many arguments ({}/{})", args, self.threshold),
            );
        }
    }

    fn check_line_number(self, cx: &LateContext<'_, '_>, span: Span) {
        if in_external_macro(cx.sess(), span) {
            return;
        }

        let code_snippet = snippet(cx, span, "..");
        let mut line_count: u64 = 0;
        let mut in_comment = false;
        let mut code_in_line;

        // Skip the surrounding function decl.
        let start_brace_idx = match code_snippet.find('{') {
            Some(i) => i + 1,
            None => 0,
        };
        let end_brace_idx = match code_snippet.find('}') {
            Some(i) => i,
            None => code_snippet.len(),
        };
        let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines();

        for mut line in function_lines {
            code_in_line = false;
            loop {
                line = line.trim_start();
                if line.is_empty() {
                    break;
                }
                if in_comment {
                    match line.find("*/") {
                        Some(i) => {
                            line = &line[i + 2..];
                            in_comment = false;
                            continue;
                        },
                        None => break,
                    }
                } else {
                    let multi_idx = match line.find("/*") {
                        Some(i) => i,
                        None => line.len(),
                    };
                    let single_idx = match line.find("//") {
                        Some(i) => i,
                        None => line.len(),
                    };
                    code_in_line |= multi_idx > 0 && single_idx > 0;
                    // Implies multi_idx is below line.len()
                    if multi_idx < single_idx {
                        line = &line[multi_idx + 2..];
                        in_comment = true;
                        continue;
                    }
                    break;
                }
            }
            if code_in_line {
                line_count += 1;
            }
        }

        if line_count > self.max_lines {
            span_lint(cx, TOO_MANY_LINES, span, "This function has a large number of lines.")
        }
    }

    fn check_raw_ptr(
        self,
        cx: &LateContext<'a, 'tcx>,
        unsafety: hir::Unsafety,
        decl: &'tcx hir::FnDecl,
        body: &'tcx hir::Body,
        nodeid: ast::NodeId,
    ) {
        let expr = &body.value;
        if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(nodeid) {
            let raw_ptrs = iter_input_pats(decl, body)
                .zip(decl.inputs.iter())
                .filter_map(|(arg, ty)| raw_ptr_arg(arg, ty))
                .collect::<FxHashSet<_>>();

            if !raw_ptrs.is_empty() {
                let tables = cx.tcx.body_tables(body.id());
                let mut v = DerefVisitor {
                    cx,
                    ptrs: raw_ptrs,
                    tables,
                };

                hir::intravisit::walk_expr(&mut v, expr);
            }
        }
    }
}

fn raw_ptr_arg(arg: &hir::Arg, ty: &hir::Ty) -> Option<ast::NodeId> {
    if let (&hir::PatKind::Binding(_, id, _, _), &hir::TyKind::Ptr(_)) = (&arg.pat.node, &ty.node) {
        Some(id)
    } else {
        None
    }
}

struct DerefVisitor<'a, 'tcx: 'a> {
    cx: &'a LateContext<'a, 'tcx>,
    ptrs: FxHashSet<ast::NodeId>,
    tables: &'a ty::TypeckTables<'tcx>,
}

impl<'a, 'tcx> hir::intravisit::Visitor<'tcx> for DerefVisitor<'a, 'tcx> {
    fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
        match expr.node {
            hir::ExprKind::Call(ref f, ref args) => {
                let ty = self.tables.expr_ty(f);

                if type_is_unsafe_function(self.cx, ty) {
                    for arg in args {
                        self.check_arg(arg);
                    }
                }
            },
            hir::ExprKind::MethodCall(_, _, ref args) => {
                let def_id = self.tables.type_dependent_defs()[expr.hir_id].def_id();
                let base_type = self.cx.tcx.type_of(def_id);

                if type_is_unsafe_function(self.cx, base_type) {
                    for arg in args {
                        self.check_arg(arg);
                    }
                }
            },
            hir::ExprKind::Unary(hir::UnDeref, ref ptr) => self.check_arg(ptr),
            _ => (),
        }

        hir::intravisit::walk_expr(self, expr);
    }
    fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'tcx> {
        intravisit::NestedVisitorMap::None
    }
}

impl<'a, 'tcx: 'a> DerefVisitor<'a, 'tcx> {
    fn check_arg(&self, ptr: &hir::Expr) {
        if let hir::ExprKind::Path(ref qpath) = ptr.node {
            if let Def::Local(id) = self.cx.tables.qpath_def(qpath, ptr.hir_id) {
                if self.ptrs.contains(&id) {
                    span_lint(
                        self.cx,
                        NOT_UNSAFE_PTR_ARG_DEREF,
                        ptr.span,
                        "this public function dereferences a raw pointer but is not marked `unsafe`",
                    );
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate tar;
extern crate flate2;

use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;

use self::tar::Archive;
use self::flate2::read::GzDecoder;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during extraction. {}", why),
    });
}

pub fn extract_tar(input: &Path, output: &Path) {
    let file = custom_try!(File::open(input));
    let mut archive = Archive::new(file);

    match archive.unpack(output) {
        Err(why) => panic!("An error occured during extraction. \n{}", why),
    };
}

pub fn extract_gz(input: &Path, output: &Path) {
    let file = custom_try!(File::open(input));
    let archive = custom_try!(GzDecoder::new(BufReader::new(file)));
    let mut target = custom_try!(File::create(output));

    for byte in archive.bytes() {
        target.write(&[byte.unwrap()]);
    }
}

<commit_msg>Will change later.<commit_after>extern crate tar;
extern crate flate2;

use std::fs::File;
use std::io::{BufReader, Read, Write};
use std::path::Path;

use self::tar::Archive;
use self::flate2::read::GzDecoder;

macro_rules! custom_try {
    ($x:expr) => (match $x {
        Ok(x) => x,
        Err(why) => panic!("An error occured during extraction. {}", why),
    });
}

pub fn extract_tar(input: &Path, output: &Path) {
    let file = custom_try!(File::open(input));
    let mut archive = Archive::new(file);

    archive.unpack(output).ok();
}

pub fn extract_gz(input: &Path, output: &Path) {
    let file = custom_try!(File::open(input));
    let archive = custom_try!(GzDecoder::new(BufReader::new(file)));
    let mut target = custom_try!(File::create(output));

    for byte in archive.bytes() {
        target.write(&[byte.unwrap()]);
    }
}

<|endoftext|>


<commit_before>use uuid::Uuid;
use std::rc::Rc;

use action::{Action, ExecResult};
use conditions::Conditions;
use config;
use message::Message;
use state::State;
use timer::TimerEvent;

#[derive(Debug)]
pub struct BaseContext {
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContext {
        BaseContext {
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.update_timers(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.actions.is_empty() {
            state.close();
            None
        } else {
            let commands = self.actions.iter().map(|action| action.execute(state, self)).collect();
            state.close();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{name, uuid, conditions, actions} = config;
        BaseContext {
            uuid: uuid,
            conditions: conditions,
            actions: actions
        }
    }
}
<commit_msg>BaseContext: add name field<commit_after>use uuid::Uuid;
use std::rc::Rc;

use action::{Action, ExecResult};
use conditions::Conditions;
use config;
use message::Message;
use state::State;
use timer::TimerEvent;

#[derive(Debug)]
pub struct BaseContext {
    name: Option<String>,
    uuid: Uuid,
    conditions: Conditions,
    actions: Vec<Action>
}

impl BaseContext {
    pub fn new(uuid: Uuid, conditions: Conditions) -> BaseContext {
        BaseContext {
            name: None,
            uuid: uuid,
            conditions: conditions,
            actions: Vec::new()
        }
    }

    pub fn conditions(&self) -> &Conditions {
        &self.conditions
    }

    pub fn on_timer(&self, event: &TimerEvent, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.update_timers(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        }
        None
    }

    pub fn on_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.conditions.ignore_message(&event) {
            None
        } else {
            self.on_relevant_message(event, state)
        }
    }

    fn on_relevant_message(&self, event: Rc<Message>, state: &mut State) -> Option<Vec<ExecResult>> {
        if state.is_open() {
            state.add_message(event);
            if self.conditions.is_closing(state) {
                return self.close_state(state);
            }
        } else if self.conditions.is_opening(&event) {
            state.add_message(event);
            state.open();
        }
        None
    }

    fn close_state(&self, state: &mut State) -> Option<Vec<ExecResult>> {
        if self.actions.is_empty() {
            state.close();
            None
        } else {
            let commands = self.actions.iter().map(|action| action.execute(state, self)).collect();
            state.close();
            Some(commands)
        }
    }
}

impl From<config::Context> for BaseContext {
    fn from(config: config::Context) -> BaseContext {
        let config::Context{name, uuid, conditions, actions} = config;
        BaseContext {
            name: name,
            uuid: uuid,
            conditions: conditions,
            actions: actions
        }
    }
}
<|endoftext|>


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

use bitstring::Bit;
use bitstring::Bitstring;

// Open questions:
// - How to declare some fields final
// - How to declare some fields mutable (can be changed for non-mut self)
// - Have the tree implement iter and simplify some methods with "fold".

/// An object capable of predicting observations and rewards based on
/// experience. Predictors have an abstract notion of history which
/// grows over time and represents the experience.
pub trait Predictor {
  /// Returns the size of the currently tracked history.
  fn history_size(&self) -> usize;

  /// Appends the provided bit string to the tracked history.
  fn update(&mut self, bitstring: &Bitstring);

  /// Reverts the context tree to a previous state by undoing update
  /// operations. The specified size must be at most the current size.
  fn revert_to_history_size(&mut self, target_size: usize);
}

/// Context tree which computes a probability estimate for a sequence of
/// bits based on a mixture model of Markov chains. Lower-degree Markov
/// chains have higher priors in the mixture model, thus formalizing the
/// notion of Occam's Razor.
///
/// In order to get a probability for a sequence, all bits in the sequence
/// must be processed in-order.
pub struct ContextTree {
  root: Node,
  history: Bitstring,
  depth: usize,
}

impl Predictor for ContextTree {
  fn history_size(&self) -> usize {
    self.history.len()
  }

  fn revert_to_history_size(&mut self, target_size: usize) {
    assert!(target_size <= self.history_size());
    while target_size > self.history_size() {
      self.revert_last();
    }
  }

  fn update(&mut self, bitstring: &Bitstring) {
    for bit in bitstring.bits() {
      self.update_bit(*bit);
    }
  }
}

impl ContextTree {
  /// The depth of the tree is the distance between leaves and the root.
  /// For a given depth d, the tree will compute a mixture model of all
  /// Markov chains of degree at most d.
  pub fn create(depth: usize) -> Self {
    ContextTree {
      root: Node::create_root(depth, 0),
      history: Bitstring::new(),
      depth: depth,
    }
  }

  /// Returns the total number of nodes in the tree.
  pub fn size(&self) -> usize {
    self.root.size()
  }

  fn update_bit(&mut self, bit: Bit) {
    if self.history_size() < self.depth {
      self.history.push(bit);
      return;
    }
    // TODO(dinowernli): Find current context path and update from leaf
    // to root.
  }

  fn revert_last(&mut self) {
    let bit = self.history.pop();
    self.root.revert(bit);
  }

  /// Returns log2 of the estimated probability of the current history.
  fn log_block_prob(&mut self) -> f64 {
    return self.root.log_weighted_prob();
  }
}

/// One node in the context tree. Maintains a count of the number
/// of zeroes and ones seen and provides access to partial results
/// of the overall probability estimates computed in the context
/// tree.
struct Node {
  /// Children.
  zero_child: Option<Box<Node>>,
  one_child: Option<Box<Node>>,

  /// Frequencies.
  zeroes: u64,
  ones: u64,

  /// The log2 of the probability of a sequence with self.zeroes zeroes
  /// and self.ones one. Computed using the Krichevsky Trofimov
  /// estimator algorithm.
  log_kt_prob: f64,

  /// The log2 of the weighted block probability of the current sequence.
  /// Funtion of self.zeroes and self.ones and the values recursively
  /// provided by the children of this node (if any), lazily recomputed.
  log_weighted_prob: f64,
}

impl Node {
  /// Creates a node and all its children recursively until the provided
  /// depth is reached.
  pub fn create_root(target_depth: usize, current_depth: usize) -> Self {
    if target_depth == current_depth {
      return Node::new(None, None);  // Leaf.
    } else {
      return Node::new(
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))),
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))));
    }
  }

  fn new(zero_child: Option<Box<Node>>, one_child: Option<Box<Node>>) -> Self {
    // Context trees are complete trees (either both children or no children).
    assert!(zero_child.is_none() == one_child.is_none());

    return Node {
      zero_child: zero_child,
      one_child: one_child,
      zeroes: 0,
      ones: 0,
      log_kt_prob: 0.0,
      log_weighted_prob: 0.0,
    };
  }

  pub fn log_weighted_prob(&self) -> f64 {
    self.log_weighted_prob
  }

  /// Updates the state of the node based on the value of the new bit.
  /// Assumes that child nodes (if any) have already been updated.
  pub fn update(&mut self, bit: Bit) {
    match bit {
      Bit::Zero => self.zeroes += 1,
      Bit::One => self.ones += 1,
    }

    // Old value + 0.5 is the same as new value - 0.5.
    let first_summand = match bit {
      Bit::Zero => self.zeroes as f64 - 0.5,
      Bit::One => self.ones as f64 - 0.5,
    }.log2();
    let norm_summand = ((self.zeroes + self.ones) as f64).log2();

    self.log_kt_prob = first_summand - norm_summand + self.log_kt_prob;
    self.update_weighted_prob();
  }

  /// Corresponds to undoing one update for the specified bit value.
  /// Assumes that child nodes (if any) have already been reverted.
  pub fn revert(&mut self, bit: Bit) {
    match bit {
      Bit::Zero => self.zeroes -= 1,
      Bit::One => self.ones -= 1,
    }
    // TODO(dinowernli): Update kt probs.
    self.update_weighted_prob();
  }

  /// Updates the value of log_weighted_prob. Assumes that log_kt_prob
  /// as well as all values in all children (if any) are up-to-date.
  fn update_weighted_prob(&mut self) {
    if self.is_leaf() {
      self.log_weighted_prob = self.log_kt_prob;
    }

    let log_weighted_probs =
        self.zero_child.as_ref().unwrap().log_weighted_prob() +
        self.one_child.as_ref().unwrap().log_weighted_prob();
    let exponent = log_weighted_probs - self.log_kt_prob;
    let power = exponent.exp2();

    // The recursive term should be log2(1 + 2^exponent). If the exponent is
    // large enough, 2^exponent is inf. In this case, we approximate
    // log2(1 + 2^exponent) by log2(2^exponent) = exponent.
    let inf = 1.0f64 / 0.0f64;
    let recursive_term =
        if power == inf { exponent } else { (power + 1.0).log2() };

    self.log_weighted_prob = self.log_kt_prob + recursive_term - 1.0;
  }

  /// Returns the number of nodes in the subtree rooted at this node.
  fn size(&self) -> usize {
    1 + match self.zero_child {
      None => 0,
      Some(ref node) => node.size(),
    } + match self.one_child {
      None => 0,
      Some(ref node) => node.size(),
    }
  }

  fn is_leaf(&self) -> bool {
    // By construction we have either both children or none.
    return self.zero_child.is_none();
  }
}
<commit_msg>Add missing return and use proper infinity.<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 dinowernli
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

use std::f64;

use bitstring::Bit;
use bitstring::Bitstring;

// Open questions:
// - How to declare some fields final
// - How to declare some fields mutable (can be changed for non-mut self)
// - Have the tree implement iter and simplify some methods with "fold".

/// An object capable of predicting observations and rewards based on
/// experience. Predictors have an abstract notion of history which
/// grows over time and represents the experience.
pub trait Predictor {
  /// Returns the size of the currently tracked history.
  fn history_size(&self) -> usize;

  /// Appends the provided bit string to the tracked history.
  fn update(&mut self, bitstring: &Bitstring);

  /// Reverts the context tree to a previous state by undoing update
  /// operations. The specified size must be at most the current size.
  fn revert_to_history_size(&mut self, target_size: usize);
}

/// Context tree which computes a probability estimate for a sequence of
/// bits based on a mixture model of Markov chains. Lower-degree Markov
/// chains have higher priors in the mixture model, thus formalizing the
/// notion of Occam's Razor.
///
/// In order to get a probability for a sequence, all bits in the sequence
/// must be processed in-order.
pub struct ContextTree {
  root: Node,
  history: Bitstring,
  depth: usize,
}

impl Predictor for ContextTree {
  fn history_size(&self) -> usize {
    self.history.len()
  }

  fn revert_to_history_size(&mut self, target_size: usize) {
    assert!(target_size <= self.history_size());
    while target_size > self.history_size() {
      self.revert_last();
    }
  }

  fn update(&mut self, bitstring: &Bitstring) {
    for bit in bitstring.bits() {
      self.update_bit(*bit);
    }
  }
}

impl ContextTree {
  /// The depth of the tree is the distance between leaves and the root.
  /// For a given depth d, the tree will compute a mixture model of all
  /// Markov chains of degree at most d.
  pub fn create(depth: usize) -> Self {
    ContextTree {
      root: Node::create_root(depth, 0),
      history: Bitstring::new(),
      depth: depth,
    }
  }

  /// Returns the total number of nodes in the tree.
  pub fn size(&self) -> usize {
    self.root.size()
  }

  fn update_bit(&mut self, bit: Bit) {
    if self.history_size() < self.depth {
      self.history.push(bit);
      return;
    }
    // TODO(dinowernli): Find current context path and update from leaf
    // to root.
  }

  fn revert_last(&mut self) {
    let bit = self.history.pop();
    self.root.revert(bit);
  }

  /// Returns log2 of the estimated probability of the current history.
  fn log_block_prob(&mut self) -> f64 {
    return self.root.log_weighted_prob();
  }
}

/// One node in the context tree. Maintains a count of the number
/// of zeroes and ones seen and provides access to partial results
/// of the overall probability estimates computed in the context
/// tree.
struct Node {
  /// Children.
  zero_child: Option<Box<Node>>,
  one_child: Option<Box<Node>>,

  /// Frequencies.
  zeroes: u64,
  ones: u64,

  /// The log2 of the probability of a sequence with self.zeroes zeroes
  /// and self.ones one. Computed using the Krichevsky Trofimov
  /// estimator algorithm.
  log_kt_prob: f64,

  /// The log2 of the weighted block probability of the current sequence.
  /// Funtion of self.zeroes and self.ones and the values recursively
  /// provided by the children of this node (if any), lazily recomputed.
  log_weighted_prob: f64,
}

impl Node {
  /// Creates a node and all its children recursively until the provided
  /// depth is reached.
  pub fn create_root(target_depth: usize, current_depth: usize) -> Self {
    if target_depth == current_depth {
      return Node::new(None, None);  // Leaf.
    } else {
      return Node::new(
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))),
          Some(Box::new(Node::create_root(target_depth, current_depth + 1))));
    }
  }

  fn new(zero_child: Option<Box<Node>>, one_child: Option<Box<Node>>) -> Self {
    // Context trees are complete trees (either both children or no children).
    assert!(zero_child.is_none() == one_child.is_none());

    return Node {
      zero_child: zero_child,
      one_child: one_child,
      zeroes: 0,
      ones: 0,
      log_kt_prob: 0.0,
      log_weighted_prob: 0.0,
    };
  }

  pub fn log_weighted_prob(&self) -> f64 {
    self.log_weighted_prob
  }

  /// Updates the state of the node based on the value of the new bit.
  /// Assumes that child nodes (if any) have already been updated.
  pub fn update(&mut self, bit: Bit) {
    match bit {
      Bit::Zero => self.zeroes += 1,
      Bit::One => self.ones += 1,
    }

    // Old value + 0.5 is the same as new value - 0.5.
    let first_summand = match bit {
      Bit::Zero => self.zeroes as f64 - 0.5,
      Bit::One => self.ones as f64 - 0.5,
    }.log2();
    let norm_summand = ((self.zeroes + self.ones) as f64).log2();

    self.log_kt_prob = first_summand - norm_summand + self.log_kt_prob;
    self.update_weighted_prob();
  }

  /// Corresponds to undoing one update for the specified bit value.
  /// Assumes that child nodes (if any) have already been reverted.
  pub fn revert(&mut self, bit: Bit) {
    match bit {
      Bit::Zero => self.zeroes -= 1,
      Bit::One => self.ones -= 1,
    }
    // TODO(dinowernli): Update kt probs.
    self.update_weighted_prob();
  }

  /// Updates the value of log_weighted_prob. Assumes that log_kt_prob
  /// as well as all values in all children (if any) are up-to-date.
  fn update_weighted_prob(&mut self) {
    if self.is_leaf() {
      self.log_weighted_prob = self.log_kt_prob;
      return;
    }

    let log_weighted_probs =
        self.zero_child.as_ref().unwrap().log_weighted_prob() +
        self.one_child.as_ref().unwrap().log_weighted_prob();
    let exponent = log_weighted_probs - self.log_kt_prob;
    let power = exponent.exp2();

    // The recursive term should be log2(1 + 2^exponent). If the exponent is
    // large enough, 2^exponent is inf. In this case, we approximate
    // log2(1 + 2^exponent) by log2(2^exponent) = exponent.
    let recursive_term =
        if power == f64::INFINITY { exponent } else { (power + 1.0).log2() };

    self.log_weighted_prob = self.log_kt_prob + recursive_term - 1.0;
  }

  /// Returns the number of nodes in the subtree rooted at this node.
  fn size(&self) -> usize {
    1 + match self.zero_child {
      None => 0,
      Some(ref node) => node.size(),
    } + match self.one_child {
      None => 0,
      Some(ref node) => node.size(),
    }
  }

  fn is_leaf(&self) -> bool {
    // By construction we have either both children or none.
    return self.zero_child.is_none();
  }
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use crate::parser;
use crate::prelude::*;
use core::{fmt, str};

impl From<super::BytesError> for super::Error {
    fn from(err: super::BytesError) -> Self {
        super::Error::Bytes(err)
    }
}

impl fmt::Debug for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            super::Error::Bytes(ref err) => fmt::Display::fmt(&err, f),
            super::Error::Parse(ref err) => fmt::Display::fmt(&err, f),
        }
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Variant::NCS => write!(f, "NCS"),
            Variant::RFC4122 => write!(f, "RFC4122"),
            Variant::Microsoft => write!(f, "Microsoft"),
            Variant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::Display for crate::BytesError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "invalid bytes length: expected {}, found {}",
            self.expected(),
            self.found()
        )
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl fmt::UpperHex for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = parser::ParseError;

    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    #[inline]
    fn default() -> Self {
        Uuid::nil()
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    use crate::test_util;
    use crate::tests::*;

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.to_hyphenated().to_string());

        check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    // noinspection RsAssertEqual
    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
    }
}
<commit_msg>readd the lowerhex impl<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// 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.

use crate::parser;
use crate::prelude::*;
use core::{fmt, str};

impl From<super::BytesError> for super::Error {
    fn from(err: super::BytesError) -> Self {
        super::Error::Bytes(err)
    }
}

impl fmt::Debug for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for super::Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            super::Error::Bytes(ref err) => fmt::Display::fmt(&err, f),
            super::Error::Parse(ref err) => fmt::Display::fmt(&err, f),
        }
    }
}

impl fmt::Display for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(self, f)
    }
}

impl fmt::Display for Variant {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            Variant::NCS => write!(f, "NCS"),
            Variant::RFC4122 => write!(f, "RFC4122"),
            Variant::Microsoft => write!(f, "Microsoft"),
            Variant::Future => write!(f, "Future"),
        }
    }
}

impl fmt::Display for crate::BytesError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "invalid bytes length: expected {}, found {}",
            self.expected(),
            self.found()
        )
    }
}

impl fmt::LowerHex for Uuid {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::LowerHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl fmt::UpperHex for Uuid {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::UpperHex::fmt(&self.to_hyphenated_ref(), f)
    }
}

impl str::FromStr for Uuid {
    type Err = parser::ParseError;

    fn from_str(uuid_str: &str) -> Result<Self, Self::Err> {
        Uuid::parse_str(uuid_str)
    }
}

impl Default for Uuid {
    #[inline]
    fn default() -> Self {
        Uuid::nil()
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    use crate::test_util;
    use crate::tests::*;

    macro_rules! check {
        ($buf:ident, $format:expr, $target:expr, $len:expr, $cond:expr) => {
            $buf.clear();
            write!($buf, $format, $target).unwrap();
            assert!($buf.len() == $len);
            assert!($buf.chars().all($cond), "{}", $buf);
        };
    }

    #[test]
    fn test_uuid_compare() {
        let uuid1 = test_util::new();
        let uuid2 = test_util::new2();

        assert_eq!(uuid1, uuid1);
        assert_eq!(uuid2, uuid2);

        assert_ne!(uuid1, uuid2);
        assert_ne!(uuid2, uuid1);
    }

    #[test]
    fn test_uuid_default() {
        let default_uuid = Uuid::default();
        let nil_uuid = Uuid::nil();

        assert_eq!(default_uuid, nil_uuid);
    }

    #[test]
    fn test_uuid_display() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s, uuid.to_hyphenated().to_string());

        check!(buffer, "{}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_lowerhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:x}", uuid, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    // noinspection RsAssertEqual
    #[test]
    fn test_uuid_operator_eq() {
        let uuid1 = test_util::new();
        let uuid1_dup = uuid1.clone();
        let uuid2 = test_util::new2();

        assert!(uuid1 == uuid1);
        assert!(uuid1 == uuid1_dup);
        assert!(uuid1_dup == uuid1);

        assert!(uuid1 != uuid2);
        assert!(uuid2 != uuid1);
        assert!(uuid1_dup != uuid2);
        assert!(uuid2 != uuid1_dup);
    }

    #[test]
    fn test_uuid_to_string() {
        use super::fmt::Write;

        let uuid = test_util::new();
        let s = uuid.to_string();
        let mut buffer = String::new();

        assert_eq!(s.len(), 36);

        check!(buffer, "{}", s, 36, |c| c.is_lowercase()
            || c.is_digit(10)
            || c == '-');
    }

    #[test]
    fn test_uuid_upperhex() {
        use super::fmt::Write;

        let mut buffer = String::new();
        let uuid = test_util::new();

        check!(buffer, "{:X}", uuid, 36, |c| c.is_uppercase()
            || c.is_digit(10)
            || c == '-');
    }
}
<|endoftext|>


<commit_before>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        Vector::new(vec![0])
    }

    fn train(&mut self, data: Matrix<f64>) {
    	self.init_centroids(data.cols);

    	for i in 0..self.iters {
    		let idx = self.find_closest_centroids(&data);
    		self.compute_means(&data, idx);
    	}
    }
}

impl KMeansClassifier {
	pub fn new(k: usize) -> KMeansClassifier {
		KMeansClassifier{ iters: 100, k:k, centroids: None}
	}

    fn init_centroids(&mut self, dim: usize) {
    	// These should not all be equal!
    	self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
    	let mut idx = Vector::zeros(data.rows);

    	for i in 0..data.rows {
    		for j in 0..self.k {
    			// idx[i] = argmin distance to centroid;
    		}
    	}
    	idx
    }

    fn compute_means(&mut self, data: &Matrix<f64>, classes: Vector<usize>)
    {
    	for i in 0..self.k {
    		let mut vec_k = Vec::new();

    		for j in classes.data.iter() {
    			if *j == i {
    				vec_k.push(j);
    			}
    		}

    		// index out these rows from data
    		// make a new matrix
    		// compute average of it's rows
    	}
    }
}

<commit_msg>Filling out code for k-means.<commit_after>use linalg::matrix::Matrix;
use linalg::vector::Vector;
use learning::UnSupModel;

struct KMeansClassifier {
    iters: usize,
    k: usize,
    centroids: Option<Matrix<f64>>,
}

impl UnSupModel<Matrix<f64>, Vector<usize>> for KMeansClassifier {
    fn predict(&self, data: Matrix<f64>) -> Vector<usize> {
        Vector::new(vec![0])
    }

    fn train(&mut self, data: Matrix<f64>) {
        self.init_centroids(data.cols);

        for i in 0..self.iters {
            let idx = self.find_closest_centroids(&data);
            self.compute_means(&data, idx);
        }
    }
}

impl KMeansClassifier {
    pub fn new(k: usize) -> KMeansClassifier {
        KMeansClassifier {
            iters: 100,
            k: k,
            centroids: None,
        }
    }

    fn init_centroids(&mut self, dim: usize) {
        // These should not all be equal!
        self.centroids = Some(Matrix::zeros(self.k, dim));
    }

    fn find_closest_centroids(&self, data: &Matrix<f64>) -> Vector<usize> {
        let mut idx = Vector::zeros(data.rows);

        match self.centroids {
            Some(ref c) => {
                for i in 0..data.rows {
                    let centroid_dist = c - data.select_rows(&vec![i; c.rows]);
                    let dist = &centroid_dist.elemul(&centroid_dist).sum_cols();
                    // Now take argmin and this is the centroid.

                }
            }
            None => panic!("Centroids not defined."),
        }

        idx
    }

    fn compute_means(&mut self, data: &Matrix<f64>, classes: Vector<usize>) {
        for i in 0..self.k {
            let mut vec_k = Vec::new();

            for j in classes.data.iter() {
                if *j == i {
                    vec_k.push(j);
                }
            }

            // index out these rows from data
            // make a new matrix
            // compute average of it's rows
        }
    }
}
<|endoftext|>