1#![allow(unsafe_code)]
9#![warn(missing_docs)]
10
11use crate::SharedVector;
12use alloc::string::String;
13use core::fmt::{Debug, Display, Write};
14use core::ops::Deref;
15#[cfg(not(feature = "std"))]
16#[allow(unused)]
17use num_traits::Float;
18
19#[macro_export]
27macro_rules! format {
28 ($($arg:tt)*) => {{
29 $crate::string::format(core::format_args!($($arg)*))
30 }}
31}
32
33#[derive(Clone, Default)]
44#[repr(C)]
45pub struct SharedString {
46 inner: SharedVector<u8>,
48}
49
50impl SharedString {
51 pub fn new() -> Self {
55 Self::default()
56 }
57
58 fn as_ptr(&self) -> *const u8 {
59 self.inner.as_ptr()
60 }
61
62 pub fn len(&self) -> usize {
64 self.inner.len().saturating_sub(1)
65 }
66
67 pub fn is_empty(&self) -> bool {
69 self.len() == 0
70 }
71
72 pub fn as_str(&self) -> &str {
74 unsafe {
76 core::str::from_utf8_unchecked(core::slice::from_raw_parts(self.as_ptr(), self.len()))
77 }
78 }
79
80 pub(crate) fn replace_characters(&mut self, from: char, to: char, count: usize) {
82 let mut from_buffer = [0u8; 4];
83 let mut to_buffer = [0u8; 4];
84 self.inner.replace_range(
85 from.encode_utf8(&mut from_buffer).as_bytes(),
86 to.encode_utf8(&mut to_buffer).as_bytes(),
87 count,
88 );
89 }
90
91 pub fn push_str(&mut self, x: &str) {
102 let mut iter = x.as_bytes().iter().copied();
103 if self.inner.is_empty() {
104 self.inner.extend(iter.chain(core::iter::once(0)));
105 } else if let Some(first) = iter.next() {
106 let prev_len = self.len();
110 self.inner.extend(iter.chain(core::iter::once(0)));
111 self.inner.make_mut_slice()[prev_len] = first;
112 }
113 }
114}
115
116impl Deref for SharedString {
117 type Target = str;
118 fn deref(&self) -> &Self::Target {
119 self.as_str()
120 }
121}
122
123impl From<&str> for SharedString {
124 fn from(value: &str) -> Self {
125 SharedString {
126 inner: SharedVector::from_iter(
127 value.as_bytes().iter().cloned().chain(core::iter::once(0)),
128 ),
129 }
130 }
131}
132
133impl Debug for SharedString {
134 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
135 Debug::fmt(self.as_str(), f)
136 }
137}
138
139impl Display for SharedString {
140 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
141 Display::fmt(self.as_str(), f)
142 }
143}
144
145impl AsRef<str> for SharedString {
146 #[inline]
147 fn as_ref(&self) -> &str {
148 self.as_str()
149 }
150}
151
152#[cfg(feature = "serde")]
153impl serde::Serialize for SharedString {
154 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
155 where
156 S: serde::Serializer,
157 {
158 let string = self.as_str();
159 serializer.serialize_str(string)
160 }
161}
162
163#[cfg(feature = "serde")]
164impl<'de> serde::Deserialize<'de> for SharedString {
165 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
166 where
167 D: serde::Deserializer<'de>,
168 {
169 struct SharedStringVisitor;
170
171 impl<'de> serde::de::Visitor<'de> for SharedStringVisitor {
172 type Value = SharedString;
173
174 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
175 formatter.write_str("a borrowed or owned string")
176 }
177
178 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
179 where
180 E: serde::de::Error,
181 {
182 Ok(SharedString::from(v))
183 }
184 }
185 deserializer.deserialize_str(SharedStringVisitor)
186 }
187}
188
189#[cfg(feature = "std")]
190impl AsRef<std::ffi::CStr> for SharedString {
191 #[inline]
192 fn as_ref(&self) -> &std::ffi::CStr {
193 if self.inner.is_empty() {
194 return Default::default();
195 }
196 debug_assert_eq!(self.inner.as_slice()[self.inner.len() - 1], 0);
198 unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(self.inner.as_slice()) }
199 }
200}
201
202#[cfg(feature = "std")]
203impl AsRef<std::path::Path> for SharedString {
204 #[inline]
205 fn as_ref(&self) -> &std::path::Path {
206 self.as_str().as_ref()
207 }
208}
209
210#[cfg(feature = "std")]
211impl AsRef<std::ffi::OsStr> for SharedString {
212 #[inline]
213 fn as_ref(&self) -> &std::ffi::OsStr {
214 self.as_str().as_ref()
215 }
216}
217
218impl AsRef<[u8]> for SharedString {
219 #[inline]
220 fn as_ref(&self) -> &[u8] {
221 self.as_str().as_bytes()
222 }
223}
224
225impl<T> PartialEq<T> for SharedString
226where
227 T: ?Sized + AsRef<str>,
228{
229 fn eq(&self, other: &T) -> bool {
230 self.as_str() == other.as_ref()
231 }
232}
233impl Eq for SharedString {}
234
235impl<T> PartialOrd<T> for SharedString
236where
237 T: ?Sized + AsRef<str>,
238{
239 fn partial_cmp(&self, other: &T) -> Option<core::cmp::Ordering> {
240 PartialOrd::partial_cmp(self.as_str(), other.as_ref())
241 }
242}
243impl Ord for SharedString {
244 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
245 Ord::cmp(self.as_str(), other.as_str())
246 }
247}
248
249impl From<String> for SharedString {
250 fn from(s: String) -> Self {
251 s.as_str().into()
252 }
253}
254
255impl From<&String> for SharedString {
256 fn from(s: &String) -> Self {
257 s.as_str().into()
258 }
259}
260
261impl From<char> for SharedString {
262 fn from(c: char) -> Self {
263 SharedString::from(c.encode_utf8(&mut [0; 6]) as &str)
264 }
265}
266
267impl From<SharedString> for String {
268 fn from(s: SharedString) -> String {
269 s.as_str().into()
270 }
271}
272
273impl From<&SharedString> for String {
274 fn from(s: &SharedString) -> String {
275 s.as_str().into()
276 }
277}
278
279impl core::ops::AddAssign<&str> for SharedString {
280 fn add_assign(&mut self, other: &str) {
281 self.push_str(other);
282 }
283}
284
285impl core::ops::Add<&str> for SharedString {
286 type Output = SharedString;
287 fn add(mut self, other: &str) -> SharedString {
288 self.push_str(other);
289 self
290 }
291}
292
293impl core::hash::Hash for SharedString {
294 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
295 self.as_str().hash(state)
296 }
297}
298
299impl Write for SharedString {
300 fn write_str(&mut self, s: &str) -> core::fmt::Result {
301 self.push_str(s);
302 Ok(())
303 }
304}
305
306impl core::borrow::Borrow<str> for SharedString {
307 fn borrow(&self) -> &str {
308 self.as_str()
309 }
310}
311
312impl Extend<char> for SharedString {
313 fn extend<X: IntoIterator<Item = char>>(&mut self, iter: X) {
314 let iter = iter.into_iter();
315 self.inner.reserve(iter.size_hint().0);
316 let mut buf = [0; 4];
317 for ch in iter {
318 let utf8 = ch.encode_utf8(&mut buf);
319 self.push_str(utf8);
320 }
321 }
322}
323
324impl FromIterator<char> for SharedString {
325 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
326 let mut str = Self::new();
327 str.extend(iter);
328 str
329 }
330}
331
332pub fn format(args: core::fmt::Arguments<'_>) -> SharedString {
334 let mut output = SharedString::default();
337 output.write_fmt(args).unwrap();
338 output
339}
340
341pub trait ToSharedString {
346 fn to_shared_string(&self) -> SharedString;
348}
349
350impl<T> ToSharedString for T
351where
352 T: Display + ?Sized,
353{
354 fn to_shared_string(&self) -> SharedString {
355 format!("{}", self)
356 }
357}
358
359#[inline]
361pub fn shared_string_from_number_unlocalized(n: f64) -> SharedString {
362 crate::format!("{}", i_slint_common::FormattedNumber(n))
363}
364
365pub fn shared_string_from_number(n: f64) -> SharedString {
367 crate::context::GLOBAL_CONTEXT.with(|ctx| {
368 let mut result = shared_string_from_number_unlocalized(n);
369
370 if let Some(ctx) = ctx.get() {
371 let pinned = ctx.0.as_ref().project_ref();
372 let decimal_separator = pinned.locale_decimal_separator.get();
373 if decimal_separator != i_slint_common::DEFAULT_DECIMAL_SEPARATOR {
374 result.replace_characters('.', decimal_separator, 1);
375 }
376 }
377 result
378 })
379}
380
381pub fn shared_string_from_number_fixed(n: f64, digits: usize) -> SharedString {
383 crate::context::GLOBAL_CONTEXT.with(|ctx| {
384 let mut result = crate::format!("{number:.digits$}", number = n, digits = digits);
385
386 if let Some(ctx) = ctx.get() {
387 let pinned = ctx.0.as_ref().project_ref();
388 let decimal_separator = pinned.locale_decimal_separator.get();
389 if decimal_separator != i_slint_common::DEFAULT_DECIMAL_SEPARATOR {
390 result.replace_characters('.', decimal_separator, 1);
391 }
392 }
393 result
394 })
395}
396
397pub fn shared_string_from_number_precision(n: f64, precision: usize) -> SharedString {
399 let exponent = f64::log10(n.abs()).floor() as isize;
400 if precision == 0 {
401 shared_string_from_number(n)
402 } else if exponent < -6 || (exponent >= 0 && exponent as usize >= precision) {
403 crate::format!(
404 "{number:.digits$e}",
405 number = n,
406 digits = precision.saturating_add_signed(-1)
407 )
408 } else {
409 shared_string_from_number_fixed(n, precision.saturating_add_signed(-(exponent + 1)))
410 }
411}
412
413pub fn shared_string_replace_all(s: &SharedString, from: &str, to: &str) -> SharedString {
416 let mut matches = s.match_indices(from);
417 let Some((first, _)) = matches.next() else {
418 return s.clone();
419 };
420
421 let mut result = SharedString::from(&s[..first]);
422 result.push_str(to);
423 let mut last_end = first + from.len();
424 for (start, _) in matches {
425 result.push_str(&s[last_end..start]);
426 result.push_str(to);
427 last_end = start + from.len();
428 }
429 result.push_str(&s[last_end..]);
430 result
431}
432
433pub fn string_to_float(string: &str) -> Option<f32> {
435 crate::context::GLOBAL_CONTEXT.with(|ctx| {
436 let sep = ctx.get().map(|ctx| ctx.locale_decimal_separator()).unwrap_or('.');
437
438 if sep == '.' {
439 string.parse::<f32>().ok()
440 } else {
441 if string.contains('.') {
442 return None;
443 }
444 string.replace(sep, ".").parse::<f32>().ok()
446 }
447 })
448}
449
450#[test]
451fn test_string_to_float() {
452 const TEST: &[(&str, Option<f32>)] = &[
453 ("-", None),
454 (".", None),
455 ("-.", None),
456 ("-.5", Some(-0.5)),
457 ("--", None),
458 ("..", None),
459 ("5.5.", None),
460 ("231.435", Some(231.435)),
461 ("-0.007", Some(-0.007)),
462 ("10e6", Some(10e6)),
463 ];
464
465 for (test_string, result) in TEST {
466 assert_eq!(string_to_float(test_string), *result);
467 }
468}
469
470#[test]
471fn simple_test() {
472 use std::string::ToString;
473 let x = SharedString::from("hello world!");
474 assert_eq!(x, "hello world!");
475 assert_ne!(x, "hello world?");
476 assert_eq!(x, x.clone());
477 assert_eq!("hello world!", x.as_str());
478 let string = String::from("hello world!");
479 assert_eq!(x, string);
480 assert_eq!(x.to_string(), string);
481 let def = SharedString::default();
482 assert_eq!(def, SharedString::default());
483 assert_eq!(def, SharedString::new());
484 assert_ne!(def, x);
485 assert_eq!(
486 (&x as &dyn AsRef<std::ffi::CStr>).as_ref(),
487 &*std::ffi::CString::new("hello world!").unwrap()
488 );
489 assert_eq!(SharedString::from('h'), "h");
490 assert_eq!(SharedString::from('😎'), "😎");
491}
492
493#[test]
494fn threading() {
495 let shared_cst = SharedString::from("Hello there!");
496 let shared_mtx = std::sync::Arc::new(std::sync::Mutex::new(SharedString::from("Shared:")));
497 let mut handles = std::vec::Vec::new();
498 for _ in 0..20 {
499 let cst = shared_cst.clone();
500 let mtx = shared_mtx.clone();
501 handles.push(std::thread::spawn(move || {
502 assert_eq!(cst, "Hello there!");
503 let mut cst2 = cst.clone();
504 cst2.push_str(" ... or not?");
505 assert_eq!(cst2, "Hello there! ... or not?");
506 assert_eq!(cst.clone(), "Hello there!");
507
508 let shared = {
509 let mut lock = mtx.lock().unwrap();
510 assert!(lock.starts_with("Shared:"));
511 lock.push_str("!");
512 lock.clone()
513 };
514 assert!(shared.clone().starts_with("Shared:"));
515 }));
516 }
517 for j in handles {
518 j.join().unwrap();
519 }
520 assert_eq!(shared_cst.clone(), "Hello there!");
521 assert_eq!(shared_mtx.lock().unwrap().as_str(), "Shared:!!!!!!!!!!!!!!!!!!!!");
522 }
524
525#[test]
526fn to_shared_string() {
527 let i = 5.1;
528 let five = SharedString::from("5.1");
529
530 assert_eq!(five, i.to_shared_string());
531}
532
533#[test]
534fn test_replace_characters() {
535 let mut value = SharedString::from("5.1");
536 value.replace_characters('.', ',', 1);
537
538 assert_eq!(value, "5,1".to_shared_string());
539}
540
541#[cfg(feature = "ffi")]
542pub(crate) mod ffi {
543 use super::*;
544
545 #[allow(non_camel_case_types)]
547 type c_char = u8;
548
549 #[unsafe(no_mangle)]
550 pub extern "C" fn slint_shared_string_bytes(ss: &SharedString) -> *const c_char {
554 if ss.is_empty() { c"".as_ptr().cast() } else { ss.as_ptr() }
555 }
556
557 #[unsafe(no_mangle)]
558 pub unsafe extern "C" fn slint_shared_string_drop(ss: *const SharedString) {
560 unsafe {
561 core::ptr::read(ss);
562 }
563 }
564
565 #[unsafe(no_mangle)]
566 pub unsafe extern "C" fn slint_shared_string_clone(out: *mut SharedString, ss: &SharedString) {
569 unsafe { core::ptr::write(out, ss.clone()) }
570 }
571
572 #[unsafe(no_mangle)]
573 pub unsafe extern "C" fn slint_shared_string_from_bytes(
576 out: *mut SharedString,
577 bytes: *const c_char,
578 len: usize,
579 ) {
580 unsafe {
581 let str = core::str::from_utf8(core::slice::from_raw_parts(bytes, len)).unwrap();
582 core::ptr::write(out, SharedString::from(str));
583 }
584 }
585
586 #[unsafe(no_mangle)]
589 pub unsafe extern "C" fn slint_shared_string_from_number_unlocalized(
590 out: *mut SharedString,
591 n: f64,
592 ) {
593 let str = shared_string_from_number_unlocalized(n);
594 unsafe { core::ptr::write(out, str) };
595 }
596
597 #[unsafe(no_mangle)]
600 pub unsafe extern "C" fn slint_shared_string_from_number(out: *mut SharedString, n: f64) {
601 let str = shared_string_from_number(n);
602 unsafe { core::ptr::write(out, str) };
603 }
604
605 #[test]
606 fn test_slint_shared_string_from_number() {
607 unsafe {
608 let mut s = core::mem::MaybeUninit::uninit();
609 slint_shared_string_from_number(s.as_mut_ptr(), 45.);
610 assert_eq!(s.assume_init(), "45");
611
612 let mut s = core::mem::MaybeUninit::uninit();
613 slint_shared_string_from_number(s.as_mut_ptr(), 45.12);
614 assert_eq!(s.assume_init(), "45.12");
615
616 let mut s = core::mem::MaybeUninit::uninit();
617 slint_shared_string_from_number(s.as_mut_ptr(), -1325466.);
618 assert_eq!(s.assume_init(), "-1325466");
619
620 let mut s = core::mem::MaybeUninit::uninit();
621 slint_shared_string_from_number(s.as_mut_ptr(), 0.);
622 assert_eq!(s.assume_init(), "0");
623
624 let mut s = core::mem::MaybeUninit::uninit();
625 slint_shared_string_from_number(
626 s.as_mut_ptr(),
627 ((1235.82756f32 * 1000f32).round() / 1000f32) as _,
628 );
629 assert_eq!(s.assume_init(), "1235.828");
630 }
631 }
632
633 #[unsafe(no_mangle)]
634 pub extern "C" fn slint_shared_string_from_number_fixed(
635 out: &mut SharedString,
636 n: f64,
637 digits: usize,
638 ) {
639 *out = shared_string_from_number_fixed(n, digits);
640 }
641
642 #[test]
643 fn test_slint_shared_string_from_number_fixed() {
644 let mut s = SharedString::default();
645
646 let num = 12345.6789;
647
648 slint_shared_string_from_number_fixed(&mut s, num, 0);
649 assert_eq!(s.as_str(), "12346");
650
651 slint_shared_string_from_number_fixed(&mut s, num, 1);
652 assert_eq!(s.as_str(), "12345.7");
653
654 slint_shared_string_from_number_fixed(&mut s, num, 6);
655 assert_eq!(s.as_str(), "12345.678900");
656
657 let num = -12345.6789;
658
659 slint_shared_string_from_number_fixed(&mut s, num, 0);
660 assert_eq!(s.as_str(), "-12346");
661
662 slint_shared_string_from_number_fixed(&mut s, num, 1);
663 assert_eq!(s.as_str(), "-12345.7");
664
665 slint_shared_string_from_number_fixed(&mut s, num, 6);
666 assert_eq!(s.as_str(), "-12345.678900");
667
668 slint_shared_string_from_number_fixed(&mut s, 1.23E+20_f64, 2);
669 assert_eq!(s.as_str(), "123000000000000000000.00");
670
671 slint_shared_string_from_number_fixed(&mut s, 1.23E-10_f64, 2);
672 assert_eq!(s.as_str(), "0.00");
673
674 slint_shared_string_from_number_fixed(&mut s, 2.34, 1);
675 assert_eq!(s.as_str(), "2.3");
676
677 slint_shared_string_from_number_fixed(&mut s, 2.35, 1);
678 assert_eq!(s.as_str(), "2.4");
679
680 slint_shared_string_from_number_fixed(&mut s, 2.55, 1);
681 assert_eq!(s.as_str(), "2.5");
682 }
683
684 #[unsafe(no_mangle)]
685 pub extern "C" fn slint_shared_string_from_number_precision(
686 out: &mut SharedString,
687 n: f64,
688 precision: usize,
689 ) {
690 *out = shared_string_from_number_precision(n, precision);
691 }
692
693 #[test]
694 fn test_slint_shared_string_from_number_precision() {
695 let mut s = SharedString::default();
696
697 let num = 5.123456;
698
699 slint_shared_string_from_number_precision(&mut s, num, 0);
700 assert_eq!(s.as_str(), "5.123456");
701
702 slint_shared_string_from_number_precision(&mut s, num, 5);
703 assert_eq!(s.as_str(), "5.1235");
704
705 slint_shared_string_from_number_precision(&mut s, num, 2);
706 assert_eq!(s.as_str(), "5.1");
707
708 slint_shared_string_from_number_precision(&mut s, num, 1);
709 assert_eq!(s.as_str(), "5");
710
711 let num = 0.000123;
712
713 slint_shared_string_from_number_precision(&mut s, num, 0);
714 assert_eq!(s.as_str(), "0.000123");
715
716 slint_shared_string_from_number_precision(&mut s, num, 5);
717 assert_eq!(s.as_str(), "0.00012300");
718
719 slint_shared_string_from_number_precision(&mut s, num, 2);
720 assert_eq!(s.as_str(), "0.00012");
721
722 slint_shared_string_from_number_precision(&mut s, num, 1);
723 assert_eq!(s.as_str(), "0.0001");
724
725 let num = 1234.5;
726
727 slint_shared_string_from_number_precision(&mut s, num, 1);
728 assert_eq!(s.as_str(), "1e3");
729
730 slint_shared_string_from_number_precision(&mut s, num, 2);
731 assert_eq!(s.as_str(), "1.2e3");
732
733 slint_shared_string_from_number_precision(&mut s, num, 6);
734 assert_eq!(s.as_str(), "1234.50");
735
736 let num = -1234.5;
737
738 slint_shared_string_from_number_precision(&mut s, num, 1);
739 assert_eq!(s.as_str(), "-1e3");
740
741 slint_shared_string_from_number_precision(&mut s, num, 2);
742 assert_eq!(s.as_str(), "-1.2e3");
743
744 slint_shared_string_from_number_precision(&mut s, num, 6);
745 assert_eq!(s.as_str(), "-1234.50");
746
747 let num = 0.00000012345;
748
749 slint_shared_string_from_number_precision(&mut s, num, 1);
750 assert_eq!(s.as_str(), "1e-7");
751
752 slint_shared_string_from_number_precision(&mut s, num, 10);
753 assert_eq!(s.as_str(), "1.234500000e-7");
754 }
755
756 #[unsafe(no_mangle)]
760 pub unsafe extern "C" fn slint_shared_string_append(
761 self_: &mut SharedString,
762 bytes: *const c_char,
763 len: usize,
764 ) {
765 let str = core::str::from_utf8(unsafe { core::slice::from_raw_parts(bytes, len) }).unwrap();
766 self_.push_str(str);
767 }
768 #[test]
769 fn test_slint_shared_string_append() {
770 let mut s = SharedString::default();
771 let mut append = |x: &str| unsafe {
772 slint_shared_string_append(&mut s, x.as_bytes().as_ptr(), x.len());
773 };
774 append("Hello");
775 append(", ");
776 append("world");
777 append("");
778 append("!");
779 assert_eq!(s.as_str(), "Hello, world!");
780 }
781
782 #[unsafe(no_mangle)]
783 pub unsafe extern "C" fn slint_shared_string_to_lowercase(
784 out: &mut SharedString,
785 ss: &SharedString,
786 ) {
787 *out = SharedString::from(ss.to_lowercase());
788 }
789 #[test]
790 fn test_slint_shared_string_to_lowercase() {
791 let s = SharedString::from("Hello");
792 let mut out = SharedString::default();
793
794 unsafe {
795 slint_shared_string_to_lowercase(&mut out, &s);
796 }
797 assert_eq!(out.as_str(), "hello");
798 }
799
800 #[unsafe(no_mangle)]
801 pub unsafe extern "C" fn slint_shared_string_to_uppercase(
802 out: &mut SharedString,
803 ss: &SharedString,
804 ) {
805 *out = SharedString::from(ss.to_uppercase());
806 }
807 #[test]
808 fn test_slint_shared_string_to_uppercase() {
809 let s = SharedString::from("Hello");
810 let mut out = SharedString::default();
811
812 unsafe {
813 slint_shared_string_to_uppercase(&mut out, &s);
814 }
815 assert_eq!(out.as_str(), "HELLO");
816 }
817
818 #[unsafe(no_mangle)]
819 pub extern "C" fn slint_shared_string_replace_all(
820 out: &mut SharedString,
821 ss: &SharedString,
822 from: crate::slice::Slice<u8>,
823 to: crate::slice::Slice<u8>,
824 ) {
825 let from = unsafe { core::str::from_utf8_unchecked(from.as_slice()) };
827 let to = unsafe { core::str::from_utf8_unchecked(to.as_slice()) };
828 *out = super::shared_string_replace_all(ss, from, to);
829 }
830 #[test]
831 fn test_slint_shared_string_replace_all() {
832 let s = SharedString::from("Hello");
833 let from = SharedString::from("l");
834 let to = SharedString::from("L");
835 let mut out = SharedString::default();
836
837 slint_shared_string_replace_all(
838 &mut out,
839 &s,
840 crate::slice::Slice::from_slice(from.as_bytes()),
841 crate::slice::Slice::from_slice(to.as_bytes()),
842 );
843 assert_eq!(out.as_str(), "HeLLo");
844 }
845}
846
847#[cfg(feature = "serde")]
848#[test]
849fn test_serialize_deserialize_sharedstring() {
850 let v = SharedString::from("data");
851 let serialized = serde_json::to_string(&v).unwrap();
852 let deserialized: SharedString = serde_json::from_str(&serialized).unwrap();
853 assert_eq!(v, deserialized);
854}
855
856#[cfg(feature = "serde")]
857#[test]
858fn test_serialize_deserialize_sharedstring_from_reader() {
859 let v = SharedString::from("data");
860 let serialized = serde_json::to_string(&v).unwrap();
861 let deserialized: SharedString = serde_json::from_reader(serialized.as_bytes()).unwrap();
862 assert_eq!(v, deserialized);
863}
864
865#[test]
866fn test_extend_from_chars() {
867 let mut s = SharedString::from("x");
868 s.extend(core::iter::repeat_n('a', 4).chain(core::iter::once('🍌')));
869 assert_eq!(s.as_str(), "xaaaa🍌");
870}
871
872#[test]
873fn test_collect_from_chars() {
874 let s: SharedString = core::iter::repeat_n('a', 4).chain(core::iter::once('🍌')).collect();
875 assert_eq!(s.as_str(), "aaaa🍌");
876}