-
Notifications
You must be signed in to change notification settings - Fork 36
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement
std::string::String
-like wrapper around FuriString
- Loading branch information
Showing
2 changed files
with
186 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
pub mod io; | ||
pub mod message_queue; | ||
pub mod string; | ||
pub mod sync; | ||
pub mod thread; | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
//! Furi String primitive. | ||
//! | ||
//! This is similar to Rust's `CString`, but used inside the Flipper Zero SDK. | ||
use core::{ | ||
cmp::Ordering, | ||
convert::Infallible, | ||
ffi::{c_char, CStr}, | ||
fmt, | ||
}; | ||
|
||
#[cfg(feature = "alloc")] | ||
use alloc::ffi::CString; | ||
|
||
use flipperzero_sys as sys; | ||
|
||
/// A Furi string. | ||
// | ||
// This is similar to Rust's [`CString`], but used inside the Flipper Zero SDK. | ||
#[derive(Eq)] | ||
pub struct String(*mut sys::FuriString); | ||
|
||
impl Drop for String { | ||
fn drop(&mut self) { | ||
unsafe { sys::furi_string_free(self.0) }; | ||
} | ||
} | ||
|
||
// Implementations matching `std::string::String`. | ||
impl String { | ||
/// Creates a new empty `String`. | ||
pub fn new() -> Self { | ||
String(unsafe { sys::furi_string_alloc() }) | ||
} | ||
|
||
/// Creates a new empty `String` with at least the specified capacity. | ||
pub fn with_capacity(capacity: usize) -> Self { | ||
let mut s = Self::new(); | ||
s.reserve(capacity); | ||
s | ||
} | ||
|
||
/// Extracts a `CStr` slice containing the entire `String`. | ||
#[must_use] | ||
pub fn as_cstr(&self) -> &CStr { | ||
unsafe { CStr::from_ptr(sys::furi_string_get_cstr(self.0)) } | ||
} | ||
|
||
/// Appends a given `CStr` slice onto the end of this `String`. | ||
pub fn push_cstr(&mut self, string: &CStr) { | ||
unsafe { sys::furi_string_cat_str(self.0, string.as_ptr()) } | ||
} | ||
|
||
/// Reserves capacity for at least `additional` bytes more than the current length. | ||
pub fn reserve(&mut self, additional: usize) { | ||
unsafe { sys::furi_string_reserve(self.0, self.len() + additional) }; | ||
} | ||
|
||
/// Appends the given [`char`] to the end of this `String`. | ||
pub fn push(&mut self, ch: char) { | ||
match ch.len_utf8() { | ||
1 => unsafe { sys::furi_string_push_back(self.0, ch as c_char) }, | ||
_ => unsafe { sys::furi_string_utf8_push(self.0, ch as u32) }, | ||
} | ||
} | ||
|
||
/// Shortens this `String` to the specified length. | ||
/// | ||
/// If `new_len` is greater than the string's current length, this has no effect. | ||
pub fn truncate(&mut self, new_len: usize) { | ||
if new_len < self.len() { | ||
unsafe { sys::furi_string_right(self.0, new_len) }; | ||
} | ||
} | ||
|
||
/// Truncates this `String`, removing all contents. | ||
/// | ||
/// While this means the `String` will have a length of zero, it does not | ||
/// touch its capacity. | ||
pub fn clear(&mut self) { | ||
unsafe { sys::furi_string_reset(self.0) }; | ||
} | ||
} | ||
|
||
// Implementations matching `&str`. | ||
impl String { | ||
/// Returns the length of `self`. | ||
/// | ||
/// This length is in bytes, not [`char`]s or graphemes. In other words, it might not | ||
/// be what a human considers the length of the string. | ||
pub fn len(&self) -> usize { | ||
unsafe { sys::furi_string_size(self.0) } | ||
} | ||
|
||
/// Returns `true` if `self` has a length of zero bytes. | ||
pub fn is_empty(&self) -> bool { | ||
unsafe { sys::furi_string_empty(self.0) } | ||
} | ||
} | ||
|
||
impl Default for String { | ||
fn default() -> Self { | ||
Self::new() | ||
} | ||
} | ||
|
||
impl PartialEq for String { | ||
fn eq(&self, other: &Self) -> bool { | ||
unsafe { sys::furi_string_equal(self.0, other.0) } | ||
} | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
impl PartialEq<CString> for String { | ||
fn eq(&self, other: &CString) -> bool { | ||
unsafe { sys::furi_string_equal_str(self.0, other.as_ptr()) } | ||
} | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
impl PartialEq<String> for CString { | ||
fn eq(&self, other: &String) -> bool { | ||
unsafe { sys::furi_string_equal_str(other.0, self.as_ptr()) } | ||
} | ||
} | ||
|
||
impl PartialEq<&CStr> for String { | ||
fn eq(&self, other: &&CStr) -> bool { | ||
unsafe { sys::furi_string_equal_str(self.0, other.as_ptr()) } | ||
} | ||
} | ||
|
||
impl PartialEq<String> for &CStr { | ||
fn eq(&self, other: &String) -> bool { | ||
unsafe { sys::furi_string_equal_str(other.0, self.as_ptr()) } | ||
} | ||
} | ||
|
||
impl Ord for String { | ||
fn cmp(&self, other: &Self) -> Ordering { | ||
match unsafe { sys::furi_string_cmp(self.0, other.0) } { | ||
..=-1 => Ordering::Less, | ||
0 => Ordering::Equal, | ||
1.. => Ordering::Greater, | ||
} | ||
} | ||
} | ||
|
||
impl PartialOrd for String { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
Some(self.cmp(other)) | ||
} | ||
} | ||
|
||
impl fmt::Write for String { | ||
fn write_str(&mut self, s: &str) -> fmt::Result { | ||
self.reserve(s.len()); | ||
for ch in s.chars() { | ||
self.push(ch); | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn write_char(&mut self, c: char) -> fmt::Result { | ||
self.push(c); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl ufmt::uWrite for String { | ||
type Error = Infallible; | ||
|
||
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> { | ||
self.reserve(s.len()); | ||
for ch in s.chars() { | ||
self.push(ch); | ||
} | ||
Ok(()) | ||
} | ||
|
||
fn write_char(&mut self, c: char) -> Result<(), Self::Error> { | ||
self.push(c); | ||
Ok(()) | ||
} | ||
} |