rich_sdl2_rust/file/
rw.rs

1use std::{
2    ffi::CString,
3    io::{self, Seek},
4    marker::PhantomData,
5    os::raw::c_int,
6    ptr::NonNull,
7};
8
9use super::mode::OpenMode;
10use crate::{bind, Result, Sdl, SdlError};
11
12/// A file handler, how to read and write from file on SDL2.
13pub struct RwOps<'a> {
14    ptr: NonNull<bind::SDL_RWops>,
15    _phantom: PhantomData<&'a mut ()>,
16}
17
18impl std::fmt::Debug for RwOps<'_> {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        f.debug_struct("RwOps")
21            .field("size", &self.size())
22            .finish_non_exhaustive()
23    }
24}
25
26impl<'a> RwOps<'a> {
27    /// Returns the raw pointer of the file handler.
28    ///
29    /// # Safety
30    ///
31    /// Dereferencing the pointer and using the field is not recommended. Please use carefully.
32    #[must_use]
33    pub unsafe fn ptr(&self) -> NonNull<bind::SDL_RWops> {
34        self.ptr
35    }
36
37    /// Constructs from file name with the open mode.
38    ///
39    /// # Panics
40    ///
41    /// Panics if `file_name` was empty.
42    ///
43    /// # Errors
44    ///
45    /// Returns `Err` if failed to open the file with `mode`.
46    pub fn from_file(file_name: &str, mode: OpenMode) -> Result<RwOps<'static>> {
47        let cstr = CString::new(file_name).expect("file_name must not be empty");
48        let ptr = unsafe { bind::SDL_RWFromFile(cstr.as_ptr(), mode.into_raw().as_ptr()) };
49        if ptr.is_null() {
50            Err(SdlError::Others { msg: Sdl::error() })
51        } else {
52            Ok(RwOps {
53                ptr: NonNull::new(ptr).unwrap(),
54                _phantom: PhantomData,
55            })
56        }
57    }
58
59    /// Constructs from the buffer `&[u8]`.
60    ///
61    /// # Errors
62    ///
63    /// Returns `Err` if failed to make it a read-only memory buffer.
64    pub fn from_mem(buf: &'a [u8]) -> Result<Self> {
65        let ptr = unsafe { bind::SDL_RWFromConstMem(buf.as_ptr().cast(), buf.len() as c_int) };
66        if ptr.is_null() {
67            Err(SdlError::Others { msg: Sdl::error() })
68        } else {
69            Ok(RwOps {
70                ptr: NonNull::new(ptr).unwrap(),
71                _phantom: PhantomData,
72            })
73        }
74    }
75
76    /// Constructs from the mutable buffer `&mut [u8]`.
77    ///
78    /// # Errors
79    ///
80    /// Returns `Err` if failed to make it a read-write memory buffer.
81    pub fn from_mem_mut(buf: &'a mut [u8]) -> Result<Self> {
82        let ptr = unsafe { bind::SDL_RWFromMem(buf.as_mut_ptr().cast(), buf.len() as c_int) };
83        if ptr.is_null() {
84            Err(SdlError::Others { msg: Sdl::error() })
85        } else {
86            Ok(RwOps {
87                ptr: NonNull::new(ptr).unwrap(),
88                _phantom: PhantomData,
89            })
90        }
91    }
92
93    /// Returns the size of the read/write target.
94    ///
95    /// # Errors
96    ///
97    /// Returns `Err` if failed to get the size of buffer.
98    pub fn size(&self) -> Result<usize> {
99        let ret = unsafe { bind::SDL_RWsize(self.ptr.as_ptr()) };
100        if ret < 0 {
101            Err(SdlError::Others { msg: Sdl::error() })
102        } else {
103            Ok(ret as usize)
104        }
105    }
106
107    /// Returns the current position of seeking.
108    ///
109    /// # Errors
110    ///
111    /// Returns `Err` if failed to seek to get the current position.
112    pub fn tell(&mut self) -> io::Result<u64> {
113        self.stream_position()
114    }
115
116    /// Reads and pops the 8-bits value.
117    pub fn read_u8(&mut self) -> u8 {
118        unsafe { bind::SDL_ReadU8(self.ptr.as_ptr()) }
119    }
120    /// Reads and pops the big endian 16-bits value.
121    pub fn read_be16(&mut self) -> u16 {
122        unsafe { bind::SDL_ReadBE16(self.ptr.as_ptr()) }
123    }
124    /// Reads and pops the little endian 16-bits value.
125    pub fn read_le16(&mut self) -> u16 {
126        unsafe { bind::SDL_ReadLE16(self.ptr.as_ptr()) }
127    }
128    /// Reads and pops the big endian 32-bits value.
129    pub fn read_be32(&mut self) -> u32 {
130        unsafe { bind::SDL_ReadBE32(self.ptr.as_ptr()) }
131    }
132    /// Reads and pops the little endian 32-bits value.
133    pub fn read_le32(&mut self) -> u32 {
134        unsafe { bind::SDL_ReadLE32(self.ptr.as_ptr()) }
135    }
136    /// Reads and pops the big endian 64-bits value.
137    pub fn read_be64(&mut self) -> u64 {
138        unsafe { bind::SDL_ReadBE64(self.ptr.as_ptr()) }
139    }
140    /// Reads and pops the little endian 64-bits value.
141    pub fn read_le64(&mut self) -> u64 {
142        unsafe { bind::SDL_ReadLE64(self.ptr.as_ptr()) }
143    }
144
145    /// Writes the 8-bits value.
146    pub fn write_u8(&mut self, value: u8) -> bool {
147        unsafe { bind::SDL_WriteU8(self.ptr.as_ptr(), value) == 1 }
148    }
149    /// Writes the big endian 16-bits value.
150    pub fn write_be16(&mut self, value: u16) -> bool {
151        unsafe { bind::SDL_WriteBE16(self.ptr.as_ptr(), value) == 1 }
152    }
153    /// Writes the little endian 16-bits value.
154    pub fn write_le16(&mut self, value: u16) -> bool {
155        unsafe { bind::SDL_WriteLE16(self.ptr.as_ptr(), value) == 1 }
156    }
157    /// Writes the big endian 32-bits value.
158    pub fn write_be32(&mut self, value: u32) -> bool {
159        unsafe { bind::SDL_WriteBE32(self.ptr.as_ptr(), value) == 1 }
160    }
161    /// Writes the little endian 32-bits value.
162    pub fn write_le32(&mut self, value: u32) -> bool {
163        unsafe { bind::SDL_WriteLE32(self.ptr.as_ptr(), value) == 1 }
164    }
165    /// Writes the big endian 64-bits value.
166    pub fn write_be64(&mut self, value: u64) -> bool {
167        unsafe { bind::SDL_WriteBE64(self.ptr.as_ptr(), value) == 1 }
168    }
169    /// Writes the little endian 64-bits value.
170    pub fn write_le64(&mut self, value: u64) -> bool {
171        unsafe { bind::SDL_WriteLE64(self.ptr.as_ptr(), value) == 1 }
172    }
173}
174
175impl Drop for RwOps<'_> {
176    fn drop(&mut self) {
177        let _ = unsafe { bind::SDL_RWclose(self.ptr.as_ptr()) };
178    }
179}
180
181impl io::Read for RwOps<'_> {
182    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
183        let ret = unsafe {
184            bind::SDL_RWread(
185                self.ptr.as_ptr(),
186                buf.as_mut_ptr().cast(),
187                1,
188                buf.len() as _,
189            )
190        };
191        if ret == 0 {
192            Err(io::Error::new(
193                io::ErrorKind::Other,
194                SdlError::Others { msg: Sdl::error() },
195            ))
196        } else {
197            Ok(ret as _)
198        }
199    }
200}
201
202impl io::Seek for RwOps<'_> {
203    fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
204        let ret = match pos {
205            io::SeekFrom::Start(pos) => unsafe {
206                bind::SDL_RWseek(self.ptr.as_ptr(), pos as i64, 0)
207            },
208            io::SeekFrom::End(pos) => unsafe { bind::SDL_RWseek(self.ptr.as_ptr(), pos, 2) },
209            io::SeekFrom::Current(pos) => unsafe { bind::SDL_RWseek(self.ptr.as_ptr(), pos, 1) },
210        };
211        if ret < 0 {
212            Err(io::Error::new(
213                io::ErrorKind::Other,
214                SdlError::Others { msg: Sdl::error() },
215            ))
216        } else {
217            Ok(ret as u64)
218        }
219    }
220}
221
222impl io::Write for RwOps<'_> {
223    #[allow(clippy::unnecessary_cast)]
224    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
225        let written =
226            unsafe { bind::SDL_RWwrite(self.ptr.as_ptr(), buf.as_ptr().cast(), 1, buf.len() as _) }
227                as usize;
228        if written < buf.len() {
229            Err(io::Error::new(
230                io::ErrorKind::Other,
231                SdlError::Others { msg: Sdl::error() },
232            ))
233        } else {
234            Ok(written)
235        }
236    }
237
238    fn flush(&mut self) -> io::Result<()> {
239        Ok(())
240    }
241}