<commit_before>use ::data::{NBT, NBTFile, Compression};

use std::io;
use std::io::Read;

use regex::Regex;

/** Based on the idea of std::io::Cursor, letting us iterate over all the tags
 * from the pretty text format */
struct Cursor {
    inner: Vec<String>,
    index: usize,
}
impl Cursor {
    fn new(tags: Vec<String>) -> Self {
        Cursor {
            inner: tags,
            index: 0,
        }
    }
    /** Gets the next item, pushing the index one forward */
    fn next(&mut self) -> io::Result<&str> {
        match self.inner.get(self.index) {
            Some(ref x) => {
                self.index += 1;
                Ok(x)
            },
            None => io_error!("Tried to read beyond Cursor"),
        }
    }
}

/** Read an NBT file from the reader, in the pretty text format */
pub fn read_file<R: Read>(reader: &mut R) -> io::Result<NBTFile> {
    let mut buf = Vec::new();
    let _: usize = reader.read_to_end(&mut buf)?;
    let string = match String::from_utf8(buf) {
        Ok(x) => x,
        Err(_) => return io_error!("Unable to parse string as valid UTF-8"),
    };

    /* We want to make a Vec<String> of all the items in the pretty text format,
     * where an item is defined as a Type, Length or other atomic value.
     *
     * For almost all items this is no problem, because \S+ will match them,
     * but strings are just a slight exception, because they can contain any
     * character, including newline. */
    let re = Regex::new(r"(?s:''(.*?)'')|(\S+)").unwrap();

    let mut tags: Vec<String> = Vec::new();
    for cap in re.captures_iter(&string) {
        tags.push(match cap.get(1) {
            /* Only the first capture is a String, so we only undo the quotes
             * on the first capture, not that it would make any difference also
             * doing it on the second */
            Some(x) => x.as_str().replace(r#"\'"#, r#"'"#),
            None => match cap.get(2) {
                Some(x) => x.as_str().to_string(),
                None => return io_error!("Capture did not match regex"),
            },
        });
    };

    if tags.len() < 2 {
        /* There has to be at least 2 tags: The compression, and the End tag
         * for the implicit compound */
        return io_error!("Invalid text file, too short");
    }

    let mut cursor = Cursor::new(tags);

    let compression = {
        let tmp = cursor.next()?;

        match Compression::from_str(tmp) {
            Some(x) => x,
            None => return io_error!("Unknown compression format {}", tmp),
        }
    };

    let root = read_compound(&mut cursor)?;

    Ok(NBTFile {
        root: root,
        compression: compression,
    })
}

fn read_tag(tags: &mut Cursor, tag_type: &str) -> io::Result<NBT> {
    match tag_type {
        "Byte" => read_byte(tags),
        "Short" => read_short(tags),
        "Int" => read_int(tags),
        "Long" => read_long(tags),
        "Float" => read_float(tags),
        "Double" => read_double(tags),
        "ByteArray" => read_byte_array(tags),
        "String" => read_string(tags),
        "List" => read_list(tags),
        "Compound" => read_compound(tags),
        "IntArray" => read_int_array(tags),
        _ => io_error!("Unknown tag type {}", tag_type),
    }
}

fn read_byte(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i8>() {
        Ok(x) => Ok(NBT::Byte(x)),
        Err(_) => io_error!("Invalid Byte {}", val),
    }
}

fn read_short(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i16>() {
        Ok(x) => Ok(NBT::Short(x)),
        Err(_) => io_error!("Invalid Short {}", val),
    }
}

fn read_int(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i32>() {
        Ok(x) => Ok(NBT::Int(x)),
        Err(_) => io_error!("Invalid Int {}", val),
    }
}

fn read_long(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i64>() {
        Ok(x) => Ok(NBT::Long(x)),
        Err(_) => io_error!("Invalid Long {}", val),
    }
}

fn read_float(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<f32>() {
        Ok(x) => Ok(NBT::Float(x)),
        Err(_) => io_error!("Invalid Float {}", val),
    }
}

fn read_double(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<f64>() {
        Ok(x) => Ok(NBT::Double(x)),
        Err(_) => io_error!("Invalid Double {}", val),
    }
}

fn read_byte_array(tags: &mut Cursor) -> io::Result<NBT> {
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::new();
    for _ in 0..len {
        tmp.push(match read_byte(tags)? {
            NBT::Byte(x) => x,
            _ => unreachable!(),
        });
    }
    Ok(NBT::ByteArray(tmp))
}

fn read_string(tags: &mut Cursor) -> io::Result<NBT> {
    Ok(NBT::String(tags.next()?.to_string()))
}

fn read_list(tags: &mut Cursor) -> io::Result<NBT> {
    let list_type = tags.next()?.to_string();
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::new();
    for _ in 0..len {
        tmp.push(read_tag(tags, &list_type)?);
    }

    Ok(NBT::List(tmp))
}

fn read_compound(tags: &mut Cursor) -> io::Result<NBT> {
    let mut map = Vec::new();

    loop {
        let tag_type = tags.next()?.to_string();

        /* If we get an End tag then the compound is done */
        if tag_type == "End" {
            break;
        }

        let name = tags.next()?.to_string();
        let nbt = read_tag(tags, &tag_type)?;

        map.push((name, nbt));
    }

    Ok(NBT::Compound(map))
}

fn read_int_array(tags: &mut Cursor) -> io::Result<NBT> {
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::new();
    for _ in 0..len {
        tmp.push(match read_int(tags)? {
            NBT::Int(x) => x,
            _ => unreachable!(),
        });
    }
    Ok(NBT::IntArray(tmp))
}

<commit_msg>Use Vec::with_capacity() instead of Vec::new() where possible<commit_after>use ::data::{NBT, NBTFile, Compression};

use std::io;
use std::io::Read;

use regex::Regex;

/** Based on the idea of std::io::Cursor, letting us iterate over all the tags
 * from the pretty text format */
struct Cursor {
    inner: Vec<String>,
    index: usize,
}
impl Cursor {
    fn new(tags: Vec<String>) -> Self {
        Cursor {
            inner: tags,
            index: 0,
        }
    }
    /** Gets the next item, pushing the index one forward */
    fn next(&mut self) -> io::Result<&str> {
        match self.inner.get(self.index) {
            Some(ref x) => {
                self.index += 1;
                Ok(x)
            },
            None => io_error!("Tried to read beyond Cursor"),
        }
    }
}

/** Read an NBT file from the reader, in the pretty text format */
pub fn read_file<R: Read>(reader: &mut R) -> io::Result<NBTFile> {
    let mut buf = Vec::new();
    let _: usize = reader.read_to_end(&mut buf)?;
    let string = match String::from_utf8(buf) {
        Ok(x) => x,
        Err(_) => return io_error!("Unable to parse string as valid UTF-8"),
    };

    /* We want to make a Vec<String> of all the items in the pretty text format,
     * where an item is defined as a Type, Length or other atomic value.
     *
     * For almost all items this is no problem, because \S+ will match them,
     * but strings are just a slight exception, because they can contain any
     * character, including newline. */
    let re = Regex::new(r"(?s:''(.*?)'')|(\S+)").unwrap();

    let mut tags: Vec<String> = Vec::new();
    for cap in re.captures_iter(&string) {
        tags.push(match cap.get(1) {
            /* Only the first capture is a String, so we only undo the quotes
             * on the first capture, not that it would make any difference also
             * doing it on the second */
            Some(x) => x.as_str().replace(r#"\'"#, r#"'"#),
            None => match cap.get(2) {
                Some(x) => x.as_str().to_string(),
                None => return io_error!("Capture did not match regex"),
            },
        });
    };

    if tags.len() < 2 {
        /* There has to be at least 2 tags: The compression, and the End tag
         * for the implicit compound */
        return io_error!("Invalid text file, too short");
    }

    let mut cursor = Cursor::new(tags);

    let compression = {
        let tmp = cursor.next()?;

        match Compression::from_str(tmp) {
            Some(x) => x,
            None => return io_error!("Unknown compression format {}", tmp),
        }
    };

    let root = read_compound(&mut cursor)?;

    Ok(NBTFile {
        root: root,
        compression: compression,
    })
}

fn read_tag(tags: &mut Cursor, tag_type: &str) -> io::Result<NBT> {
    match tag_type {
        "Byte" => read_byte(tags),
        "Short" => read_short(tags),
        "Int" => read_int(tags),
        "Long" => read_long(tags),
        "Float" => read_float(tags),
        "Double" => read_double(tags),
        "ByteArray" => read_byte_array(tags),
        "String" => read_string(tags),
        "List" => read_list(tags),
        "Compound" => read_compound(tags),
        "IntArray" => read_int_array(tags),
        _ => io_error!("Unknown tag type {}", tag_type),
    }
}

fn read_byte(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i8>() {
        Ok(x) => Ok(NBT::Byte(x)),
        Err(_) => io_error!("Invalid Byte {}", val),
    }
}

fn read_short(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i16>() {
        Ok(x) => Ok(NBT::Short(x)),
        Err(_) => io_error!("Invalid Short {}", val),
    }
}

fn read_int(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i32>() {
        Ok(x) => Ok(NBT::Int(x)),
        Err(_) => io_error!("Invalid Int {}", val),
    }
}

fn read_long(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<i64>() {
        Ok(x) => Ok(NBT::Long(x)),
        Err(_) => io_error!("Invalid Long {}", val),
    }
}

fn read_float(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<f32>() {
        Ok(x) => Ok(NBT::Float(x)),
        Err(_) => io_error!("Invalid Float {}", val),
    }
}

fn read_double(tags: &mut Cursor) -> io::Result<NBT> {
    let val = tags.next()?;
    match val.parse::<f64>() {
        Ok(x) => Ok(NBT::Double(x)),
        Err(_) => io_error!("Invalid Double {}", val),
    }
}

fn read_byte_array(tags: &mut Cursor) -> io::Result<NBT> {
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::with_capacity(len as usize);
    for _ in 0..len {
        tmp.push(match read_byte(tags)? {
            NBT::Byte(x) => x,
            _ => unreachable!(),
        });
    }
    Ok(NBT::ByteArray(tmp))
}

fn read_string(tags: &mut Cursor) -> io::Result<NBT> {
    Ok(NBT::String(tags.next()?.to_string()))
}

fn read_list(tags: &mut Cursor) -> io::Result<NBT> {
    let list_type = tags.next()?.to_string();
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::with_capacity(len as usize);
    for _ in 0..len {
        tmp.push(read_tag(tags, &list_type)?);
    }

    Ok(NBT::List(tmp))
}

fn read_compound(tags: &mut Cursor) -> io::Result<NBT> {
    let mut map = Vec::new();

    loop {
        let tag_type = tags.next()?.to_string();

        /* If we get an End tag then the compound is done */
        if tag_type == "End" {
            break;
        }

        let name = tags.next()?.to_string();
        let nbt = read_tag(tags, &tag_type)?;

        map.push((name, nbt));
    }

    Ok(NBT::Compound(map))
}

fn read_int_array(tags: &mut Cursor) -> io::Result<NBT> {
    let len = match read_int(tags)? {
        NBT::Int(x) => x,
        _ => unreachable!(),
    };
    let mut tmp = Vec::with_capacity(len as usize);
    for _ in 0..len {
        tmp.push(match read_int(tags)? {
            NBT::Int(x) => x,
            _ => unreachable!(),
        });
    }
    Ok(NBT::IntArray(tmp))
}

<|endoftext|>


<commit_before>#![cfg(target_os = "linux")]

pub mod ffi;

use std::fmt;
use std::ptr;
use std::rc::Rc;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};

use super::x11::ScreenID;

pub struct Connection {
   pub ptr: *mut ffi::xcb_connection_t
}

impl Connection {
   pub fn new(connection_ptr: *mut ffi::xcb_connection_t) -> Self {
      Connection {
         ptr: connection_ptr,
      }
   }

   pub fn screen_of_display(&self, screen_id: &ScreenID) -> Result<Screen, RuntimeError> {
      let setup = unsafe { ffi::xcb_get_setup(self.ptr) };

      if setup == ptr::null() {
         return Err(RuntimeError::new(
            ErrorKind::XCB,
            "Getting XCB connection setup failed".to_string()
         ));
      }

      let mut iter = unsafe {
         ffi::xcb_setup_roots_iterator(setup)
      };

      let mut screen_num = screen_id.screen;

      while screen_num > 0 && iter.rem != 0 {
         unsafe { ffi::xcb_screen_next(&mut iter) };
         screen_num -= 1;
      }

      Ok(Screen::new(iter.data))
   }

   pub fn generate_id(&self) -> Result<XID, RuntimeError> {
      let id = unsafe {
         ffi::xcb_generate_id(self.ptr)
      };

      if id == 0xffffffff {
         return Err(RuntimeError::new(
            ErrorKind::XCB,
            "Generating XID failed".to_string()
         ));
      }

      Ok(XID {
         id: id
      })
   }

   pub fn wait_for_event(&self) -> Option<Event> {
      let event_ptr = unsafe {
         ffi::xcb_wait_for_event(self.ptr)
      };

      if event_ptr.is_null() {
         return None;
      }

      Some(
         Event::new(event_ptr)
      )
   }

   pub fn poll_event_iter(&self) -> EventIterator {
      EventIterator::new(self.ptr)
   }

   pub fn flush(&self) {
      unsafe {
         ffi::xcb_flush(self.ptr);
      }
   }

   pub fn intern_atom(&self, name: &str, existing_only: bool) -> InternAtomCookie {
      let c_name = CString::new(name).unwrap();

      let xcb_cookie = unsafe {
         ffi::xcb_intern_atom(
               self.ptr,
               existing_only as ffi::c_uchar,
               name.len() as ffi::c_ushort,
               c_name.as_ptr()
         )
      };

      InternAtomCookie {
         xcb_cookie: xcb_cookie
      }
   }

   pub fn intern_atom_reply(&self, cookie: &InternAtomCookie) -> InternAtomReply {
      let xcb_reply = unsafe {
         ffi::xcb_intern_atom_reply(
            self.ptr,
            cookie.xcb_cookie,
            ptr::null_mut()
         )
      };

      InternAtomReply {
         xcb_reply: xcb_reply
      }
   }
}

#[derive(PartialEq)]
pub struct XID {
   pub id: ffi::c_uint
}

pub struct Screen {
   pub ptr: *mut ffi::xcb_screen_t
}

impl Screen {
   pub fn new(screen_ptr: *mut ffi::xcb_screen_t) -> Self {
      Screen {
         ptr: screen_ptr,
      }
   }

   getter!(root, ffi::xcb_window_t);

   getter!(default_colormap, ffi::xcb_colormap_t);

   getter!(white_pixel, ffi::c_uint);

   getter!(black_pixel, ffi::c_uint);

   getter!(current_input_masks, ffi::c_uint);

   getter!(width_in_pixels, ffi::c_ushort);

   getter!(height_in_pixels, ffi::c_ushort);

   getter!(width_in_millimeters, ffi::c_ushort);

   getter!(height_in_millimeters, ffi::c_ushort);

   getter!(min_installed_maps, ffi::c_ushort);

   getter!(max_installed_maps, ffi::c_ushort);

   getter!(root_visual, ffi::xcb_visualid_t);

   getter!(backing_stores, ffi::c_uchar);

   getter!(save_unders, ffi::c_uchar);

   getter!(root_depth, ffi::c_uchar);

   getter!(allowed_depths_len, ffi::c_uchar);
}

pub enum EventType {
   KeyPress,
   KeyRelease,
   ButtonPress,
   ButtonRelease,
   MotionNotify,
   EnterNotify,
   LeaveNotify,
   FocusIn,
   FocusOut,
   KeymapNotify,
   Expose,
   ClientMessage,
   ConfigureNotify,
   Unidentified,
}

impl EventType {
   pub fn new(xcb_type: ffi::c_uchar) -> Self {
      match xcb_type {
         ffi::XCB_KEY_PRESS => EventType::KeyPress,
         ffi::XCB_KEY_RELEASE => EventType::KeyRelease,
         ffi::XCB_BUTTON_PRESS => EventType::ButtonPress,
         ffi::XCB_BUTTON_RELEASE => EventType::ButtonRelease,
         ffi::XCB_MOTION_NOTIFY => EventType::MotionNotify,
         ffi::XCB_ENTER_NOTIFY => EventType::EnterNotify,
         ffi::XCB_LEAVE_NOTIFY => EventType::LeaveNotify,
         ffi::XCB_FOCUS_IN => EventType::FocusIn,
         ffi::XCB_FOCUS_OUT => EventType::FocusOut,
         ffi::XCB_KEYMAP_NOTIFY => EventType::KeymapNotify,
         ffi::XCB_EXPOSE => EventType::Expose,
         ffi::XCB_CLIENT_MESSAGE => EventType::ClientMessage,
         ffi::XCB_CONFIGURE_NOTIFY => EventType::ConfigureNotify,
         _ => EventType::Unidentified
      }
   }
}

impl fmt::Display for EventType {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      let type_str = match *self {
         EventType::KeyPress => "KeyPress",
         EventType::KeyRelease => "KeyRelease",
         EventType::ButtonPress => "ButtonPress",
         EventType::ButtonRelease => "ButtonRelease",
         EventType::MotionNotify => "MotionNotify",
         EventType::EnterNotify => "EnterNotify",
         EventType::LeaveNotify => "LeaveNotify",
         EventType::FocusIn => "FocusIn",
         EventType::FocusOut => "FocusOut",
         EventType::KeymapNotify => "KeymapNotify",
         EventType::Expose => "Expose",
         EventType::ClientMessage => "ClientMessage",
         EventType::ConfigureNotify => "ConfigureNotify",
         EventType::Unidentified => "Unidentified",
      };

      write!(f, "{}", type_str)
   }
}

