nvdialog_rs/string.rs
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2022-2025 Aggelos Tselios
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 * IN THE SOFTWARE.
23 */
24
25use std::{
26 ffi::{c_char, CStr}, fmt::Display, ptr::null
27};
28
29use crate::cstr;
30use nvdialog_sys::ffi::*;
31
32/// A Rust version of `NvdDynamicString`
33///
34/// A [`DynamicString`] is effectively a conversion of a heap allocated string designed to work with NvDialog
35/// that works with the Rust side. In essence, it's just another string type for Rust, but works with this crate instead.
36/// This type is useful since version v0.10 of NvDialog when the API was completely rewritten to use `NvdDynamicString`, a separate
37/// string type that addresses the limitations of working with raw character buffers and safety concerns.
38///
39#[derive(Debug)]
40pub struct DynamicString {
41 native: *mut NvdDynamicString,
42 this: String,
43}
44
45impl DynamicString {
46 /// Create a new `DynamicString` from optional UTF-8 data.
47 ///
48 /// - If `data` is `Some`, the contents are passed to the FFI (as a C string)
49 /// and mirrored into `Self` as well.
50 /// - If `data` is `None`, a null is passed to `nvd_string_new`, which is
51 /// expected (by the library) to produce an empty string.
52 ///
53 /// Note that if you want to duplicate a string, you can use [`DynamicString::duplicate`] instead of
54 /// allocating a brand new one.
55 ///
56 /// ## Safety
57 /// The returned object can be modified safely, however note that any modifications are permanent and
58 /// if you received the `DynamicString` from another function, then trying to fetch it again will return your
59 /// modified string as the internal pointer was modified.
60 pub fn new<S: AsRef<str>>(data: Option<S>) -> Self {
61 if let Some(s) = data {
62 let string = cstr!(s.as_ref());
63 Self {
64 native: unsafe {
65 let s = nvd_string_new(string.as_ptr());
66 if s.is_null() {
67 panic!("libnvdialog did not produce a valid NvdDynamicString!");
68 }
69 s
70 },
71 this: String::from(s.as_ref()),
72 }
73 } else {
74 Self {
75 native: unsafe {
76 let s = nvd_string_new(null());
77 if s.is_null() {
78 panic!("libnvdialog did not produce a valid NvdDynamicString!");
79 }
80 s
81 },
82 this: String::new(),
83 }
84 }
85 }
86
87 /// Returns a borrowed pointer to the internal string's buffer.
88 ///
89 /// ## Safety
90 /// The returned pointer is only valid as long as `self` is. Additionally, if the internal data was corrupted,
91 /// this function may corrupt the program's memory, therefore make sure `self` was not internally modified beforehand.
92 /// ## Returns
93 /// A NULL-terminated, heap-allocated C-style string on success, or NULL if `nvd_string_to_cstr` failed.
94 #[inline]
95 pub unsafe fn as_ptr(&self) -> *const c_char {
96 assert!(!self.native.is_null());
97 nvd_string_to_cstr(self.native)
98 }
99
100 /// Create a deep copy of this `DynamicString`.
101 ///
102 /// Note that this function returns a truly unique `DynamicString` - It is safe to modify the returned value as
103 /// `self` does not point to it (and vice versa).
104 ///
105 /// ## Safety
106 /// This function is safe to use, unless the internal structure was corrupted beforehand, in which case `nvd_duplicate_string`
107 /// may return invalid or corrupt data. Make sure `self` has not been modified incorrectly before calling this function.
108 ///
109 /// ## Returns
110 /// A deep copy of `self`, assuming no errors from the FFI-side.
111
112 #[inline]
113 pub fn duplicate(&self) -> Self {
114 Self {
115 native: unsafe { nvd_duplicate_string(self.native) },
116 this: self.this.clone(),
117 }
118 }
119
120 /// Returns a reference to the internal [`String`] that mirrors the FFI string to avoid extra allocations.
121 /// # Safety
122 /// This function is always safe to use. If you modify `self` correctly, then the contents are always mirrored.
123 #[inline]
124 pub fn as_str(&self) -> &str {
125 &self.this
126 }
127}
128
129impl From<*mut NvdDynamicString> for DynamicString {
130 fn from(value: *mut NvdDynamicString) -> Self {
131 assert!(!value.is_null());
132 Self {
133 native: value,
134 this: unsafe {
135 String::from(CStr::from_ptr(nvd_string_to_cstr(value)).to_string_lossy())
136 },
137 }
138 }
139}
140
141impl From<&str> for DynamicString {
142 fn from(s: &str) -> Self {
143 let string = cstr!(s);
144 Self {
145 native: unsafe { nvd_string_new(string.as_ptr()) },
146 this: s.to_owned(),
147 }
148 }
149}
150
151impl From<String> for DynamicString {
152 fn from(data: String) -> Self {
153 let string = cstr!(&*data);
154 Self {
155 native: unsafe { nvd_string_new(string.as_ptr()) },
156 this: data,
157 }
158 }
159}
160
161impl Display for DynamicString {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(f, "{}", self.this)
164 }
165}
166
167impl Clone for DynamicString {
168 fn clone(&self) -> Self {
169 assert!(!self.native.is_null());
170 self.duplicate()
171 }
172}
173
174impl Drop for DynamicString {
175 fn drop(&mut self) {
176 unsafe { nvd_delete_string(self.native) }
177 }
178}