playdate_fs/
file.rs

1use core::ffi::c_uint;
2use alloc::vec::Vec;
3
4use sys::ffi::FileOptions;
5use sys::ffi::SDFile;
6use sys::traits::AsRaw;
7
8use crate::api;
9use crate::Path;
10use crate::ApiError;
11use crate::error::Error;
12use crate::options::FileOptionsExt;
13use crate::options::OpenOptions;
14use crate::seek::SeekFrom;
15
16
17pub trait AnyFile: AsRaw<Type = SDFile> {}
18impl<T: AsRaw<Type = SDFile>> AnyFile for T {}
19
20
21#[must_use = "File will be closed on drop"]
22#[cfg_attr(feature = "bindings-derive-debug", derive(Debug))]
23pub struct File<Api: api::Api = api::Default>(pub(crate) *mut SDFile, pub(crate) Api);
24
25// impl<Api: api::Api> File<Api> {
26// 	pub type Default = File<api::Default>;
27// 	pub type Cached = File<api::Cached>;
28// }
29
30impl<Api: api::Api> AsRaw for File<Api> {
31	type Type = SDFile;
32	unsafe fn as_raw(&self) -> *mut Self::Type { self.0 }
33}
34
35
36impl File<api::Default> {
37	/// Creates a blank new set of options ready for configuration.
38	/// All options are initially set to false.
39	///
40	/// It is equivalent to `FileOptions::new()`.
41	#[must_use]
42	pub fn options() -> impl OpenOptions + FileOptionsExt { FileOptions::new() }
43}
44
45
46impl<Api: api::Api> File<Api> {
47	/// Attempts to open a file in read-only mode.
48	///
49	/// See the [`OpenOptions::open`] method and [official docs][docs] for more details.
50	///
51	/// [docs]: https://sdk.play.date/Inside%20Playdate%20with%20C.html#f-file.open
52	///
53	/// Equivalent to [`sys::ffi::playdate_file::open`]
54	#[doc(alias = "sys::ffi::playdate_file::open")]
55	#[must_use]
56	pub fn open<P: AsRef<Path>>(path: P, data_dir: bool) -> Result<File<Api>, ApiError>
57		where Api: Default {
58		let api = Default::default();
59		crate::ops::open(api, path, FileOptions::new().read(true).read_data(data_dir))
60	}
61
62	/// Attempts to open a file in read-only mode, using the given `api`.
63	///
64	/// See the [`OpenOptions::open`] method and [official docs][docs] for more details.
65	///
66	/// [docs]: https://sdk.play.date/Inside%20Playdate%20with%20C.html#f-file.open
67	///
68	/// Equivalent to [`sys::ffi::playdate_file::open`]
69	#[doc(alias = "sys::ffi::playdate_file::open")]
70	#[must_use]
71	pub fn open_with<P: AsRef<Path>>(api: Api, path: P, data_dir: bool) -> Result<File<Api>, ApiError> {
72		crate::ops::open(api, path, FileOptions::new().read(true).read_data(data_dir))
73	}
74
75	/// Reads up to `len` bytes from the file into the buffer `buf`.
76	///
77	/// Returns the number of bytes read (0 indicating end of file).
78	///
79	/// Equivalent to [`sys::ffi::playdate_file::read`]
80	#[doc(alias = "sys::ffi::playdate_file::read")]
81	#[must_use]
82	#[inline(always)]
83	pub fn read(&mut self, to: &mut Vec<u8>, len: c_uint) -> Result<c_uint, Error> {
84		crate::ops::read(self, to, len)
85	}
86
87	/// Writes the buffer of bytes buf to the file.
88	///
89	/// Returns the number of bytes written.
90	///
91	/// Equivalent to [`sys::ffi::playdate_file::write`]
92	#[doc(alias = "sys::ffi::playdate_file::write")]
93	#[must_use]
94	#[inline(always)]
95	pub fn write(&mut self, from: &[u8]) -> Result<c_uint, Error> { crate::ops::write(self, from) }
96
97	/// Flushes the output buffer of file immediately.
98	///
99	/// Returns the number of bytes written.
100	///
101	/// Equivalent to [`sys::ffi::playdate_file::flush`]
102	#[doc(alias = "sys::ffi::playdate_file::flush")]
103	#[inline(always)]
104	pub fn flush(&mut self) -> Result<c_uint, Error> { crate::ops::flush(self) }
105
106	/// Returns the current read/write offset in the given file handle.
107	///
108	/// Equivalent to [`sys::ffi::playdate_file::tell`]
109	#[doc(alias = "sys::ffi::playdate_file::tell")]
110	#[must_use]
111	#[inline(always)]
112	pub fn tell(&mut self) -> Result<c_uint, Error> { crate::ops::tell(self) }
113
114	/// Sets the read/write offset in the file to `pos`.
115	///
116	/// Equivalent to [`sys::ffi::playdate_file::seek`]
117	#[doc(alias = "sys::ffi::playdate_file::seek")]
118	#[inline(always)]
119	pub fn seek(&mut self, pos: SeekFrom) -> Result<(), Error> {
120		let (whence, pos) = pos.into_parts();
121		crate::ops::seek(self, pos, whence)
122	}
123
124	/// Closes this file.
125	///
126	/// Equivalent to [`sys::ffi::playdate_file::close`]
127	#[doc(alias = "sys::ffi::playdate_file::close")]
128	#[inline(always)]
129	pub fn close(self) -> Result<(), Error> { crate::ops::close(self) }
130}
131
132impl<Api: api::Api> Drop for File<Api> {
133	fn drop(&mut self) {
134		if !self.0.is_null() {
135			let f = self.1.close();
136			let result = unsafe { f(self.0) };
137			self.0 = core::ptr::null_mut();
138
139			match Error::ok_from_code_with(result, &self.1) {
140				Ok(_) => (),
141				Err(err) => println!("Err on file-drop: {err}"),
142			}
143		}
144	}
145}