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