1use crate::{
2 bindings,
3 error::Error,
4 region::VipsBlob,
5 utils::{self, vips_source_result, vips_target_result},
6 Result,
7};
8use std::{
9 borrow::Cow,
10 ffi::{c_void, CStr, CString},
11 ptr::null_mut,
12};
13
14#[derive(Debug, Clone)]
15pub struct VipsConnection {
16 pub(crate) ctx: *mut bindings::VipsConnection,
17}
18
19#[derive(Debug, Clone)]
20pub struct VipsSource {
21 pub(crate) ctx: *mut bindings::VipsSource,
22}
23
24#[derive(Debug, Clone)]
25pub struct VipsTarget {
26 pub(crate) ctx: *mut bindings::VipsTarget,
27}
28
29impl VipsConnection {
30 pub fn connection_filename(&self) -> Option<String> {
31 unsafe {
32 let result = bindings::vips_connection_filename(self.ctx);
33 if result.is_null() {
34 None
35 } else {
36 let cstr = CStr::from_ptr(result);
37 match cstr.to_string_lossy() {
38 Cow::Borrowed(slice) => Some(slice.to_string()),
39 Cow::Owned(string) => Some(string),
40 }
41 }
42 }
43 }
44
45 pub fn connection_nick(&self) -> Option<String> {
46 unsafe {
47 let result = bindings::vips_connection_nick(self.ctx);
48 if result.is_null() {
49 None
50 } else {
51 let cstr = CStr::from_ptr(result);
52 match cstr.to_string_lossy() {
53 Cow::Borrowed(slice) => Some(slice.to_string()),
54 Cow::Owned(string) => Some(string),
55 }
56 }
57 }
58 }
59}
60
61impl VipsSource {
62 pub fn new_from_descriptor(descriptor: i32) -> Result<Self> {
64 unsafe {
65 let res = bindings::vips_source_new_from_descriptor(descriptor);
66 vips_source_result(
67 res,
68 Error::InitializationError(
69 "Could not initialise VipsSource from descriptor".to_string(),
70 ),
71 )
72 }
73 }
74
75 pub fn new_from_file(filename: &str) -> Result<Self> {
77 unsafe {
78 let f = utils::new_c_string(filename)?;
79 let res = bindings::vips_source_new_from_file(f.as_ptr());
80 vips_source_result(
81 res,
82 Error::InitializationError("Could not initialise VipsSource from file".to_string()),
83 )
84 }
85 }
86
87 fn new_from_blob(blob: VipsBlob) -> Result<Self> {
91 unsafe {
92 let res = bindings::vips_source_new_from_blob(blob.ctx);
93 vips_source_result(
94 res,
95 Error::InitializationError("Could not initialise VipsSource from blob".to_string()),
96 )
97 }
98 }
99
100 pub fn new_from_memory(buffer: &[u8]) -> Result<Self> {
102 unsafe {
103 let res = bindings::vips_source_new_from_memory(
104 buffer.as_ptr() as *const c_void,
105 buffer.len() as u64,
106 );
107 vips_source_result(
108 res,
109 Error::InitializationError(
110 "Could not initialise VipsSource from memory".to_string(),
111 ),
112 )
113 }
114 }
115
116 pub fn new_from_options(option_str: &str) -> Result<Self> {
118 unsafe {
119 let options = utils::new_c_string(option_str)?;
120 let res = bindings::vips_source_new_from_options(options.as_ptr());
121 vips_source_result(
122 res,
123 Error::InitializationError(
124 "Could not initialise VipsSource from options".to_string(),
125 ),
126 )
127 }
128 }
129
130 pub fn minimise(&mut self) {
132 unsafe {
133 bindings::vips_source_minimise(self.ctx);
134 }
135 }
136
137 pub fn unminimise(&mut self) -> Result<()> {
139 unsafe {
140 let result = bindings::vips_source_unminimise(self.ctx);
141 utils::result(
142 result,
143 (),
144 Error::OperationError("Error on vips unminimise".to_string()),
145 )
146 }
147 }
148
149 pub fn decode(&mut self) -> Result<()> {
151 unsafe {
152 let result = bindings::vips_source_decode(self.ctx);
153 utils::result(
154 result,
155 (),
156 Error::OperationError("Error on vips decode".to_string()),
157 )
158 }
159 }
160
161 pub fn read(&mut self, length: u64) -> Result<Vec<u8>> {
163 unsafe {
164 let bytes: *mut c_void = null_mut();
165 let result = bindings::vips_source_read(
166 self.ctx,
167 bytes,
168 length,
169 );
170 if result != -1 {
171 let buffer = Vec::from_raw_parts(
172 bytes as *mut u8,
173 result as usize,
174 result as usize,
175 );
176 Ok(buffer)
177 } else {
178 Err(Error::OperationError("Error on vips read".to_string()))
179 }
180 }
181 }
182
183 pub fn is_mappable(&self) -> bool {
185 unsafe { bindings::vips_source_is_mappable(self.ctx) == 1 }
186 }
187
188 pub fn seek(&mut self, offset: i64, whence: i32) -> Result<i64> {
190 unsafe {
191 let result = bindings::vips_source_seek(
192 self.ctx,
193 offset,
194 whence,
195 );
196 if result == -1 {
197 Err(Error::OperationError("Error on vips seek".to_string()))
198 } else {
199 Ok(result)
200 }
201 }
202 }
203
204 pub fn rewind(&mut self) -> Result<()> {
206 unsafe {
207 let result = bindings::vips_source_rewind(self.ctx);
208 if result == -1 {
209 Err(Error::OperationError("Error on vips rewind".to_string()))
210 } else {
211 Ok(())
212 }
213 }
214 }
215
216 pub fn length(&self) -> Result<i64> {
218 unsafe {
219 let result = bindings::vips_source_length(self.ctx);
220 if result == -1 {
221 Err(Error::OperationError("Error on vips length".to_string()))
222 } else {
223 Ok(result)
224 }
225 }
226 }
227}
228
229impl<'a> VipsSource {
230 pub fn map(&'a self) -> Result<&'a [u8]> {
232 unsafe {
233 let length: *mut u64 = null_mut();
234 let result = bindings::vips_source_map(
235 self.ctx,
236 length,
237 );
238 if length.is_null() {
239 Err(Error::OperationError("Error on vips map".to_string()))
240 } else {
241 let size = (*length)
242 .try_into()
243 .map_err(|_| Error::OperationError("Can't get size of array".to_string()))?;
244 Ok(
245 std::slice::from_raw_parts(
246 result as *mut u8,
247 size,
248 ),
249 )
250 }
251 }
252 }
253}
254
255impl VipsTarget {
256 pub fn new_to_descriptor(descriptor: i32) -> Result<Self> {
258 unsafe {
259 let res = bindings::vips_target_new_to_descriptor(descriptor);
260 vips_target_result(
261 res,
262 Error::InitializationError(
263 "Could not initialise VipsTarget from descriptor".to_string(),
264 ),
265 )
266 }
267 }
268
269 pub fn new_to_file(filename: &str) -> Result<Self> {
271 unsafe {
272 let f = utils::new_c_string(filename)?;
273 let res = bindings::vips_target_new_to_file(f.as_ptr());
274 vips_target_result(
275 res,
276 Error::InitializationError("Could not initialise VipsTarget from file".to_string()),
277 )
278 }
279 }
280
281 pub fn new_to_memory() -> Result<Self> {
283 unsafe {
284 let res = bindings::vips_target_new_to_memory();
285 vips_target_result(
286 res,
287 Error::InitializationError(
288 "Could not initialise VipsTarget from memory".to_string(),
289 ),
290 )
291 }
292 }
293
294 pub fn end(self) {
296 unsafe {
297 bindings::vips_target_end(self.ctx);
298 }
299 }
300
301 pub fn putc(&mut self, ch: char) -> Result<()> {
303 unsafe {
304 let res = bindings::vips_target_putc(
305 self.ctx,
306 ch as i32,
307 );
308 if res == -1 {
309 Err(Error::OperationError("Could not write to buffer".to_string()))
310 } else {
311 Ok(())
312 }
313 }
314 }
315
316 pub fn write(&mut self, buffer: &[u8]) -> Result<()> {
318 unsafe {
319 let res = bindings::vips_target_write(
320 self.ctx,
321 buffer.as_ptr() as *const c_void,
322 buffer.len() as u64,
323 );
324 if res == -1 {
325 Err(Error::OperationError("Could not write to buffer".to_string()))
326 } else {
327 Ok(())
328 }
329 }
330 }
331
332 pub fn write_amp(&mut self, text: &str) -> Result<()> {
334 unsafe {
335 let cstr = CString::new(text)
336 .map_err(|_| Error::OperationError("Cannot initialize C string".to_string()))?;
337 let res = bindings::vips_target_write_amp(
338 self.ctx,
339 cstr.as_ptr(),
340 );
341 if res == -1 {
342 Err(Error::OperationError("Could not write to buffer".to_string()))
343 } else {
344 Ok(())
345 }
346 }
347 }
348
349 pub fn writes(&mut self, text: &str) -> Result<()> {
351 unsafe {
352 let cstr = CString::new(text)
353 .map_err(|_| Error::OperationError("Cannot initialize C string".to_string()))?;
354 let res = bindings::vips_target_writes(
355 self.ctx,
356 cstr.as_ptr(),
357 );
358 if res == -1 {
359 Err(Error::OperationError("Could not write to buffer".to_string()))
360 } else {
361 Ok(())
362 }
363 }
364 }
365
366 pub fn get_blob(&self) -> VipsBlob {
367 unsafe {
368 VipsBlob {
369 ctx: (*self.ctx).blob,
370 }
371 }
372 }
373}
374
375impl Drop for VipsConnection {
376 fn drop(&mut self) {
377 unsafe {
378 if !self
379 .ctx
380 .is_null()
381 {
382 bindings::g_object_unref(self.ctx as *mut c_void);
383 }
384 }
385 }
386}
387
388impl Drop for VipsSource {
389 fn drop(&mut self) {
390 unsafe {
391 if !self
392 .ctx
393 .is_null()
394 {
395 bindings::g_object_unref(self.ctx as *mut c_void);
396 }
397 }
398 }
399}
400
401impl Drop for VipsTarget {
402 fn drop(&mut self) {
403 unsafe {
404 if !self
405 .ctx
406 .is_null()
407 {
408 bindings::g_object_unref(self.ctx as *mut c_void);
409 }
410 }
411 }
412}
413
414impl From<*mut bindings::VipsSource> for VipsSource {
415 fn from(value: *mut bindings::VipsSource) -> Self {
416 Self {
417 ctx: value,
418 }
419 }
420}
421
422impl From<*mut bindings::VipsTarget> for VipsTarget {
423 fn from(value: *mut bindings::VipsTarget) -> Self {
424 Self {
425 ctx: value,
426 }
427 }
428}