diff --git a/Cargo.toml b/Cargo.toml
index 5d3f1dd..2a43c7b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -18,6 +18,10 @@ exclude = [
 ]
 build = "build/main.rs"
 
+[dependencies]
+profiling = "^1"
+libc = "^0.2"
+
 [build-dependencies]
 bindgen = "^0.65.0"
 cmake = "^0.1.49"
diff --git a/build/bind.rs b/build/bind.rs
index ea41907..773ff90 100644
--- a/build/bind.rs
+++ b/build/bind.rs
@@ -77,6 +77,7 @@ pub fn generate_bindings(header_file: &str) {
     let mut builder = bindgen::Builder::default()
         .header(header_file)
         .parse_callbacks(Box::new(bindgen::CargoCallbacks))
+        .wrap_unsafe_ops(true)
         .blocklist_item("DEG2RAD")
         .blocklist_item("PI")
         .blocklist_item("RAD2DEG")
diff --git a/build/main.rs b/build/main.rs
index facf5b1..68f3fcf 100644
--- a/build/main.rs
+++ b/build/main.rs
@@ -1,4 +1,7 @@
-use crate::wrap::{raylib_api::RayLibApiDefinition, enums::wrap_exposed_enums, colors::wrap_default_colors};
+use crate::wrap::{
+    colors::wrap_default_colors, enums::wrap_exposed_enums, profiling::auto_profile_exported_fns,
+    raylib_api::RayLibApiDefinition, structs::wrap_exposed_structs,
+};
 
 mod bind;
 mod wrap;
@@ -17,9 +20,14 @@ pub fn main() {
     bind::generate_bindings("src/wrapper.h");
 
     // Load the API definitions
-    let api_defs = RayLibApiDefinition::load("third_party/raylib/parser/output/raylib_api.json").unwrap();
+    let api_defs =
+        RayLibApiDefinition::load("third_party/raylib/parser/output/raylib_api.json").unwrap();
 
     // Generate safe wrappers
     wrap_exposed_enums(api_defs.clone());
-    wrap_default_colors(api_defs);
+    wrap_default_colors(api_defs.clone());
+    wrap_exposed_structs(api_defs);
+
+    // Make everything profile-able
+    // auto_profile_exported_fns(&format!("{}/bindings.rs", std::env::var("OUT_DIR").unwrap()));
 }
diff --git a/build/wrap/mod.rs b/build/wrap/mod.rs
index d333496..c4319cd 100644
--- a/build/wrap/mod.rs
+++ b/build/wrap/mod.rs
@@ -1,3 +1,6 @@
 pub mod raylib_api;
+pub mod type_xlat;
 pub mod enums;
-pub mod colors;
\ No newline at end of file
+pub mod colors;
+pub mod structs;
+pub mod profiling;
\ No newline at end of file
diff --git a/build/wrap/profiling.rs b/build/wrap/profiling.rs
new file mode 100644
index 0000000..b402e61
--- /dev/null
+++ b/build/wrap/profiling.rs
@@ -0,0 +1,26 @@
+use std::{fs::File, io::{Read, Write}};
+
+use regex::Regex;
+
+/// Finds all `pub fn` in a file and wraps them with `#[profiling::function]`
+pub fn auto_profile_exported_fns(rust_file_path: &str) {
+    // Open the file
+    let mut file = File::open(rust_file_path).unwrap();
+    let mut contents = String::new();
+    file.read_to_string(&mut contents).unwrap();
+
+    // Find all `pub fn` and wrap them with `#[profiling::function]`
+    let exported_fn_re = Regex::new(r"\s{4}pub fn").unwrap();
+    let mut new_contents = String::new();
+    for line in contents.lines() {
+        if exported_fn_re.is_match(line) {
+            new_contents.push_str(&format!("    #[profiling::function]\n{}\n", line));
+        } else {
+            new_contents.push_str(&format!("{}\n", line));
+        }
+    }
+
+    // Re-write the file
+    let mut file = File::create(rust_file_path).unwrap();
+    file.write_all(new_contents.as_bytes()).unwrap();
+}
diff --git a/build/wrap/raylib_api.rs b/build/wrap/raylib_api.rs
index 646e1bc..bf63512 100644
--- a/build/wrap/raylib_api.rs
+++ b/build/wrap/raylib_api.rs
@@ -18,6 +18,21 @@ pub struct EnumVariant {
     pub value: u32,
 }
 
+#[derive(Debug, Clone, serde::Deserialize)]
+pub struct StructureMember {
+    pub name: String,
+    #[serde(rename = "type")]
+    pub kind: String,
+    pub description: String,
+}
+
+#[derive(Debug, Clone, serde::Deserialize)]
+pub struct Structure {
+    pub name: String,
+    pub description: String,
+    pub fields: Vec<StructureMember>,
+}
+
 #[derive(Debug, Clone, serde::Deserialize)]
 pub struct Enum {
     pub name: String,
@@ -29,6 +44,7 @@ pub struct Enum {
 pub struct RayLibApiDefinition {
     pub defines: Vec<Definition>,
     pub enums: Vec<Enum>,
+    pub structs: Vec<Structure>,
 }
 
 impl RayLibApiDefinition {
diff --git a/build/wrap/structs.rs b/build/wrap/structs.rs
new file mode 100644
index 0000000..d479510
--- /dev/null
+++ b/build/wrap/structs.rs
@@ -0,0 +1,35 @@
+use super::{raylib_api::RayLibApiDefinition, type_xlat::translate_c_type_to_rust};
+
+
+pub fn wrap_exposed_structs(api_defs: RayLibApiDefinition) {
+    // Allocate an output buffer for lines
+    let mut lines = Vec::new();
+
+    // Handle each struct
+    for st in api_defs.structs {
+        // Write a doc comment with raylib's provided struct description
+        lines.push("".to_string());
+        lines.push(format!("/// {}", st.description));
+
+        // Write the struct definition
+        lines.push(format!("#[repr(C)]"));
+        lines.push(format!("pub struct {} {{", st.name));
+
+        // Write each field
+        for field in st.fields {
+            // Write a doc comment with raylib's provided field description
+            lines.push(format!("    /// {}", field.description));
+
+            // Write the field definition
+            lines.push(format!("    pub {}: {},", field.name, translate_c_type_to_rust(&field.kind)));
+        }
+
+        // Close the struct definition
+        lines.push(format!("}}"));
+    }
+
+    // Write the output file
+    let out_dir = std::env::var("OUT_DIR").unwrap();
+    let out_path = format!("{}/structs.rs", out_dir);
+    std::fs::write(out_path, lines.join("\n")).unwrap();
+}
diff --git a/build/wrap/type_xlat.rs b/build/wrap/type_xlat.rs
new file mode 100644
index 0000000..8d6814a
--- /dev/null
+++ b/build/wrap/type_xlat.rs
@@ -0,0 +1,73 @@
+pub fn translate_c_type_to_rust(c_type: &str) -> String {
+    // match c_type {
+    //     "float" => "f32".to_string(),
+    //     "float *" => "std::ptr::null_mut()".to_string(),
+    //     "int" => "i32".to_string(),
+    //     "unsigned int" => "u32".to_string(),
+    //     "unsigned char *" => "std::ptr::null_mut()".to_string(),
+    //     "unsigned short *" => "std::ptr::null_mut()".to_string(),
+    //     "bool" => "bool".to_string(),
+    //     "void *" => "std::ptr::null_mut()".to_string(),
+    //     "Texture" => "crate::structs::Texture".to_string(),
+    //     "Rectangle" => "crate::structs::Rectangle".to_string(),
+    //     "Rectangle *" => "std::ptr::null_mut()".to_string(),
+    //     "Image" => "crate::structs::Image".to_string(),
+    //     "Texture2D" => "crate::structs::Texture2D".to_string(),
+    //     "GlyphInfo *" => "std::ptr::null_mut()".to_string(),
+    //     "Vector3" => "crate::structs::Vector3".to_string(),
+    //     "Vector2" => "crate::structs::Vector2".to_string(),
+    //     "Color" => "crate::structs::Color".to_string(),
+    //     "float[4]" => "[f32; 4]".to_string(),
+    //     "MaterialMap *" => "std::ptr::null_mut()".to_string(),
+    //     "Quaternion" => "crate::structs::Quaternion".to_string(),
+    //     "char[32]" => "[u8; 32]".to_string(),
+    //     _ => {panic!("Unknown C type: {}", c_type)}
+    // }
+
+    // Translate basic C types to their Rust equivalents
+    if let Some(ty) = match c_type {
+        "char" => Some("i8"),
+        "unsigned char" => Some("u8"),
+        "short" => Some("i16"),
+        "unsigned short" => Some("u16"),
+        "int" => Some("i32"),
+        "unsigned int" => Some("u32"),
+        "long" => Some("i64"),
+        "unsigned long" => Some("u64"),
+        "float" => Some("f32"),
+        "double" => Some("f64"),
+        "bool" => Some("bool"),
+        "char *" => Some("String"),
+        "void *" => Some("*mut libc::c_void"),
+        _ => None,
+    } {
+        return ty.to_string();
+    }
+
+    // For some reason, an internal data type is exposed.
+    if c_type == "rAudioBuffer *" || c_type == "rAudioProcessor *" {
+        return "std::ptr::null_mut()".to_string();
+    }
+
+
+    // If the type ends with a *, it's a pointer to an array of the type without the *
+    if c_type.ends_with("*") {
+        let ty = &c_type[..c_type.len() - 1].trim();
+        return format!("Vec<{}>", translate_c_type_to_rust(ty));
+    }
+
+    // If the type ends with `[N]`, it's an array of N elements of the type without the `[N]`
+    let arr_len_re = regex::Regex::new(r"\[(\d+)\]$").unwrap();
+    if let Some(caps) = arr_len_re.captures(c_type) {
+        let ty = &c_type[..c_type.len() - caps[0].len()].trim();
+        let len = &caps[1];
+        return format!("[{}; {}]", translate_c_type_to_rust(ty), len);
+    }
+
+    // Uppercase types are assumed to be structs
+    if c_type.chars().next().unwrap().is_uppercase() {
+        return format!("crate::structs::{}", c_type);
+    }
+
+    panic!("Unknown C type: {}", c_type)
+}