[rust] no_std
diff --git a/src/rust/Cargo.toml b/src/rust/Cargo.toml
index c160023..d920ef5 100644
--- a/src/rust/Cargo.toml
+++ b/src/rust/Cargo.toml
@@ -4,8 +4,9 @@
 rust-version = "1.75.0"
 
 [dependencies]
-skrifa = { version = "0.*", optional = true }
-harfrust = { version = "0.1.*", optional = true }
+skrifa = { version = "0.*", optional = true, default-features = false, features = ["libm"] }
+harfrust = { version = "0.1.*", optional = true, default-features = false }
+core_maths = "0.1"
 
 [lib]
 name = "harfbuzz_rust"
diff --git a/src/rust/font.rs b/src/rust/font.rs
index 579219a..fdf5c94 100644
--- a/src/rust/font.rs
+++ b/src/rust/font.rs
@@ -1,11 +1,13 @@
 use super::hb::*;
 
-use std::collections::HashMap;
-use std::ffi::c_void;
-use std::mem::transmute;
-use std::ptr::null_mut;
-use std::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
-use std::sync::Mutex;
+extern crate alloc;
+use alloc::collections::HashMap;
+
+use core::ffi::c_void;
+use core::mem::transmute;
+use core::ptr::null_mut;
+use core::sync::atomic::{AtomicPtr, AtomicU32, Ordering};
+use core::sync::Mutex;
 
 use skrifa::charmap::Charmap;
 use skrifa::charmap::MapVariant::Variant;
@@ -58,7 +60,7 @@
         if blob_data.is_null() {
             return None;
         }
-        let face_data = std::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
+        let face_data = core::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
 
         let font_ref = FontRef::from_index(face_data, face_index);
         let font_ref = match font_ref {
@@ -126,7 +128,7 @@
         let coords = if coords.is_null() {
             &[]
         } else {
-            std::slice::from_raw_parts(coords, num_coords as usize)
+            core::slice::from_raw_parts(coords, num_coords as usize)
         };
         let all_zeros = coords.iter().all(|&x| x == 0);
         // if all zeros, use Location::default()
diff --git a/src/rust/lib.rs b/src/rust/lib.rs
index af3b2b4..4f235eb 100644
--- a/src/rust/lib.rs
+++ b/src/rust/lib.rs
@@ -1,3 +1,5 @@
+#![no_std]
+
 mod hb;
 use hb::*;
 
@@ -6,32 +8,37 @@
 #[cfg(feature = "shape")]
 mod shape;
 
-use std::alloc::{GlobalAlloc, Layout};
-use std::os::raw::c_void;
+use core::alloc::{GlobalAlloc, Layout};
+use core::ffi::c_void;
 
 struct MyAllocator;
 
 unsafe impl GlobalAlloc for MyAllocator {
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        assert!(layout.align() <= 2 * core::mem::size_of::<*mut u8>());
         hb_malloc(layout.size()) as *mut u8
     }
 
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        assert!(layout.align() <= 2 * core::mem::size_of::<*mut u8>());
         hb_calloc(layout.size(), 1) as *mut u8
     }
 
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        assert!(layout.align() <= 2 * core::mem::size_of::<*mut u8>());
         hb_realloc(ptr as *mut c_void, new_size) as *mut u8
     }
 
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        assert!(layout.align() <= 2 * std::mem::size_of::<*mut u8>());
+        assert!(layout.align() <= 2 * core::mem::size_of::<*mut u8>());
         hb_free(ptr as *mut c_void);
     }
 }
 
 #[global_allocator]
 static GLOBAL: MyAllocator = MyAllocator;
+
+#[panic_handler]
+fn panic(_: &core::panic::PanicInfo) -> ! {
+    unsafe { core::hint::unreachable_unchecked() }
+}
diff --git a/src/rust/meson.build b/src/rust/meson.build
index b086dd9..96c1db5 100644
--- a/src/rust/meson.build
+++ b/src/rust/meson.build
@@ -7,6 +7,8 @@
   args : ['--allowlist-function=hb_.*',
           '--allowlist-type=hb_.*',
           '--no-copy=hb_.*',
+          '--use-core',
+          '--ctypes-prefix=core::ffi',
           ],
 )
 
diff --git a/src/rust/shape.rs b/src/rust/shape.rs
index d7b348f..2afd5b2 100644
--- a/src/rust/shape.rs
+++ b/src/rust/shape.rs
@@ -2,10 +2,16 @@
 
 use super::hb::*;
 
-use std::ffi::c_void;
-use std::mem::transmute;
-use std::ptr::null_mut;
-use std::str::FromStr;
+extern crate alloc;
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
+use core_maths::CoreFloat;
+
+use core::ffi::c_void;
+use core::mem::transmute;
+use core::ptr::null_mut;
+use core::str::FromStr;
 
 use harfrust::{FontRef, NormalizedCoord, Shaper, ShaperData, ShaperInstance, Tag};
 
@@ -26,7 +32,7 @@
     if blob_data.is_null() {
         return null_mut();
     }
-    let face_data = std::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
+    let face_data = core::slice::from_raw_parts(blob_data as *const u8, blob_length as usize);
 
     let font_ref = match FontRef::from_index(face_data, face_index) {
         Ok(f) => f,
@@ -62,7 +68,7 @@
     let coords = if coords.is_null() {
         &[]
     } else {
-        unsafe { std::slice::from_raw_parts(coords, num_coords as usize) }
+        unsafe { core::slice::from_raw_parts(coords, num_coords as usize) }
     };
     let coords = coords.iter().map(|&v| NormalizedCoord::from_bits(v as i16));
     ShaperInstance::from_coords(font_ref, coords)
@@ -105,7 +111,7 @@
     if language_str.is_null() {
         return None;
     }
-    let language_str = unsafe { std::ffi::CStr::from_ptr(language_str) };
+    let language_str = unsafe { core::ffi::CStr::from_ptr(language_str) };
     let language_str = language_str.to_str().unwrap_or_default();
     Some(harfrust::Language::from_str(language_str).unwrap())
 }
@@ -250,7 +256,7 @@
     let features = if features.is_null() {
         Vec::new()
     } else {
-        let features = std::slice::from_raw_parts(features, num_features as usize);
+        let features = core::slice::from_raw_parts(features, num_features as usize);
         features
             .iter()
             .map(|f| {