RAII and resources
Every raylib resource in raylib-rs is a Rust struct that cleans up on drop. The Unload* family of
C functions is never exposed in the public API — Drop implementations call them automatically
when the resource leaves scope. This eliminates the class of bug where a resource is forgotten or
freed twice.
The pattern applies uniformly: Image, Texture2D, RenderTexture2D, Font, Mesh, Shader,
Material, and Model all implement Drop. You allocate with load_* or gen_image_*; you free
by letting the value go out of scope (or by calling drop() explicitly when order matters).
API surface
Image— CPU-side pixel buffer; dropped by callingUnloadImage.Texture2D— GPU texture handle; dropped by callingUnloadTexture.RenderTexture2D— off-screen render target; dropped byUnloadRenderTexture.Font— loaded font; dropped byUnloadFont.Mesh— vertex data; owned byModel(do not drop separately).Shader— GPU shader program; dropped byUnloadShader.Material— material parameters; owned byModel.Model— 3D model including meshes and materials; dropped byUnloadModel.ModelAnimations— new in 6.0, RAII wrapper for the skeletal-animation animation set.
Example
The example below shows resource loading and explicit teardown order. image is dropped first;
font is kept alive until the end of the outer scope. Because Drop is deterministic in Rust, the
sequence is predictable and correct.
extern crate raylib;
use raylib::prelude::*;
fn main() {
let (mut rl, thread) = raylib::init()
.size(640, 480)
.title("RAII demo")
.build();
// gen_image_color returns an Image that owns its pixel buffer.
let image = Image::gen_image_color(64, 64, Color::RED);
// load_texture_from_image uploads to the GPU.
let texture = rl.load_texture_from_image(&thread, &image).unwrap();
// Explicit drop: image is freed here (UnloadImage called).
// texture remains alive.
drop(image);
// texture is freed here when it leaves scope (UnloadTexture called).
drop(texture);
// RaylibHandle (rl) is freed here, tearing down the window.
}
Gotchas
- Lifetime-bound audio resources —
Wave,Sound,Music, andAudioStreamare bound by lifetime to aRaylibAudio. They cannot outlive the audio device. See the audio chapter. - raylib-allocated buffers — functions that return raylib-managed byte slices (e.g., exported
image data) wrap them as
ManuallyDrop<Box<[T]>>and free via the matchingUnload*orMemFreecall — neverlibc::free. This stays correct under custom raylib allocators. SeeDECISIONS.mdfor the rationale. Modelowns itsMeshandMaterialarrays — do not calldrop()on aMeshorMaterialthat came from aModel. Dropping theModelhandles everything.
See also
core-concepts/handle-and-thread.md— why the handle matters for resource loading.modules/textures-and-images.md—Imagevs.Texture2Din depth.modules/audio.md— lifetime-bound audio resources.