From 66e41f190bc6c4288e8c45c88a2b8fcdfa3336f9 Mon Sep 17 00:00:00 2001 From: jabu Date: Fri, 4 Nov 2022 05:19:57 -0700 Subject: [PATCH] more docs. modules, errors cleanup. --- Cargo.lock | 2 +- Cargo.toml | 2 +- examples/bevy.rs | 11 +++-- examples/simple.rs | 2 +- src/animation_state.rs | 43 ++++++++++++++---- src/animation_state_data.rs | 5 ++- src/atlas.rs | 31 ++++++++++--- src/bone.rs | 16 +++---- src/{skeleton_controller.rs => controller.rs} | 2 + src/draw/combined.rs | 30 +++++++++++-- src/draw/mod.rs | 8 ++++ src/draw/simple.rs | 31 +++++++++++-- src/error.rs | 45 ++++++++++++------- src/event.rs | 5 ++- src/extension.rs | 2 +- src/lib.rs | 15 +++---- src/skeleton.rs | 34 +++++++++++--- src/skeleton_binary.rs | 30 ++++++++++--- src/skeleton_json.rs | 28 +++++++++--- src/skin.rs | 26 ++++++++++- src/slot.rs | 4 +- 21 files changed, 283 insertions(+), 89 deletions(-) rename src/{skeleton_controller.rs => controller.rs} (98%) diff --git a/Cargo.lock b/Cargo.lock index 99ffa3c..4cfa92f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2809,7 +2809,7 @@ dependencies = [ [[package]] name = "rusty_spine" -version = "0.4.0" +version = "0.5.0-dev" dependencies = [ "bevy", "bevy_egui", diff --git a/Cargo.toml b/Cargo.toml index 8d31d54..088a262 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rusty_spine" -version = "0.4.0" +version = "0.5.0-dev" edition = "2021" description = "Spine runtime for Rust (and wasm!) transpiled from the official C Runtime." homepage = "https://github.com/jabuwu/rusty_spine" diff --git a/examples/bevy.rs b/examples/bevy.rs index ecab93a..81907e9 100644 --- a/examples/bevy.rs +++ b/examples/bevy.rs @@ -13,8 +13,9 @@ use bevy::{ sprite::Mesh2dHandle, }; use rusty_spine::{ - draw::CullDirection, AnimationStateData, Atlas, Error, SkeletonController, - SkeletonControllerSettings, SkeletonJson, + controller::{SkeletonController, SkeletonControllerSettings}, + draw::CullDirection, + AnimationStateData, Atlas, SkeletonJson, SpineError, }; #[cfg(feature = "egui_debugger")] @@ -387,7 +388,11 @@ fn spine_update( } } -fn load_skeleton(atlas: &Vec, json: &Vec, dir: &str) -> Result { +fn load_skeleton( + atlas: &Vec, + json: &Vec, + dir: &str, +) -> Result { let atlas = Arc::new(Atlas::new(atlas, dir)?); let skeleton_json = SkeletonJson::new(atlas.clone()); let skeleton_data = Arc::new(skeleton_json.read_skeleton_data(json)?); diff --git a/examples/simple.rs b/examples/simple.rs index 772c5e0..babc278 100644 --- a/examples/simple.rs +++ b/examples/simple.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use rusty_spine::*; +use rusty_spine::{controller::*, *}; fn main() { let atlas_path = "assets/spineboy/export/spineboy.atlas"; diff --git a/src/animation_state.rs b/src/animation_state.rs index 9ce165a..0201731 100644 --- a/src/animation_state.rs +++ b/src/animation_state.rs @@ -15,7 +15,7 @@ use crate::{ spTrackEntry, spTrackEntry_getAnimationTime, spTrackEntry_getTrackComplete, }, c_interface::{CTmpMut, CTmpRef, NewFromPtr, SyncPtr}, - error::Error, + error::SpineError, event::Event, skeleton::Skeleton, }; @@ -65,18 +65,23 @@ impl AnimationState { unsafe { spAnimationState_apply(self.c_animation_state.0, skeleton.c_ptr()) != 0 } } + /// Clears all animations in all track entries in this animation state. pub fn clear_tracks(&mut self) { unsafe { spAnimationState_clearTracks(self.c_ptr()); } } + /// Clears animations for the given track entry index in this animation state. pub fn clear_track(&mut self, track_index: i32) { unsafe { spAnimationState_clearTrack(self.c_ptr(), track_index); } } + /// Sets the animation for the given track by name, clearing any queued tracks, and returning + /// the track index. If the track index doesn't exist then it will be created. + /// /// # Safety /// /// This function should only be called with valid animation names. It is faster than the safe @@ -100,12 +105,18 @@ impl AnimationState { ) } + /// Sets the animation for the given track by name, clearing any queued tracks, and returning + /// the track index. If the track index doesn't exist then it will be created. + /// + /// # Errors + /// + /// Returns [`SpineError::NotFound`] if an animation doesn't exist with the given name. pub fn set_animation_by_name( &mut self, track_index: i32, animation_name: &str, looping: bool, - ) -> Result, Error> { + ) -> Result, SpineError> { if self .data() .skeleton_data() @@ -116,10 +127,12 @@ impl AnimationState { self.set_animation_by_name_unchecked(track_index, animation_name, looping) }) } else { - Err(Error::NotFound) + Err(SpineError::new_not_found("Animation", animation_name)) } } + /// Sets the animation for the given track, clearning any queued tracks, and returning the + /// track index. If the track index doesn't exist then it will be created. pub fn set_animation( &mut self, track_index: i32, @@ -139,6 +152,9 @@ impl AnimationState { } } + /// Queues the animation in the given track by name, returning the track index. If the track + /// index doesn't exist then it will be created. + /// /// # Safety /// /// This function should only be called with valid animation names. It is faster than the safe @@ -164,13 +180,19 @@ impl AnimationState { ) } + /// Queues the animation in the given track by name, returning the track index. If the track + /// index doesn't exist then it will be created. + /// + /// # Errors + /// + /// Returns [`SpineError::NotFound`] if an animation doesn't exist with the given name. pub fn add_animation_by_name( &mut self, track_index: i32, animation_name: &str, looping: bool, delay: f32, - ) -> Result, Error> { + ) -> Result, SpineError> { if self .data() .skeleton_data() @@ -181,10 +203,12 @@ impl AnimationState { self.add_animation_by_name_unchecked(track_index, animation_name, looping, delay) }) } else { - Err(Error::NotFound) + Err(SpineError::new_not_found("Animation", animation_name)) } } + /// Queues the animation in the given track, returning the track index. If the track index + /// doesn't exist then it will be created. pub fn add_animation( &mut self, track_index: i32, @@ -259,6 +283,8 @@ impl AnimationState { } } + /// Set the event listener on this animation state. An animation state can only have one event + /// listener at a time. See the documentation for [`Event`] for more information. pub fn set_listener(&mut self, listener: F) where F: Fn(&AnimationState, EventType, &TrackEntry, Option<&Event>) + 'static, @@ -464,12 +490,11 @@ impl TrackEntry { } c_handle_indexed_decl!( - /// A storeable reference to a [TrackEntry](struct.TrackEntry.html). + /// A storeable reference to a [`TrackEntry`]. /// /// Can be acquired from a - /// [CTmpRef](c_interface/struct.CTmpRef.html) or - /// [CTmpMut](c_interface/struct.CTmpMut.html) acquired from an - /// [AnimationState](struct.AnimationState.html) instance. + /// [`CTmpRef`] or [`CTmpMut`] acquired + /// from an [`AnimationState`] instance. /// /// ``` /// # #[path="./doctests.rs"] diff --git a/src/animation_state_data.rs b/src/animation_state_data.rs index 11f3b44..0158fd3 100644 --- a/src/animation_state_data.rs +++ b/src/animation_state_data.rs @@ -11,7 +11,10 @@ use crate::{ skeleton_data::SkeletonData, }; -/// Animation settings used to instantiate [AnimationState](struct.AnimationState.html). +#[allow(unused_imports)] +use crate::AnimationState; + +/// Animation settings used to instantiate [`AnimationState`]. /// /// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#AnimationStateData) /// diff --git a/src/atlas.rs b/src/atlas.rs index b179b84..815316c 100644 --- a/src/atlas.rs +++ b/src/atlas.rs @@ -9,7 +9,7 @@ use crate::c_interface::{CTmpMut, CTmpRef, NewFromPtr, SyncPtr}; use crate::texture_region::TextureRegion; use crate::{ c::{c_int, spAtlas, spAtlasPage, spAtlas_create, spAtlas_dispose}, - error::Error, + error::SpineError, }; use atlas::*; @@ -37,6 +37,7 @@ impl NewFromPtr for Atlas { impl Atlas { /// Create an Atlas from an in-memory vector. + /// /// ``` /// use rusty_spine::Atlas; /// fn load_atlas() -> Atlas { @@ -44,7 +45,13 @@ impl Atlas { /// Atlas::new(&atlas_file, "").unwrap() /// } /// ``` - pub fn new>(data: &[u8], dir: P) -> Result { + /// + /// # Errors + /// + /// Returns the [`SpineError::NulError`] if `dir` or `data` contain an internal 0 byte. This + /// function does not error if the atlas file is invalid or malformed. The file is parsed + /// line-by-line and invalid lines are simply ignored. + pub fn new>(data: &[u8], dir: P) -> Result { let c_data = CString::new(data)?; let c_dir = CString::new(dir.as_ref().to_str().unwrap())?; let c_atlas = unsafe { @@ -64,11 +71,17 @@ impl Atlas { /// Create an Atlas from a file. /// ``` /// use rusty_spine::Atlas; - /// fn load_atlas() -> Result{ + /// fn load_atlas() -> Result{ /// Ok(Atlas::new_from_file("skeleton.json")?) /// } /// ``` - pub fn new_from_file>(path: P) -> Result { + /// + /// # Errors + /// + /// Returns [`SpineError::FailedToReadFile`] if the file could not be read, returns + /// [`SpineError::NulError`] if `path` contains an internal 0 byte or if the loaded atlas + /// contains a 0 byte. + pub fn new_from_file>(path: P) -> Result { let c_path = CString::new(path.as_ref().to_str().unwrap())?; let c_atlas = unsafe { spAtlas_createFromFile(c_path.as_ptr(), null_mut()) }; if !c_atlas.is_null() { @@ -77,9 +90,9 @@ impl Atlas { owns_memory: true, }) } else { - Err(Error::FailedToReadFile( - path.as_ref().to_str().unwrap().to_owned(), - )) + Err(SpineError::FailedToReadFile { + file: path.as_ref().to_str().unwrap().to_owned(), + }) } } @@ -142,6 +155,10 @@ impl Drop for Atlas { } pub mod atlas { + //! Types related to atlases. + //! + //! To load an atlas file, see [`Atlas`]. + use super::*; #[derive(Debug)] diff --git a/src/bone.rs b/src/bone.rs index 5a59de9..a3079a5 100644 --- a/src/bone.rs +++ b/src/bone.rs @@ -14,18 +14,16 @@ use crate::{ #[cfg(feature = "mint")] use mint::Vector2; -/// A bone within the [Skeleton](struct.Skeleton.html) hierarchy. +/// A bone within the [`Skeleton`] hierarchy. /// /// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#Bone) /// -/// Bones can be acquired from a [Skeleton](struct.Skeleton.html) and a safe -/// [BoneHandle](struct.BoneHandle.html) can be obtained using the -/// [handle](struct.Bone.html#method.handle) method to store long-term references to a specific +/// Bones can be acquired from a [`Skeleton`] and a safe [`BoneHandle`] can be obtained using the +/// [`Bone::handle`] method to store long-term references to a specific /// bone. /// -/// The hierarchy can be traversed using [parent](struct.Bone.html#method.parent) and -/// [children](struct.Bone.html#method.children), and specific bones can be located using -/// [Skeleton::find_bone](struct.Skeleton.html#method.find_bone). +/// The hierarchy can be traversed using [`Bone::parent`] and [`Bone::children`], and specific +/// bones can be located using [`Skeleton::find_bone`]. #[derive(Debug)] pub struct Bone { c_bone: SyncPtr, @@ -352,9 +350,9 @@ impl Bone { } c_handle_decl!( - /// A storeable reference to a [Bone](struct.Bone.html). + /// A storeable reference to a [`Bone`]. /// - /// Can be acquired from any instance of [Bone](struct.Bone.html). + /// Can be acquired from any instance of [`Bone`]. /// /// ``` /// # #[path="./doctests.rs"] diff --git a/src/skeleton_controller.rs b/src/controller.rs similarity index 98% rename from src/skeleton_controller.rs rename to src/controller.rs index fa892d3..11f6294 100644 --- a/src/skeleton_controller.rs +++ b/src/controller.rs @@ -1,3 +1,5 @@ +//! Provides [`SkeletonController`], a helper struct for updating and drawing Spine skeletons. + use std::{mem::take, sync::Arc}; use crate::{ diff --git a/src/draw/combined.rs b/src/draw/combined.rs index 9a862c7..b1d2ef7 100644 --- a/src/draw/combined.rs +++ b/src/draw/combined.rs @@ -5,26 +5,50 @@ use crate::{ use super::{ColorSpace, CullDirection}; +#[allow(unused_imports)] +use crate::{draw::SimpleDrawer, extension}; + +/// Renderables generated from [`CombinedDrawer::draw`]. pub struct CombinedRenderable { + /// A list of vertex attributes for a mesh. pub vertices: Vec<[f32; 2]>, + /// A list of UV attributes for a mesh. pub uvs: Vec<[f32; 2]>, + /// A list of color attributes for a mesh. pub colors: Vec<[f32; 4]>, + /// A list of dark color attributes for a mesh. + /// See the [Spine User Guide](http://en.esotericsoftware.com/spine-slots#Tint-black). pub dark_colors: Vec<[f32; 4]>, + /// A list of indices for a mesh. pub indices: Vec, + /// The blend mode to use when drawing this mesh. pub blend_mode: BlendMode, + /// The attachment's renderer object as a raw pointer. Usually represents the texture created + /// from [`extension::set_create_texture_cb`]. pub attachment_renderer_object: Option<*const c_void>, } +/// A combined drawer with a mesh combining optimization. +/// +/// Assumes use of the default atlas attachment loader. +/// +/// See [`CombinedDrawer::draw`] pub struct CombinedDrawer { pub cull_direction: CullDirection, pub premultiplied_alpha: bool, pub color_space: ColorSpace, } -/// A combined drawer with a mesh combining optimization. -/// -/// Assumes use of the default atlas attachment loader. impl CombinedDrawer { + /// This function returns a list of [`CombinedRenderable`] structs containing all the necessary + /// data to create and render meshes. Attachments are batched together into a single renderable + /// so long as their blend mode or renderer object is not different from the previous + /// attachment. If a [`SkeletonClipping`] is provided, meshes will be properly clipped. The + /// renderables are expected to be rendered in the order provided with the first renderable + /// being drawn behind all the others. + /// + /// This drawer can provide a significant performance advantage over the [`SimpleDrawer`] in + /// most cases. pub fn draw( &self, skeleton: &mut Skeleton, diff --git a/src/draw/mod.rs b/src/draw/mod.rs index 308feaa..4b8125a 100644 --- a/src/draw/mod.rs +++ b/src/draw/mod.rs @@ -1,3 +1,11 @@ +//! Helpers types for drawing Spine skeletons. +//! +//! Drawers generate mesh information ready to be used in graphics libraries and game engines. +//! +//! Two implementations are currently provided: +//! - [`SimpleDrawer`] +//! - [`CombinedDrawer`] + mod combined; mod simple; diff --git a/src/draw/simple.rs b/src/draw/simple.rs index 464d180..ef374ea 100644 --- a/src/draw/simple.rs +++ b/src/draw/simple.rs @@ -5,27 +5,52 @@ use crate::{ use super::{ColorSpace, CullDirection}; +#[allow(unused_imports)] +use crate::extension; + +/// Renderables generated from [`SimpleDrawer::draw`]. +#[derive(Clone)] pub struct SimpleRenderable { + /// The index of the slot in [`Skeleton`] that this renderable represents. pub slot_index: i32, + /// A list of vertex attributes for a mesh. pub vertices: Vec<[f32; 2]>, + /// A list of UV attributes for a mesh. pub uvs: Vec<[f32; 2]>, + /// A list of indices for a mesh. pub indices: Vec, + /// The color tint of the mesh. pub color: Color, + /// The dark color tint of the mesh. + /// See the [Spine User Guide](http://en.esotericsoftware.com/spine-slots#Tint-black). pub dark_color: Color, + /// The blend mode to use when drawing this mesh. pub blend_mode: BlendMode, + /// The attachment's renderer object as a raw pointer. Usually represents the texture created + /// from [`extension::set_create_texture_cb`]. pub attachment_renderer_object: Option<*const c_void>, } +/// A simple drawer with no optimizations. +/// +/// Assumes use of the default atlas attachment loader. +/// +/// See [`SimpleDrawer::draw`] pub struct SimpleDrawer { + /// The cull direction to use for the vertices. pub cull_direction: CullDirection, + /// Set to `true` if the textures are expected to have premultiplied alpha. pub premultiplied_alpha: bool, + /// The color space to use for the colors returned in [`SimpleRenderable`]. pub color_space: ColorSpace, } -/// A simple drawer with no optimizations. -/// -/// Assumes use of the default atlas attachment loader. impl SimpleDrawer { + /// This function returns a list of [`SimpleRenderable`] structs containing all the necessary + /// data to create and render meshes. One renderable is created for each visible attachment on + /// the skeleton. If a [`SkeletonClipping`] is provided, meshes will be properly clipped. The + /// renderables are expected to be rendered in the order provided with the first renderable + /// being drawn behind all the others. pub fn draw( &self, skeleton: &mut Skeleton, diff --git a/src/error.rs b/src/error.rs index 8aafdbe..2c0d8ca 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,42 +1,55 @@ use std::{error, ffi::NulError, fmt}; #[derive(Debug)] -pub enum Error { - Spine(String), +pub enum SpineError { + /// A parsing error straight from the Spine C runtime. + ParsingFailed { reason: String }, + /// A wrapper for [`std::ffi::NulError`]. NulError(NulError), - NotFound, - FailedToReadFile(String), + /// An error when something couldn't be found, represented by `what` it was and its `name`. + NotFound { what: String, name: String }, + /// An error when failing to read files. + FailedToReadFile { file: String }, } -impl Error { - pub fn new_from_spine(message: &str) -> Self { - Self::Spine(String::from(message)) +impl SpineError { + pub(crate) fn new_from_spine(reason: &str) -> Self { + Self::ParsingFailed { + reason: reason.to_owned(), + } + } + + pub(crate) fn new_not_found(what: &str, name: &str) -> Self { + Self::NotFound { + what: what.to_owned(), + name: name.to_owned(), + } } } -impl From for Error { +impl From for SpineError { fn from(err: NulError) -> Self { Self::NulError(err) } } -impl fmt::Display for Error { +impl fmt::Display for SpineError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Error::Spine(str) => { - write!(f, "Spine error: {}", str)?; + SpineError::ParsingFailed { reason } => { + write!(f, "Spine parsing failed: {}", reason)?; Ok(()) } - Error::NulError(error) => { + SpineError::NulError(error) => { write!(f, "Nul error: {}", error)?; Ok(()) } - Error::NotFound => { + SpineError::NotFound { what, name } => { // TODO: make this error better, this is not helpful - write!(f, "Not found.")?; + write!(f, "{} not found: {}", what, name)?; Ok(()) } - Self::FailedToReadFile(file) => { + Self::FailedToReadFile { file } => { write!(f, "Failed to read file: {}", file)?; Ok(()) } @@ -44,4 +57,4 @@ impl fmt::Display for Error { } } -impl error::Error for Error {} +impl error::Error for SpineError {} diff --git a/src/event.rs b/src/event.rs index 2610622..82f40f6 100644 --- a/src/event.rs +++ b/src/event.rs @@ -3,11 +3,14 @@ use crate::{ c_interface::{NewFromPtr, SyncPtr}, }; +#[allow(unused_imports)] +use crate::AnimationState; + /// Events fired from animations. /// /// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#Event) /// -/// To receive events, set a listener on [AnimationState](struct.AnimationState.html) +/// To receive events, set a listener on [`AnimationState`]. /// ``` /// # #[path="./doctests.rs"] /// # mod doctests; diff --git a/src/extension.rs b/src/extension.rs index 8c50a08..df92245 100644 --- a/src/extension.rs +++ b/src/extension.rs @@ -78,7 +78,7 @@ where /// Set `_spAtlasPage_disposeTexture` /// -/// For an example, see [set_create_texture_cb](fn.set_create_texture_cb.html). +/// For an example, see [`set_create_texture_cb`]. pub fn set_dispose_texture_cb(dispose_texture_cb: F) where F: Fn(&mut AtlasPage) + 'static, diff --git a/src/lib.rs b/src/lib.rs index d20a251..7ed32c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,13 @@ //! Spine runtime for Rust (and wasm!) transpiled from the official C Runtime. Supports Spine 4.1. //! -//! To load a [Skeleton](struct.Skeleton.html), see [SkeletonJson](struct.SkeletonJson.html) or -//! [SkeletonBinary](struct.SkeletonBinary.html). +//! To load a [`Skeleton`], see [`SkeletonJson`] or [`SkeletonBinary`]. //! //! To set automatic mix durations (crossfading) between animations, see -//! [AnimationStateData](struct.AnimationStateData.html). +//! [`AnimationStateData`]. //! -//! To find and manage bones, see [Bone](struct.Bone.html). +//! To find and manage bones, see [`Bone`]. //! -//! To receive animation events, see [Event](struct.Event.html). +//! To receive animation events, see [`Event`]. #[macro_use] pub mod c_interface; @@ -16,11 +15,9 @@ pub mod c; pub mod extension; #[cfg(feature = "draw_functions")] -pub mod draw; -#[cfg(feature = "draw_functions")] -mod skeleton_controller; +pub mod controller; #[cfg(feature = "draw_functions")] -pub use skeleton_controller::*; +pub mod draw; #[cfg(feature = "egui_debugger")] pub mod debugger; diff --git a/src/skeleton.rs b/src/skeleton.rs index a6ab72f..a176e10 100644 --- a/src/skeleton.rs +++ b/src/skeleton.rs @@ -11,17 +11,20 @@ use crate::{ spSkeleton_updateWorldTransformWith, spSkin, spSlot, }, c_interface::{CTmpMut, CTmpRef, NewFromPtr, SyncPtr}, - error::Error, + error::SpineError, skeleton_data::SkeletonData, skin::Skin, slot::Slot, Attachment, }; +#[allow(unused_imports)] +use crate::{SkeletonBinary, SkeletonJson}; + #[cfg(feature = "mint")] use mint::Vector2; -/// A live Skeleton instance created from [SkeletonData](struct.SkeletonData.html). +/// A live Skeleton instance created from [`SkeletonData`]. /// /// [Spine API Reference](http://esotericsoftware.com/spine-api-reference#Skeleton) #[derive(Debug)] @@ -33,10 +36,9 @@ pub struct Skeleton { } impl Skeleton { - /// Create a new instance of the skeleton loaded in [SkeletonData](struct.SkeletonData.html). + /// Create a new instance of the skeleton loaded in [`SkeletonData`]. /// - /// See [SkeletonJson](struct.SkeletonJson.html) or - /// [SkeletonBinary](struct.SkeletonBinary.html) for a complete example of loading a skeleton. + /// See [`SkeletonJson`] or [`SkeletonBinary`] for a complete example of loading a skeleton. pub fn new(skeleton_data: Arc) -> Self { let c_skeleton = unsafe { spSkeleton_create(skeleton_data.c_ptr()) }; Self { @@ -81,6 +83,9 @@ impl Skeleton { } } + /// Set the skeleton's skin. If the skin is a user-created one (via [`Skin::new`]), then a + /// clone is created and used instead, to help ensure memory safety. If this behavior is not + /// desired then [`Skeleton::set_skin_unchecked`] can be used instead. pub fn set_skin(&mut self, skin: &Skin) { if skin.owns_memory { let cloned_skin = skin.clone(); @@ -93,22 +98,37 @@ impl Skeleton { self.set_to_setup_pose(); } + /// Set the skeleton's skin. + /// + /// # Safety + /// + /// The [`Skin`] struct will destroy the underlying C representation of the skin in its [`Drop`] + /// implementation. Skins assigned to a skeleton must live as long as the skeletons using them + /// or else the skeleton may cause a segfault. pub unsafe fn set_skin_unchecked(&mut self, skin: &Skin) { spSkeleton_setSkin(self.c_ptr(), skin.c_ptr()); } + /// Set the skeleton's skin by name. + /// + /// # Safety + /// + /// This function should only be called with valid skin names. It is faster than the safe + /// alternative, [`Skeleton::set_skin_by_name`], but will likely segfault if the skin does not + /// exist. pub unsafe fn set_skin_by_name_unchecked(&mut self, skin_name: &str) { let c_skin_name = CString::new(skin_name).unwrap(); spSkeleton_setSkinByName(self.c_ptr(), c_skin_name.as_ptr()); self._skin = None; } - pub fn set_skin_by_name(&mut self, skin_name: &str) -> Result<(), Error> { + /// Set the skeleton's skin by name. + pub fn set_skin_by_name(&mut self, skin_name: &str) -> Result<(), SpineError> { if self.data().skins().any(|skin| skin.name() == skin_name) { unsafe { self.set_skin_by_name_unchecked(skin_name) }; Ok(()) } else { - Err(Error::NotFound) + Err(SpineError::new_not_found("Skin", skin_name)) } } diff --git a/src/skeleton_binary.rs b/src/skeleton_binary.rs index 0e94291..c44144e 100644 --- a/src/skeleton_binary.rs +++ b/src/skeleton_binary.rs @@ -10,7 +10,7 @@ use crate::{ spSkeletonBinary_readSkeletonData, spSkeletonBinary_readSkeletonDataFile, }, c_interface::SyncPtr, - error::Error, + error::SpineError, skeleton_data::SkeletonData, Atlas, }; @@ -30,9 +30,9 @@ impl SkeletonBinary { /// /// ``` /// use std::sync::Arc; - /// use rusty_spine::{AnimationState, AnimationStateData, Atlas, Error, Skeleton, SkeletonBinary}; + /// use rusty_spine::{AnimationState, AnimationStateData, Atlas, SpineError, Skeleton, SkeletonBinary}; /// - /// fn load_skeleton() -> Result<(Skeleton, AnimationState), Error> { + /// fn load_skeleton() -> Result<(Skeleton, AnimationState), SpineError> { /// let atlas = Arc::new(Atlas::new_from_file("spineboy.atlas")?); /// let skeleton_binary = SkeletonBinary::new(atlas); /// let skeleton_data = Arc::new(skeleton_binary.read_skeleton_data_file("spineboy.skel")?); @@ -52,7 +52,13 @@ impl SkeletonBinary { } } - pub fn read_skeleton_data(&self, data: &[u8]) -> Result { + /// Read the Spine skeleton binary data in-memory. See [`SkeletonBinary::new`] for a full + /// example. + /// + /// # Errors + /// + /// Returns [`SpineError::ParsingFailed`] if parsing of the binary data failed. + pub fn read_skeleton_data(&self, data: &[u8]) -> Result { let c_skeleton_data = unsafe { spSkeletonBinary_readSkeletonData( self.c_skeleton_binary.0, @@ -64,11 +70,21 @@ impl SkeletonBinary { Ok(SkeletonData::new(c_skeleton_data, self.atlas.clone())) } else { let c_error = unsafe { CStr::from_ptr((*self.c_skeleton_binary.0).error) }; - Err(Error::new_from_spine(c_error.to_str().unwrap())) + Err(SpineError::new_from_spine(c_error.to_str().unwrap())) } } - pub fn read_skeleton_data_file>(&self, path: P) -> Result { + /// Read the Spine skeleton binary data from a file. See [`SkeletonBinary::new`] for a full + /// example. + /// + /// # Errors + /// + /// Returns [`SpineError::ParsingFailed`] if parsing of the binary data failed. Returns + /// [`SpineError::NulError`] if `path` contains an internal 0 byte. + pub fn read_skeleton_data_file>( + &self, + path: P, + ) -> Result { let c_path = CString::new(path.as_ref().to_str().unwrap())?; let c_skeleton_data = unsafe { spSkeletonBinary_readSkeletonDataFile(self.c_skeleton_binary.0, c_path.as_ptr()) @@ -77,7 +93,7 @@ impl SkeletonBinary { Ok(SkeletonData::new(c_skeleton_data, self.atlas.clone())) } else { let c_error = unsafe { CStr::from_ptr((*self.c_skeleton_binary.0).error) }; - Err(Error::new_from_spine(c_error.to_str().unwrap())) + Err(SpineError::new_from_spine(c_error.to_str().unwrap())) } } diff --git a/src/skeleton_json.rs b/src/skeleton_json.rs index 7fdd986..9f7e3aa 100644 --- a/src/skeleton_json.rs +++ b/src/skeleton_json.rs @@ -10,7 +10,7 @@ use crate::{ spSkeletonJson_readSkeletonData, spSkeletonJson_readSkeletonDataFile, }, c_interface::SyncPtr, - error::Error, + error::SpineError, skeleton_data::SkeletonData, Atlas, }; @@ -30,9 +30,9 @@ impl SkeletonJson { /// /// ``` /// use std::sync::Arc; - /// use rusty_spine::{AnimationState, AnimationStateData, Atlas, Error, Skeleton, SkeletonJson}; + /// use rusty_spine::{AnimationState, AnimationStateData, Atlas, SpineError, Skeleton, SkeletonJson}; /// - /// fn load_skeleton() -> Result<(Skeleton, AnimationState), Error> { + /// fn load_skeleton() -> Result<(Skeleton, AnimationState), SpineError> { /// let atlas = Arc::new(Atlas::new_from_file("spineboy.atlas")?); /// let skeleton_json = SkeletonJson::new(atlas); /// let skeleton_data = Arc::new(skeleton_json.read_skeleton_data_file("spineboy.json")?); @@ -52,7 +52,12 @@ impl SkeletonJson { } } - pub fn read_skeleton_data(&self, json: &[u8]) -> Result { + /// Read the Spine skeleton json data in-memory. See [`SkeletonJson::new`] for a full example. + /// + /// # Errors + /// + /// Returns [`SpineError::ParsingFailed`] if parsing of the json data failed. + pub fn read_skeleton_data(&self, json: &[u8]) -> Result { let c_json = CString::new(json)?; let c_skeleton_data = unsafe { spSkeletonJson_readSkeletonData(self.c_skeleton_json.0, c_json.as_ptr()) }; @@ -60,11 +65,20 @@ impl SkeletonJson { Ok(SkeletonData::new(c_skeleton_data, self.atlas.clone())) } else { let c_error = unsafe { CStr::from_ptr((*self.c_skeleton_json.0).error) }; - Err(Error::new_from_spine(c_error.to_str().unwrap())) + Err(SpineError::new_from_spine(c_error.to_str().unwrap())) } } - pub fn read_skeleton_data_file>(&self, path: P) -> Result { + /// Read the Spine skeleton json data from a file. See [`SkeletonJson::new`] for a full example. + /// + /// # Errors + /// + /// Returns [`SpineError::ParsingFailed`] if parsing of the json data failed. Returns + /// [`SpineError::NulError`] if `path` contains an internal 0 byte. + pub fn read_skeleton_data_file>( + &self, + path: P, + ) -> Result { let c_path = CString::new(path.as_ref().to_str().unwrap())?; let c_skeleton_data = unsafe { spSkeletonJson_readSkeletonDataFile(self.c_skeleton_json.0, c_path.as_ptr()) }; @@ -72,7 +86,7 @@ impl SkeletonJson { Ok(SkeletonData::new(c_skeleton_data, self.atlas.clone())) } else { let c_error = unsafe { CStr::from_ptr((*self.c_skeleton_json.0).error) }; - Err(Error::new_from_spine(c_error.to_str().unwrap())) + Err(SpineError::new_from_spine(c_error.to_str().unwrap())) } } diff --git a/src/skin.rs b/src/skin.rs index 203fd04..0218a19 100644 --- a/src/skin.rs +++ b/src/skin.rs @@ -85,7 +85,31 @@ impl Drop for Skin { } } -c_handle_decl!(SkinHandle, Skin, SkeletonData, spSkin, spSkeletonData); +c_handle_decl!( + /// A storeable reference to a [`Skin`]. + /// + /// Can be acquired from a + /// [`CTmpRef`], [`CTmpMut`], + /// [`CTmpRef`], or [`CTmpMut`]. + /// + /// ``` + /// # #[path="./doctests.rs"] + /// # mod doctests; + /// # use rusty_spine::{AnimationState, EventType, SkinHandle}; + /// # let (skeleton, _) = doctests::test_spineboy_instance(); + /// let skeleton_data = skeleton.data(); + /// let skin_handles: Vec = skeleton_data.skins().map(|skin| skin.handle()).collect(); + /// for skin_handle in skin_handles.iter() { + /// let skin = skin_handle.get(skeleton_data.as_ref()).unwrap(); + /// println!("{}", skin.name()); + /// } + /// ``` + SkinHandle, + Skin, + SkeletonData, + spSkin, + spSkeletonData +); impl<'a> CTmpRef<'a, SkeletonData, Skin> { pub fn handle(&self) -> SkinHandle { diff --git a/src/slot.rs b/src/slot.rs index 4916323..4c65e24 100644 --- a/src/slot.rs +++ b/src/slot.rs @@ -129,9 +129,9 @@ impl Slot { } c_handle_decl!( - /// A storeable reference to a [Slot](struct.Slot.html). + /// A storeable reference to a [`Slot`]. /// - /// Can be acquired from any instance of [Slot](struct.Slot.html). + /// Can be acquired from any instance of [`Slot`]. /// /// ``` /// # #[path="./doctests.rs"]