pub struct Event {
   pub ptr: *mut ffi::xcb_generic_event_t
}

impl Event {
   pub fn new(event_ptr: *mut ffi::xcb_generic_event_t) -> Self {
      Event {
         ptr: event_ptr,
      }
   }

   pub fn event_type(&self) -> EventType {
      EventType::new(
         unsafe {
            (*self.ptr).response_type & !0x80
         }
      )
   }

   pub fn is_close_event(
      &self,
      protocols_atom: &Atom,
      delete_window_atom: &Atom
   ) -> bool {
      unsafe {
         let ptr = self.ptr as *mut ffi::xcb_client_message_event_t;

         let data = (*ptr).data.data32();

         if (*ptr).format != 32 ||
            (*ptr)._type != protocols_atom.xcb_atom ||
            (*data)[0] != delete_window_atom.xcb_atom {
            return false;
         }

         true
      }
   }

   pub fn resize_properties(&self) -> (XID, u32, u32) {
      unsafe {
         let ptr = self.ptr as *mut ffi::xcb_configure_notify_event_t;

         let window_id = XID {
            id: (*ptr).window
         };

         (window_id, (*ptr).width as u32, (*ptr).height as u32)
      }
   }
}

impl Drop for Event {
   fn drop (&mut self) {
      unsafe {
         ffi::free(self.ptr as *mut _);
      }
   }
}

pub struct EventIterator {
   ptr: *mut ffi::xcb_connection_t,
   started: bool,
}

impl EventIterator {
   pub fn new(connection_ptr: *mut ffi::xcb_connection_t) -> Self {
      EventIterator {
         ptr: connection_ptr,
         started: false,
      }
   }
}

impl Iterator for EventIterator {
   type Item = Result<Event, RuntimeError>;

   fn next(&mut self) -> Option<Result<Event, RuntimeError>> {
      let event_ptr = unsafe {
         if !self.started {
            self.started = true;
            ffi::xcb_poll_for_event(self.ptr)
         } else {
            ffi::xcb_poll_for_queued_event(self.ptr)
         }
      };

      if event_ptr.is_null() {
         if unsafe { ffi::xcb_connection_has_error(self.ptr) } != 0 {
            return Some(
               Err(RuntimeError::new(
                  ErrorKind::XCB,
                  "Poll event failed".to_string()
               ))
            );
         }

         return None;
      }

      Some(
         Ok(Event::new(event_ptr))
      )
   }
}

pub struct Window {
   pub connection: Rc<Connection>,
   pub window_id: XID,
}

impl Window {
   pub fn create(
      connection: &Rc<Connection>,
      screen: &Screen,
      width: u32,
      height: u32,
   ) -> Result<Self, RuntimeError> {
      let window_id = match connection.generate_id() {
         Ok(window_id) => window_id,
         Err(e) => return Err(e)
      };

      let eventmask = ffi::XCB_EVENT_MASK_EXPOSURE |
         ffi::XCB_EVENT_MASK_KEY_PRESS |
         ffi::XCB_EVENT_MASK_STRUCTURE_NOTIFY;
      let valuelist = [eventmask, 0];
      let valuemask = ffi::XCB_CW_EVENT_MASK;

      let cookie = unsafe {
         ffi::xcb_create_window_checked(
            connection.ptr,
            ffi::XCB_COPY_FROM_PARENT as u8,
            window_id.id,
            screen.root(),
            0, 0,
            width as ffi::c_ushort, height as ffi::c_ushort,
            0,
            ffi::XCB_WINDOW_CLASS_INPUT_OUTPUT as u16,
            screen.root_visual(),
            valuemask,
            valuelist.as_ptr()
         )
      };

      match error_check(connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Create XCB window failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(Window {
         connection: connection.clone(),
         window_id: window_id,
      })
   }

   pub fn map(&self) -> Result<(), RuntimeError> {
      let cookie = unsafe {
         ffi::xcb_map_window_checked(self.connection.ptr, self.window_id.id)
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Mapping XCB window failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }

   pub fn position(&self, x: u32, y: u32) -> Result<(), RuntimeError> {
      let value_mask = ffi::XCB_CONFIG_WINDOW_X | ffi::XCB_CONFIG_WINDOW_Y;
      let value_list = [x as ffi::c_uint, y as ffi::c_uint, 0];

      let cookie = unsafe {
         ffi::xcb_configure_window_checked(
            self.connection.ptr,
            self.window_id.id,
            value_mask as ffi::c_ushort,
            value_list.as_ptr()
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Setting XCB window position failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }

   pub fn register_close_event(&self) -> Result<(Atom, Atom), RuntimeError> {
      let protocols_cookie = self.connection.intern_atom("WM_PROTOCOLS", true);
      let protocols_reply = self.connection.intern_atom_reply(&protocols_cookie);

      let delete_window_cookie = self.connection.intern_atom("WM_DELETE_WINDOW", false);
      let delete_window_reply = self.connection.intern_atom_reply(&delete_window_cookie);

      let protocols_atom = protocols_reply.atom();
      let delete_window_atom = delete_window_reply.atom();

      let cookie = unsafe {
         ffi::xcb_change_property_checked(
            self.connection.ptr,
            ffi::XCB_PROP_MODE_REPLACE,
            self.window_id.id,
            protocols_atom.xcb_atom,
            ffi::XCB_ATOM_ATOM,
            32,
            1,
            &delete_window_atom.xcb_atom as *const u32 as *const _
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Registering close event failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok((protocols_atom, delete_window_atom))
   }

   pub fn set_title(&self, title: &str) -> Result<(), RuntimeError> {
      let c_title = CString::new(title).unwrap();

      let cookie = unsafe {
         ffi::xcb_change_property_checked(
            self.connection.ptr,
            ffi::XCB_PROP_MODE_REPLACE,
            self.window_id.id,
            ffi::XCB_ATOM_WM_NAME,
            ffi::XCB_ATOM_STRING,
            8,
            title.len() as ffi::c_uint,
            c_title.as_ptr() as *const _
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Setting window title failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }
}

fn error_check(
   c: *mut ffi::xcb_connection_t,
   cookie: ffi::xcb_void_cookie_t
) -> Option<ffi::c_uchar> {

   let error = unsafe {
      ffi::xcb_request_check(c, cookie)
   };

   if error != ptr::null_mut() {
      return Some(
         unsafe {
            (*error).error_code
         }
      )
   }

   None
}

impl Drop for Window {
   fn drop (&mut self) {
      unsafe {
         ffi::xcb_destroy_window(
            self.connection.ptr, self.window_id.id
         );
      }
   }
}

pub struct Atom {
   xcb_atom: ffi::xcb_atom_t
}

pub struct InternAtomCookie {
   xcb_cookie: ffi::xcb_intern_atom_cookie_t
}

pub struct InternAtomReply {
   xcb_reply: *mut ffi::xcb_intern_atom_reply_t
}

impl InternAtomReply {
   pub fn atom(&self) -> Atom {
      let xcb_atom = unsafe { (*(self.xcb_reply)).atom };
      Atom {
         xcb_atom: xcb_atom
      }
   }
}
<commit_msg>Do not register for exposure event in XCB<commit_after>#![cfg(target_os = "linux")]

pub mod ffi;

use std::fmt;
use std::ptr;
use std::rc::Rc;
use std::ffi::CString;

use error::{RuntimeError, ErrorKind};

use super::x11::ScreenID;

pub struct Connection {
   pub ptr: *mut ffi::xcb_connection_t
}

impl Connection {
   pub fn new(connection_ptr: *mut ffi::xcb_connection_t) -> Self {
      Connection {
         ptr: connection_ptr,
      }
   }

   pub fn screen_of_display(&self, screen_id: &ScreenID) -> Result<Screen, RuntimeError> {
      let setup = unsafe { ffi::xcb_get_setup(self.ptr) };

      if setup == ptr::null() {
         return Err(RuntimeError::new(
            ErrorKind::XCB,
            "Getting XCB connection setup failed".to_string()
         ));
      }

      let mut iter = unsafe {
         ffi::xcb_setup_roots_iterator(setup)
      };

      let mut screen_num = screen_id.screen;

      while screen_num > 0 && iter.rem != 0 {
         unsafe { ffi::xcb_screen_next(&mut iter) };
         screen_num -= 1;
      }

      Ok(Screen::new(iter.data))
   }

   pub fn generate_id(&self) -> Result<XID, RuntimeError> {
      let id = unsafe {
         ffi::xcb_generate_id(self.ptr)
      };

      if id == 0xffffffff {
         return Err(RuntimeError::new(
            ErrorKind::XCB,
            "Generating XID failed".to_string()
         ));
      }

      Ok(XID {
         id: id
      })
   }

   pub fn wait_for_event(&self) -> Option<Event> {
      let event_ptr = unsafe {
         ffi::xcb_wait_for_event(self.ptr)
      };

      if event_ptr.is_null() {
         return None;
      }

      Some(
         Event::new(event_ptr)
      )
   }

   pub fn poll_event_iter(&self) -> EventIterator {
      EventIterator::new(self.ptr)
   }

   pub fn flush(&self) {
      unsafe {
         ffi::xcb_flush(self.ptr);
      }
   }

   pub fn intern_atom(&self, name: &str, existing_only: bool) -> InternAtomCookie {
      let c_name = CString::new(name).unwrap();

      let xcb_cookie = unsafe {
         ffi::xcb_intern_atom(
               self.ptr,
               existing_only as ffi::c_uchar,
               name.len() as ffi::c_ushort,
               c_name.as_ptr()
         )
      };

      InternAtomCookie {
         xcb_cookie: xcb_cookie
      }
   }

   pub fn intern_atom_reply(&self, cookie: &InternAtomCookie) -> InternAtomReply {
      let xcb_reply = unsafe {
         ffi::xcb_intern_atom_reply(
            self.ptr,
            cookie.xcb_cookie,
            ptr::null_mut()
         )
      };

      InternAtomReply {
         xcb_reply: xcb_reply
      }
   }
}

#[derive(PartialEq)]
pub struct XID {
   pub id: ffi::c_uint
}

pub struct Screen {
   pub ptr: *mut ffi::xcb_screen_t
}

impl Screen {
   pub fn new(screen_ptr: *mut ffi::xcb_screen_t) -> Self {
      Screen {
         ptr: screen_ptr,
      }
   }

   getter!(root, ffi::xcb_window_t);

   getter!(default_colormap, ffi::xcb_colormap_t);

   getter!(white_pixel, ffi::c_uint);

   getter!(black_pixel, ffi::c_uint);

   getter!(current_input_masks, ffi::c_uint);

   getter!(width_in_pixels, ffi::c_ushort);

   getter!(height_in_pixels, ffi::c_ushort);

   getter!(width_in_millimeters, ffi::c_ushort);

   getter!(height_in_millimeters, ffi::c_ushort);

   getter!(min_installed_maps, ffi::c_ushort);

   getter!(max_installed_maps, ffi::c_ushort);

   getter!(root_visual, ffi::xcb_visualid_t);

   getter!(backing_stores, ffi::c_uchar);

   getter!(save_unders, ffi::c_uchar);

   getter!(root_depth, ffi::c_uchar);

   getter!(allowed_depths_len, ffi::c_uchar);
}

pub enum EventType {
   KeyPress,
   KeyRelease,
   ButtonPress,
   ButtonRelease,
   MotionNotify,
   EnterNotify,
   LeaveNotify,
   FocusIn,
   FocusOut,
   KeymapNotify,
   Expose,
   ClientMessage,
   ConfigureNotify,
   Unidentified,
}

impl EventType {
   pub fn new(xcb_type: ffi::c_uchar) -> Self {
      match xcb_type {
         ffi::XCB_KEY_PRESS => EventType::KeyPress,
         ffi::XCB_KEY_RELEASE => EventType::KeyRelease,
         ffi::XCB_BUTTON_PRESS => EventType::ButtonPress,
         ffi::XCB_BUTTON_RELEASE => EventType::ButtonRelease,
         ffi::XCB_MOTION_NOTIFY => EventType::MotionNotify,
         ffi::XCB_ENTER_NOTIFY => EventType::EnterNotify,
         ffi::XCB_LEAVE_NOTIFY => EventType::LeaveNotify,
         ffi::XCB_FOCUS_IN => EventType::FocusIn,
         ffi::XCB_FOCUS_OUT => EventType::FocusOut,
         ffi::XCB_KEYMAP_NOTIFY => EventType::KeymapNotify,
         ffi::XCB_EXPOSE => EventType::Expose,
         ffi::XCB_CLIENT_MESSAGE => EventType::ClientMessage,
         ffi::XCB_CONFIGURE_NOTIFY => EventType::ConfigureNotify,
         _ => EventType::Unidentified
      }
   }
}

impl fmt::Display for EventType {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      let type_str = match *self {
         EventType::KeyPress => "KeyPress",
         EventType::KeyRelease => "KeyRelease",
         EventType::ButtonPress => "ButtonPress",
         EventType::ButtonRelease => "ButtonRelease",
         EventType::MotionNotify => "MotionNotify",
         EventType::EnterNotify => "EnterNotify",
         EventType::LeaveNotify => "LeaveNotify",
         EventType::FocusIn => "FocusIn",
         EventType::FocusOut => "FocusOut",
         EventType::KeymapNotify => "KeymapNotify",
         EventType::Expose => "Expose",
         EventType::ClientMessage => "ClientMessage",
         EventType::ConfigureNotify => "ConfigureNotify",
         EventType::Unidentified => "Unidentified",
      };

      write!(f, "{}", type_str)
   }
}

pub struct Event {
   pub ptr: *mut ffi::xcb_generic_event_t
}

impl Event {
   pub fn new(event_ptr: *mut ffi::xcb_generic_event_t) -> Self {
      Event {
         ptr: event_ptr,
      }
   }

   pub fn event_type(&self) -> EventType {
      EventType::new(
         unsafe {
            (*self.ptr).response_type & !0x80
         }
      )
   }

   pub fn is_close_event(
      &self,
      protocols_atom: &Atom,
      delete_window_atom: &Atom
   ) -> bool {
      unsafe {
         let ptr = self.ptr as *mut ffi::xcb_client_message_event_t;

         let data = (*ptr).data.data32();

         if (*ptr).format != 32 ||
            (*ptr)._type != protocols_atom.xcb_atom ||
            (*data)[0] != delete_window_atom.xcb_atom {
            return false;
         }

         true
      }
   }

   pub fn resize_properties(&self) -> (XID, u32, u32) {
      unsafe {
         let ptr = self.ptr as *mut ffi::xcb_configure_notify_event_t;

         let window_id = XID {
            id: (*ptr).window
         };

         (window_id, (*ptr).width as u32, (*ptr).height as u32)
      }
   }
}

impl Drop for Event {
   fn drop (&mut self) {
      unsafe {
         ffi::free(self.ptr as *mut _);
      }
   }
}

pub struct EventIterator {
   ptr: *mut ffi::xcb_connection_t,
   started: bool,
}

impl EventIterator {
   pub fn new(connection_ptr: *mut ffi::xcb_connection_t) -> Self {
      EventIterator {
         ptr: connection_ptr,
         started: false,
      }
   }
}

impl Iterator for EventIterator {
   type Item = Result<Event, RuntimeError>;

   fn next(&mut self) -> Option<Result<Event, RuntimeError>> {
      let event_ptr = unsafe {
         if !self.started {
            self.started = true;
            ffi::xcb_poll_for_event(self.ptr)
         } else {
            ffi::xcb_poll_for_queued_event(self.ptr)
         }
      };

      if event_ptr.is_null() {
         if unsafe { ffi::xcb_connection_has_error(self.ptr) } != 0 {
            return Some(
               Err(RuntimeError::new(
                  ErrorKind::XCB,
                  "Poll event failed".to_string()
               ))
            );
         }

         return None;
      }

      Some(
         Ok(Event::new(event_ptr))
      )
   }
}

pub struct Window {
   pub connection: Rc<Connection>,
   pub window_id: XID,
}

impl Window {
   pub fn create(
      connection: &Rc<Connection>,
      screen: &Screen,
      width: u32,
      height: u32,
   ) -> Result<Self, RuntimeError> {
      let window_id = match connection.generate_id() {
         Ok(window_id) => window_id,
         Err(e) => return Err(e)
      };

      let eventmask = ffi::XCB_EVENT_MASK_KEY_PRESS |
         ffi::XCB_EVENT_MASK_STRUCTURE_NOTIFY;
      let valuelist = [eventmask, 0];
      let valuemask = ffi::XCB_CW_EVENT_MASK;

      let cookie = unsafe {
         ffi::xcb_create_window_checked(
            connection.ptr,
            ffi::XCB_COPY_FROM_PARENT as u8,
            window_id.id,
            screen.root(),
            0, 0,
            width as ffi::c_ushort, height as ffi::c_ushort,
            0,
            ffi::XCB_WINDOW_CLASS_INPUT_OUTPUT as u16,
            screen.root_visual(),
            valuemask,
            valuelist.as_ptr()
         )
      };

      match error_check(connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Create XCB window failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(Window {
         connection: connection.clone(),
         window_id: window_id,
      })
   }

   pub fn map(&self) -> Result<(), RuntimeError> {
      let cookie = unsafe {
         ffi::xcb_map_window_checked(self.connection.ptr, self.window_id.id)
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Mapping XCB window failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }

   pub fn position(&self, x: u32, y: u32) -> Result<(), RuntimeError> {
      let value_mask = ffi::XCB_CONFIG_WINDOW_X | ffi::XCB_CONFIG_WINDOW_Y;
      let value_list = [x as ffi::c_uint, y as ffi::c_uint, 0];

      let cookie = unsafe {
         ffi::xcb_configure_window_checked(
            self.connection.ptr,
            self.window_id.id,
            value_mask as ffi::c_ushort,
            value_list.as_ptr()
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Setting XCB window position failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }

   pub fn register_close_event(&self) -> Result<(Atom, Atom), RuntimeError> {
      let protocols_cookie = self.connection.intern_atom("WM_PROTOCOLS", true);
      let protocols_reply = self.connection.intern_atom_reply(&protocols_cookie);

      let delete_window_cookie = self.connection.intern_atom("WM_DELETE_WINDOW", false);
      let delete_window_reply = self.connection.intern_atom_reply(&delete_window_cookie);

      let protocols_atom = protocols_reply.atom();
      let delete_window_atom = delete_window_reply.atom();

      let cookie = unsafe {
         ffi::xcb_change_property_checked(
            self.connection.ptr,
            ffi::XCB_PROP_MODE_REPLACE,
            self.window_id.id,
            protocols_atom.xcb_atom,
            ffi::XCB_ATOM_ATOM,
            32,
            1,
            &delete_window_atom.xcb_atom as *const u32 as *const _
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Registering close event failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok((protocols_atom, delete_window_atom))
   }

   pub fn set_title(&self, title: &str) -> Result<(), RuntimeError> {
      let c_title = CString::new(title).unwrap();

      let cookie = unsafe {
         ffi::xcb_change_property_checked(
            self.connection.ptr,
            ffi::XCB_PROP_MODE_REPLACE,
            self.window_id.id,
            ffi::XCB_ATOM_WM_NAME,
            ffi::XCB_ATOM_STRING,
            8,
            title.len() as ffi::c_uint,
            c_title.as_ptr() as *const _
         )
      };

      match error_check(self.connection.ptr, cookie) {
         Some(error_code) => {
            return Err(RuntimeError::new(
               ErrorKind::XCB,
               format!("Setting window title failed: {}", error_code)
            ));
         },
         None => {}
      }

      Ok(())
   }
}

fn error_check(
   c: *mut ffi::xcb_connection_t,
   cookie: ffi::xcb_void_cookie_t
) -> Option<ffi::c_uchar> {

   let error = unsafe {
      ffi::xcb_request_check(c, cookie)
   };

   if error != ptr::null_mut() {
      return Some(
         unsafe {
            (*error).error_code
         }
      )
   }

   None
}

impl Drop for Window {
   fn drop (&mut self) {
      unsafe {
         ffi::xcb_destroy_window(
            self.connection.ptr, self.window_id.id
         );
      }
   }
}

pub struct Atom {
   xcb_atom: ffi::xcb_atom_t
}

pub struct InternAtomCookie {
   xcb_cookie: ffi::xcb_intern_atom_cookie_t
}

pub struct InternAtomReply {
   xcb_reply: *mut ffi::xcb_intern_atom_reply_t
}

impl InternAtomReply {
   pub fn atom(&self) -> Atom {
      let xcb_atom = unsafe { (*(self.xcb_reply)).atom };
      Atom {
         xcb_atom: xcb_atom
      }
   }
}
<|endoftext|>


<commit_before>use Configuration;
use deque;
use deque::{Worker, Stealer, Stolen};
use job::JobRef;
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use rand;
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::collections::VecDeque;
use std::mem;
use util::leak;
use num_cpus;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    terminate: bool,
    threads_at_work: usize,
    injected_jobs: VecDeque<JobRef>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened). If
/// initialization has not already occurred, use the default
/// configuration.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(Configuration::new()) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Starts the worker threads (if that has not already happened) with
/// the given configuration.
pub fn get_registry_with_config(config: Configuration) -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(config) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Initializes the global registry with the given configuration.
/// Meant to be called from within the `THE_REGISTRY_SET` once
/// function. Declared `unsafe` because it writes to `THE_REGISTRY` in
/// an unsynchronized fashion.
unsafe fn init_registry(config: Configuration) {
    let registry = leak(Registry::new(config.num_threads()));
    THE_REGISTRY = Some(registry);
}

enum Work {
    None,
    Job(JobRef),
    Terminate,
}

impl Registry {
    pub fn new(num_threads: Option<usize>) -> Arc<Registry> {
        let limit_value = match num_threads {
            Some(value) => value,
            None => num_cpus::get()
        };

        let (workers, stealers) : (Vec<_>, Vec<_>) =
            (0..limit_value).map(|_| deque::new()).unzip();

        let registry = Arc::new(Registry {
            thread_infos: stealers.into_iter().map(|s| ThreadInfo::new(s))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        });

        for (index, worker) in workers.into_iter().enumerate() {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(worker, registry, index) });
        }

        registry
    }

    pub fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[JobRef]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        if state.terminate {
            drop(state);
            // We can only reach this point if these conditions are met:
            // 1) This must be the global thread pool
            // 2) The only way to terminate the global thread pool is if a
            //    worker thread panics.
            // 3) A worker thread can only panic if a job panicked and was not
            //    caught by panic::recover.
            panic!("rayon thread pool is contaminated by a previous panic; recovery is only available on nightly compilers");
        }
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Work {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Check if we need to terminate.
            if state.terminate {
                return Work::Terminate;
            }

            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop_front() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Work::Job(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return Work::None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        let mut state = self.state.lock().unwrap();
        state.terminate = true;
        for job in state.injected_jobs.drain(..) {
            unsafe {
                (*job.0).abort();
            }
        }
        self.work_available.notify_all();
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: VecDeque::new(),
            terminate: false,
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(stealer: Stealer<JobRef>) -> ThreadInfo {
        ThreadInfo {
            primed: LockLatch::new(),
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    worker: Worker<JobRef>,
    stealers: Vec<Stealer<JobRef>>,
    index: usize
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> bool {
        self.worker.pop().is_some()
    }

    #[cold]
    pub unsafe fn steal_until(&self, latch: &SpinLatch) {
        // If another thread stole our job when we panic, we must halt unwinding
        // until that thread is finished using it.
        struct PanicGuard<'a>(&'a SpinLatch);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                while !self.0.probe() {
                    thread::yield_now();
                }
            }
        }

        let guard = PanicGuard(&latch);
        while !latch.probe() {
            if let Some(job) = steal_work(&self.stealers) {
                (*job.0).execute();
            } else {
                thread::yield_now();
            }
        }
        mem::forget(guard);
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
    let stealers = registry.thread_infos.iter()
        .enumerate().filter(|&(i, _)| i != index)
        .map(|(_, ti)| ti.stealer.clone())
        .collect();

    let worker_thread = WorkerThread {
        worker: worker,
        stealers: stealers,
        index: index,
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    // If a worker thread panics, bring down the entire thread pool
    struct PanicGuard<'a>(&'a Registry);
    impl<'a> Drop for PanicGuard<'a> {
        fn drop(&mut self) {
            self.0.terminate();
        }
    }
    let _guard = PanicGuard(&registry);

    let mut was_active = false;
    loop {
        match registry.wait_for_work(index, was_active) {
            Work::Job(injected_job) => {
                (*injected_job.0).execute();
                was_active = true;
                continue;
            }
            Work::Terminate => break,
            Work::None => {},
        }

        if let Some(stolen_job) = steal_work(&worker_thread.stealers) {
            log!(StoleWork { worker: index });
            registry.start_working(index);
            (*stolen_job.0).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}

unsafe fn steal_work(stealers: &[Stealer<JobRef>]) -> Option<JobRef> {
    if stealers.is_empty() { return None }
    let start = rand::random::<usize>() % stealers.len();
    stealers[start..].iter()
        .chain(&stealers[..start])
        .filter_map(|stealer| match stealer.steal() {
            Stolen::Empty => None,
            Stolen::Abort => None, // loop?
            Stolen::Data(v) => Some(v),
        })
        .next()
}
<commit_msg>thread_pool: move steal_work into WorkerThread<commit_after>use Configuration;
use deque;
use deque::{Worker, Stealer, Stolen};
use job::JobRef;
use latch::{Latch, LockLatch, SpinLatch};
#[allow(unused_imports)]
use log::Event::*;
use rand;
use std::cell::Cell;
use std::sync::{Arc, Condvar, Mutex, Once, ONCE_INIT};
use std::thread;
use std::collections::VecDeque;
use std::mem;
use util::leak;
use num_cpus;

///////////////////////////////////////////////////////////////////////////

pub struct Registry {
    thread_infos: Vec<ThreadInfo>,
    state: Mutex<RegistryState>,
    work_available: Condvar,
}

struct RegistryState {
    terminate: bool,
    threads_at_work: usize,
    injected_jobs: VecDeque<JobRef>,
}

///////////////////////////////////////////////////////////////////////////
// Initialization

static mut THE_REGISTRY: Option<&'static Registry> = None;
static THE_REGISTRY_SET: Once = ONCE_INIT;

/// Starts the worker threads (if that has not already happened). If
/// initialization has not already occurred, use the default
/// configuration.
pub fn get_registry() -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(Configuration::new()) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Starts the worker threads (if that has not already happened) with
/// the given configuration.
pub fn get_registry_with_config(config: Configuration) -> &'static Registry {
    THE_REGISTRY_SET.call_once(|| unsafe { init_registry(config) });
    unsafe { THE_REGISTRY.unwrap() }
}

/// Initializes the global registry with the given configuration.
/// Meant to be called from within the `THE_REGISTRY_SET` once
/// function. Declared `unsafe` because it writes to `THE_REGISTRY` in
/// an unsynchronized fashion.
unsafe fn init_registry(config: Configuration) {
    let registry = leak(Registry::new(config.num_threads()));
    THE_REGISTRY = Some(registry);
}

enum Work {
    None,
    Job(JobRef),
    Terminate,
}

impl Registry {
    pub fn new(num_threads: Option<usize>) -> Arc<Registry> {
        let limit_value = match num_threads {
            Some(value) => value,
            None => num_cpus::get()
        };

        let (workers, stealers) : (Vec<_>, Vec<_>) =
            (0..limit_value).map(|_| deque::new()).unzip();

        let registry = Arc::new(Registry {
            thread_infos: stealers.into_iter().map(|s| ThreadInfo::new(s))
                                          .collect(),
            state: Mutex::new(RegistryState::new()),
            work_available: Condvar::new(),
        });

        for (index, worker) in workers.into_iter().enumerate() {
            let registry = registry.clone();
            thread::spawn(move || unsafe { main_loop(worker, registry, index) });
        }

        registry
    }

    pub fn num_threads(&self) -> usize {
        self.thread_infos.len()
    }

    /// Waits for the worker threads to get up and running.  This is
    /// meant to be used for benchmarking purposes, primarily, so that
    /// you can get more consistent numbers by having everything
    /// "ready to go".
    pub fn wait_until_primed(&self) {
        for info in &self.thread_infos {
            info.primed.wait();
        }
    }

    ///////////////////////////////////////////////////////////////////////////
    // MAIN LOOP
    //
    // So long as all of the worker threads are hanging out in their
    // top-level loop, there is no work to be done.

    fn start_working(&self, index: usize) {
        log!(StartWorking { index: index });
        let mut state = self.state.lock().unwrap();
        state.threads_at_work += 1;
        self.work_available.notify_all();
    }

    pub unsafe fn inject(&self, injected_jobs: &[JobRef]) {
        log!(InjectJobs { count: injected_jobs.len() });
        let mut state = self.state.lock().unwrap();
        if state.terminate {
            drop(state);
            // We can only reach this point if these conditions are met:
            // 1) This must be the global thread pool
            // 2) The only way to terminate the global thread pool is if a
            //    worker thread panics.
            // 3) A worker thread can only panic if a job panicked and was not
            //    caught by panic::recover.
            panic!("rayon thread pool is contaminated by a previous panic; recovery is only available on nightly compilers");
        }
        state.injected_jobs.extend(injected_jobs);
        self.work_available.notify_all();
    }

    fn wait_for_work(&self, _worker: usize, was_active: bool) -> Work {
        log!(WaitForWork { worker: _worker, was_active: was_active });

        let mut state = self.state.lock().unwrap();

        if was_active {
            state.threads_at_work -= 1;
        }

        loop {
            // Check if we need to terminate.
            if state.terminate {
                return Work::Terminate;
            }

            // Otherwise, if anything was injected from outside,
            // return that.  Note that this gives preference to
            // injected items over stealing from others, which is a
            // bit dubious, but then so is the opposite.
            if let Some(job) = state.injected_jobs.pop_front() {
                state.threads_at_work += 1;
                self.work_available.notify_all();
                return Work::Job(job);
            }

            // If any of the threads are running a job, we should spin
            // up, since they may generate subworkitems.
            if state.threads_at_work > 0 {
                return Work::None;
            }

            state = self.work_available.wait(state).unwrap();
        }
    }

    pub fn terminate(&self) {
        let mut state = self.state.lock().unwrap();
        state.terminate = true;
        for job in state.injected_jobs.drain(..) {
            unsafe {
                (*job.0).abort();
            }
        }
        self.work_available.notify_all();
    }
}

impl RegistryState {
    pub fn new() -> RegistryState {
        RegistryState {
            threads_at_work: 0,
            injected_jobs: VecDeque::new(),
            terminate: false,
        }
    }
}

struct ThreadInfo {
    // latch is set once thread has started and we are entering into
    // the main loop
    primed: LockLatch,
    stealer: Stealer<JobRef>,
}

impl ThreadInfo {
    fn new(stealer: Stealer<JobRef>) -> ThreadInfo {
        ThreadInfo {
            primed: LockLatch::new(),
            stealer: stealer,
        }
    }
}

///////////////////////////////////////////////////////////////////////////
// WorkerThread identifiers

pub struct WorkerThread {
    worker: Worker<JobRef>,
    stealers: Vec<Stealer<JobRef>>,
    index: usize
}

// This is a bit sketchy, but basically: the WorkerThread is
// allocated on the stack of the worker on entry and stored into this
// thread local variable. So it will remain valid at least until the
// worker is fully unwound. Using an unsafe pointer avoids the need
// for a RefCell<T> etc.
thread_local! {
    static WORKER_THREAD_STATE: Cell<*const WorkerThread> =
        Cell::new(0 as *const WorkerThread)
}

impl WorkerThread {
    /// Gets the `WorkerThread` index for the current thread; returns
    /// NULL if this is not a worker thread. This pointer is valid
    /// anywhere on the current thread.
    #[inline]
    pub unsafe fn current() -> *const WorkerThread {
        WORKER_THREAD_STATE.with(|t| t.get())
    }

    /// Sets `self` as the worker thread index for the current thread.
    /// This is done during worker thread startup.
    unsafe fn set_current(&self) {
        WORKER_THREAD_STATE.with(|t| {
            assert!(t.get().is_null());
            t.set(self);
        });
    }

    #[inline]
    pub fn index(&self) -> usize {
        self.index
    }

    #[inline]
    pub unsafe fn push(&self, job: JobRef) {
        self.worker.push(job);
    }

    /// Pop `job` from top of stack, returning `false` if it has been
    /// stolen.
    #[inline]
    pub unsafe fn pop(&self) -> bool {
        self.worker.pop().is_some()
    }

    #[cold]
    pub unsafe fn steal_until(&self, latch: &SpinLatch) {
        // If another thread stole our job when we panic, we must halt unwinding
        // until that thread is finished using it.
        struct PanicGuard<'a>(&'a SpinLatch);
        impl<'a> Drop for PanicGuard<'a> {
            fn drop(&mut self) {
                while !self.0.probe() {
                    thread::yield_now();
                }
            }
        }

        let guard = PanicGuard(&latch);
        while !latch.probe() {
            if let Some(job) = self.steal_work() {
                (*job.0).execute();
            } else {
                thread::yield_now();
            }
        }
        mem::forget(guard);
    }

    unsafe fn steal_work(&self) -> Option<JobRef> {
        if self.stealers.is_empty() { return None }
        let start = rand::random::<usize>() % self.stealers.len();
        let (lo, hi) = self.stealers.split_at(start);
        hi.iter().chain(lo)
            .filter_map(|stealer| match stealer.steal() {
                Stolen::Empty => None,
                Stolen::Abort => None, // loop?
                Stolen::Data(v) => Some(v),
            })
            .next()
    }
}

///////////////////////////////////////////////////////////////////////////

unsafe fn main_loop(worker: Worker<JobRef>, registry: Arc<Registry>, index: usize) {
    let stealers = registry.thread_infos.iter()
        .enumerate().filter(|&(i, _)| i != index)
        .map(|(_, ti)| ti.stealer.clone())
        .collect();

    let worker_thread = WorkerThread {
        worker: worker,
        stealers: stealers,
        index: index,
    };
    worker_thread.set_current();

    // let registry know we are ready to do work
    registry.thread_infos[index].primed.set();

    // If a worker thread panics, bring down the entire thread pool
    struct PanicGuard<'a>(&'a Registry);
    impl<'a> Drop for PanicGuard<'a> {
        fn drop(&mut self) {
            self.0.terminate();
        }
    }
    let _guard = PanicGuard(&registry);

    let mut was_active = false;
    loop {
        match registry.wait_for_work(index, was_active) {
            Work::Job(injected_job) => {
                (*injected_job.0).execute();
                was_active = true;
                continue;
            }
            Work::Terminate => break,
            Work::None => {},
        }

        if let Some(stolen_job) = worker_thread.steal_work() {
            log!(StoleWork { worker: index });
            registry.start_working(index);
            (*stolen_job.0).execute();
            was_active = true;
        } else {
            was_active = false;
        }
    }
}
<|endoftext|>


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

//! The dirichlet distribution.

use Rng;
use distributions::Distribution;
use distributions::gamma::Gamma;

/// The dirichelet distribution `Dirichlet(alpha)`.
///
/// The Dirichlet distribution } is a family of continuous multivariate probability distributions parameterized by
/// a vector alpha of positive reals. https://en.wikipedia.org/wiki/Dirichlet_distribution
/// It is a multivariate generalization of the beta distribution.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::Dirichlet;
///
/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]);
/// let samples = dirichlet.sample(&mut rand::thread_rng());
/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
/// ```

#[derive(Clone, Debug)]
pub struct Dirichlet {
    /// Concentration parameters (alpha)
    alpha: Vec<f64>,
}

impl Dirichlet {
    /// Construct a new `Dirichlet` with the given alpha parameter
    /// `alpha`. Panics if `alpha.len() < 2`.
    #[inline]
    pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
        let a = alpha.into();
        assert!(a.len() > 1);
        for i in 0..a.len() {
            assert!(a[i] > 0.0);
        }

        Dirichlet { alpha: a.into() }
    }

    /// Construct a new `Dirichlet` with the given shape parameter and size
    /// `alpha`. Panics if `alpha <= 0.0`.
    /// `size` . Panic if `size < 2`
    #[inline]
    pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
        assert!(alpha > 0.0);
        assert!(size > 1);
        Dirichlet {
            alpha: vec![alpha; size],
        }
    }
}

impl Distribution<Vec<f64>> for Dirichlet {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
        let n = self.alpha.len();
        let mut samples = vec![0.0f64; n];
        let mut sum = 0.0f64;

        for i in 0..n {
            let g = Gamma::new(self.alpha[i], 1.0);
            samples[i] = g.sample(rng);
            sum += samples[i];
        }
        let invacc = 1.0 / sum;
        for i in 0..n {
            samples[i] *= invacc;
        }
        samples
    }
}

#[cfg(test)]
mod test {
    use super::Dirichlet;
    use distributions::Distribution;

    #[test]
    fn test_dirichlet() {
        let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
        let mut rng = ::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    fn test_dirichlet_with_param() {
        let alpha = 0.5f64;
        let size = 2;
        let d = Dirichlet::new_with_param(alpha, size);
        let mut rng = ::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_length() {
        Dirichlet::new_with_param(0.5f64, 1);
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_alpha() {
        Dirichlet::new_with_param(0.0f64, 2);
    }
}
<commit_msg>removed stray }<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The dirichlet distribution.

use Rng;
use distributions::Distribution;
use distributions::gamma::Gamma;

/// The dirichelet distribution `Dirichlet(alpha)`.
///
/// The Dirichlet distribution is a family of continuous multivariate probability distributions parameterized by
/// a vector alpha of positive reals. https://en.wikipedia.org/wiki/Dirichlet_distribution
/// It is a multivariate generalization of the beta distribution.
///
/// # Example
///
/// ```
/// use rand::prelude::*;
/// use rand::distributions::Dirichlet;
///
/// let dirichlet = Dirichlet::new(vec![1.0, 2.0, 3.0]);
/// let samples = dirichlet.sample(&mut rand::thread_rng());
/// println!("{:?} is from a Dirichlet([1.0, 2.0, 3.0]) distribution", samples);
/// ```

#[derive(Clone, Debug)]
pub struct Dirichlet {
    /// Concentration parameters (alpha)
    alpha: Vec<f64>,
}

impl Dirichlet {
    /// Construct a new `Dirichlet` with the given alpha parameter
    /// `alpha`. Panics if `alpha.len() < 2`.
    #[inline]
    pub fn new<V: Into<Vec<f64>>>(alpha: V) -> Dirichlet {
        let a = alpha.into();
        assert!(a.len() > 1);
        for i in 0..a.len() {
            assert!(a[i] > 0.0);
        }

        Dirichlet { alpha: a.into() }
    }

    /// Construct a new `Dirichlet` with the given shape parameter and size
    /// `alpha`. Panics if `alpha <= 0.0`.
    /// `size` . Panic if `size < 2`
    #[inline]
    pub fn new_with_param(alpha: f64, size: usize) -> Dirichlet {
        assert!(alpha > 0.0);
        assert!(size > 1);
        Dirichlet {
            alpha: vec![alpha; size],
        }
    }
}

impl Distribution<Vec<f64>> for Dirichlet {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Vec<f64> {
        let n = self.alpha.len();
        let mut samples = vec![0.0f64; n];
        let mut sum = 0.0f64;

        for i in 0..n {
            let g = Gamma::new(self.alpha[i], 1.0);
            samples[i] = g.sample(rng);
            sum += samples[i];
        }
        let invacc = 1.0 / sum;
        for i in 0..n {
            samples[i] *= invacc;
        }
        samples
    }
}

#[cfg(test)]
mod test {
    use super::Dirichlet;
    use distributions::Distribution;

    #[test]
    fn test_dirichlet() {
        let d = Dirichlet::new(vec![1.0, 2.0, 3.0]);
        let mut rng = ::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    fn test_dirichlet_with_param() {
        let alpha = 0.5f64;
        let size = 2;
        let d = Dirichlet::new_with_param(alpha, size);
        let mut rng = ::test::rng(221);
        let samples = d.sample(&mut rng);
        let _: Vec<f64> = samples
            .into_iter()
            .map(|x| {
                assert!(x > 0.0);
                x
            })
            .collect();
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_length() {
        Dirichlet::new_with_param(0.5f64, 1);
    }

    #[test]
    #[should_panic]
    fn test_dirichlet_invalid_alpha() {
        Dirichlet::new_with_param(0.0f64, 2);
    }
}
<|endoftext|>


<commit_before>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) unsafe fn new(type_: LLVMTypeRef) -> Self {
        match LLVMGetTypeKind(type_) {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        unsafe {
            BasicTypeEnum::new(self.as_type_ref())
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the ArrayType variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FloatType variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FunctionType variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the IntType variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the PointerType variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the StructType variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VectorType variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VoidType variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        matches!(self, AnyTypeEnum::ArrayType(_))
    }

    pub fn is_float_type(self) -> bool {
        matches!(self, AnyTypeEnum::FloatType(_))
    }

    pub fn is_function_type(self) -> bool {
        matches!(self, AnyTypeEnum::FunctionType(_))
    }

    pub fn is_int_type(self) -> bool {
        matches!(self, AnyTypeEnum::IntType(_))
    }

    pub fn is_pointer_type(self) -> bool {
        matches!(self, AnyTypeEnum::PointerType(_))
    }

    pub fn is_struct_type(self) -> bool {
        matches!(self, AnyTypeEnum::StructType(_))
    }

    pub fn is_vector_type(self) -> bool {
        matches!(self, AnyTypeEnum::VectorType(_))
    }

    pub fn is_void_type(self) -> bool {
        matches!(self, AnyTypeEnum::VoidType(_))
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) unsafe fn new(type_: LLVMTypeRef) -> Self {
        match LLVMGetTypeKind(type_) {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the ArrayType variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FloatType variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the IntType variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the PointerType variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the StructType variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VectorType variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        matches!(self, BasicTypeEnum::ArrayType(_))
    }

    pub fn is_float_type(self) -> bool {
        matches!(self, BasicTypeEnum::FloatType(_))
    }

    pub fn is_int_type(self) -> bool {
        matches!(self, BasicTypeEnum::IntType(_))
    }

    pub fn is_pointer_type(self) -> bool {
        matches!(self, BasicTypeEnum::PointerType(_))
    }

    pub fn is_struct_type(self) -> bool {
        matches!(self, BasicTypeEnum::StructType(_))
    }

    pub fn is_vector_type(self) -> bool {
        matches!(self, BasicTypeEnum::VectorType(_))
    }

    /// Creates a constant `BasicValueZero`.
    ///
    /// # Example
    /// ```
    /// use inkwell::context::Context;
    /// use crate::inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type().as_basic_type_enum();
    /// let f32_zero = f32_type.const_zero();
    /// ```
    pub fn const_zero(self) -> BasicValueEnum<'ctx> {
        match self {
            BasicTypeEnum::ArrayType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::FloatType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::IntType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::PointerType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::StructType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::VectorType(ty) => ty.const_zero().as_basic_value_enum(),
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<commit_msg>match on LLVMX86_AMXTypeKind; not supported, panics immediately<commit_after>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) unsafe fn new(type_: LLVMTypeRef) -> Self {
        match LLVMGetTypeKind(type_) {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(feature = "llvm12-0")]
            LLVMTypeKind::LLVMX86_AMXTypeKind => panic!("FIXME: Unsupported type: AMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        unsafe {
            BasicTypeEnum::new(self.as_type_ref())
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the ArrayType variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FloatType variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FunctionType variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the IntType variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the PointerType variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the StructType variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VectorType variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VoidType variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        matches!(self, AnyTypeEnum::ArrayType(_))
    }

    pub fn is_float_type(self) -> bool {
        matches!(self, AnyTypeEnum::FloatType(_))
    }

    pub fn is_function_type(self) -> bool {
        matches!(self, AnyTypeEnum::FunctionType(_))
    }

    pub fn is_int_type(self) -> bool {
        matches!(self, AnyTypeEnum::IntType(_))
    }

    pub fn is_pointer_type(self) -> bool {
        matches!(self, AnyTypeEnum::PointerType(_))
    }

    pub fn is_struct_type(self) -> bool {
        matches!(self, AnyTypeEnum::StructType(_))
    }

    pub fn is_vector_type(self) -> bool {
        matches!(self, AnyTypeEnum::VectorType(_))
    }

    pub fn is_void_type(self) -> bool {
        matches!(self, AnyTypeEnum::VoidType(_))
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) unsafe fn new(type_: LLVMTypeRef) -> Self {
        match LLVMGetTypeKind(type_) {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(any(feature = "llvm11-0", feature = "llvm12-0"))]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            #[cfg(feature = "llvm12-0")]
            LLVMTypeKind::LLVMX86_AMXTypeKind => unreachable!("Unsupported basic type: AMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the ArrayType variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the FloatType variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the IntType variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the PointerType variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the StructType variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected the VectorType variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        matches!(self, BasicTypeEnum::ArrayType(_))
    }

    pub fn is_float_type(self) -> bool {
        matches!(self, BasicTypeEnum::FloatType(_))
    }

    pub fn is_int_type(self) -> bool {
        matches!(self, BasicTypeEnum::IntType(_))
    }

    pub fn is_pointer_type(self) -> bool {
        matches!(self, BasicTypeEnum::PointerType(_))
    }

    pub fn is_struct_type(self) -> bool {
        matches!(self, BasicTypeEnum::StructType(_))
    }

    pub fn is_vector_type(self) -> bool {
        matches!(self, BasicTypeEnum::VectorType(_))
    }

    /// Creates a constant `BasicValueZero`.
    ///
    /// # Example
    /// ```
    /// use inkwell::context::Context;
    /// use crate::inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type().as_basic_type_enum();
    /// let f32_zero = f32_type.const_zero();
    /// ```
    pub fn const_zero(self) -> BasicValueEnum<'ctx> {
        match self {
            BasicTypeEnum::ArrayType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::FloatType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::IntType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::PointerType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::StructType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::VectorType(ty) => ty.const_zero().as_basic_value_enum(),
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<|endoftext|>