-
Notifications
You must be signed in to change notification settings - Fork 38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement String
-like wrapper around FuriString
#50
Conversation
d291a24
to
b726e0e
Compare
std::string::String
-like wrapper around FuriString
String
-like and str
-like wrappers around FuriString
8644efb
to
8abae06
Compare
String
-like and str
-like wrappers around FuriString
String
-like wrapper around FuriString
80d95b3
to
1f3be0a
Compare
22c716d
to
4c22e96
Compare
The PR currently focuses on providing newly-constructed, Rust-owned impl String {
pub(crate) unsafe fn from_borrowed_mut<'s>(raw: *mut FuriString) -> &'s mut String {
todo!("pointer magic")
}
} which is only used from inside other wrapper types, enabling them to implement APIs like: pub struct OtherWrapper(*mut sys::SomeType);
impl OtherWrapper {
pub fn name_mut(&mut self) -> &mut furi::String {
unsafe { furi::String::from_borrowed_mut((*self.0).name) }
}
} |
Rebased on |
Pushed a test suite (adapted from https://github.com/rust-lang/rust/blob/master/library/alloc/tests/string.rs). The uncommented tests are the ones for APIs I have currently implemented. The tests do all pass, but I've seen a few occasional panics that I haven't been able to pin down yet. |
Force-pushed to separate the upstream tests from my changes. |
Force-pushed to add some more trait impls. |
Almost all the remaining APIs of
In particular, I'm trying to decide whether to provide a |
It's been a while since I've thought about this, but I think my direction of thinking was:
I suspect we could even support an iterator over unicode scalars built on |
Rebased on |
- Source: https://github.com/rust-lang/rust - Revision: 7b58193f90185a5730732a727362576a9bdca26b - Path: rust/library/alloc/tests/string.rs - License: MIT
Also removes the tests that are not relevant to `FuriString`.
Force-pushed to rename |
- Source: https://github.com/rust-lang/rust - Revision: 7b58193f90185a5730732a727362576a9bdca26b - Path: rust/library/alloc/tests/str.rs - License: MIT
Also removes the tests that are not relevant to `FuriString`.
I've implemented a bunch of the pattern-based At this point I suspect we are approaching diminishing returns. I can continue to slowly implement additional methods and get more of the tests uncommented and passing, but that doesn't necessarily have to block this PR. I'm going to pause that work and ensure that I can use |
Looking great! My vote is to get the current work merged in (it's already far superior to |
Okay, I think that's everything 🙂 |
This enables us to improve the `Debug` and `Display` impls.
Okay, having committed the new file, now that's everything 😂 |
Thanks for the PR! This one was big one and will be extremely useful! |
@str4d Since you've by far the most active contributor to this repository, I've invited you to @flipperzero-rs/maintainers. This should grant you fairly broad permission to push, merge, etc. No obligation to accept, but it would be good to have another pair of eyes watching things since I'm not always as active as I would like. |
std::string::String
methods to be implemented:String::new() -> String
String::with_capacity(capacity: usize) -> String
String::from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error>
String::from_utf8_lossy(v: &[u8]) -> Cow<'_, str>
String::from_utf16(v: &[u16]) -> Result<String, FromUtf16Error>
String::from_utf16_lossy(v: &[u16]) -> String
String::into_raw_parts(self) -> (*mut u8, usize, usize)
FuriString
. We could maybe expose*mut sys::FuriString
?String::from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> String
unsafe
) if we want to leave*mut sys::FuriString
exposed.String::from_utf8_unchecked(bytes: Vec<u8>) -> String
FuriString
.String::into_bytes(self) -> Vec<u8>
FuriString
(we aren't storing the string internally as aVec<u8>
, so it's better to just callString::to_bytes().to_owned()
).String::as_str(&self) -> &str
String::as_c_str(&self) -> &CStr
String::as_mut_str(&mut self) -> &mut str
String::push_str(&mut self, string: &str)
String::capacity(&self) -> usize
String::reserve(&mut self, additional: usize)
String::reserve_exact(&mut self, additional: usize)
String::try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError>
FuriString
allocations.String::try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError>
FuriString
allocations.String::shrink_to_fit(&mut self)
String::shrink_to(&mut self, min_capacity: usize)
String::push(&mut self, ch: char)
String::as_bytes(&self) -> &[u8]
String::to_bytes
because it's a bit more expensive.String::to_bytes_with_nul
for parity withCString
.String::truncate(&mut self, new_len: usize)
String::pop(&mut self) -> Option<char>
String::remove(&mut self, idx: usize) -> char
String::retain<F>(&mut self, mut f: F) where F: FnMut(char) -> bool
String::insert(&mut self, idx: usize, ch: char)
String::insert_str(&mut self, idx: usize, string: &str)
String::as_mut_vec(&mut self) -> &mut Vec<u8>
FuriString
.String::len(&self) -> usize
String::is_empty(&self) -> bool
String::split_off(&mut self, at: usize) -> String
String::clear(&mut self)
String::drain<R>(&mut self, range: R) -> Drain<'_> where R: RangeBounds<usize>
String::replace_range<R>(&mut self, range: R, replace_with: &str) where R: RangeBounds<usize>
String::into_boxed_str(self) -> Box<str>
FuriString
.impl Clone for String
impl FromIterator<char> for String
impl<'a> FromIterator<&'a char> for String
impl<'a> FromIterator<&'a str> for String
impl FromIterator<String> for String
impl FromIterator<Box<str>> for String
impl<'a> FromIterator<Cow<'a, str>> for String
impl Extend<char> for String
impl<'a> Extend<&'a char> for String
impl<'a> Extend<&'a str> for String
impl Extend<Box<str>> for String
impl Extend<String> for String
impl<'a> Extend<Cow<'a, str>> for String
impl PartialEq for String
impl Eq for String
impl PartialOrd for String
impl Ord for String
impl Default for String
impl fmt::Display for String
impl fmt::Debug for String
impl hash::Hash for String
impl Add<&str> for String
impl AddAssign<&str> for String
impl ops::Index<ops::Range<usize>> for String
impl ops::Index<ops::RangeTo<usize>> for String
impl ops::Index<ops::RangeFrom<usize>> for String
impl ops::Index<ops::RangeFull> for String
impl ops::Index<ops::RangeInclusive<usize>> for String
impl ops::Index<ops::RangeToInclusive<usize>> for String
impl ops::IndexMut<ops::Range<usize>> for String
impl ops::IndexMut<ops::RangeTo<usize>> for String
impl ops::IndexMut<ops::RangeFrom<usize>> for String
impl ops::IndexMut<ops::RangeFull> for String
impl ops::IndexMut<ops::RangeInclusive<usize>> for String
impl ops::IndexMut<ops::RangeToInclusive<usize>> for String
impl ops::Deref for String
impl ops::DerefMut for String
impl FromStr for String
impl AsRef<str> for String
impl AsRef<CStr> for String
impl AsMut<str> for String
impl AsRef<[u8]> for String
impl From<&str> for String
impl From<&mut str> for String
impl From<&String> for String
impl From<Box<str>> for String
impl From<String> for Box<str>
FuriString
.impl<'a> From<Cow<'a, str>> for String
impl<'a> From<String> for Cow<'a, str>
FuriString
.impl<'a> From<&'a String> for Cow<'a, str>
FuriString
.impl<'a> FromIterator<String> for Cow<'a, str>
FuriString
.impl From<String> for Vec<u8>
FuriString
.impl fmt::Write for String
impl From<char> for String
str
methods to be implemented:(seestr::len(&self) -> usize
String
)(seestr::is_empty(&self) -> bool
String
)str::is_char_boundary(&self, index: usize) -> bool
str::floor_char_boundary(&self, index: usize) -> usize
str::ceil_char_boundary(&self, index: usize) -> usize
(seestr::as_bytes(&self) -> &[u8]
String
)str::as_bytes_mut(&mut self) -> &mut [u8]
str::as_ptr(&self) -> *const u8
str::as_mut_ptr(&mut self) -> *mut u8
str::get<I: ~const SliceIndex<str>>(&self, i: I) -> Option<&I::Output>
str::get_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> Option<&mut I::Output>
str::get_unchecked<I: ~const SliceIndex<str>>(&self, i: I) -> &I::Output
str::get_unchecked_mut<I: ~const SliceIndex<str>>(&mut self, i: I) -> &mut I::Output
(deprecated)str::slice_unchecked(&self, begin: usize, end: usize) -> &str
(deprecated)str::slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str
str::split_at(&self, mid: usize) -> (&str, &str)
str::split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str)
str::chars(&self) -> Chars<'_>
FuriString::chars_lossy
because it inserts replacement characters.str::char_indices(&self) -> CharIndices<'_>
FuriString::chars_lossy
because it inserts replacement characters.str::bytes(&self) -> Bytes<'_>
str::split_whitespace(&self) -> SplitWhitespace<'_>
str::split_ascii_whitespace(&self) -> SplitAsciiWhitespace<'_>
str::lines(&self) -> Lines<'_>
(deprecated)str::lines_any(&self) -> LinesAny<'_>
str::encode_utf16(&self) -> EncodeUtf16<'_>
str::contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
str::starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
str::ends_with<'a, P>(&'a self, pat: P) -> bool
str::find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>
str::rfind<'a, P>(&'a self, pat: P) -> Option<usize>
str::split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>
str::split_inclusive<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitInclusive<'a, P>
str::rsplit<'a, P>(&'a self, pat: P) -> RSplit<'a, P>
str::split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>
str::rsplit_terminator<'a, P>(&'a self, pat: P) -> RSplitTerminator<'a, P>
str::splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P>
str::rsplitn<'a, P>(&'a self, n: usize, pat: P) -> RSplitN<'a, P>
str::split_once<'a, P: Pattern<'a>>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)>
str::rsplit_once<'a, P>(&'a self, delimiter: P) -> Option<(&'a str, &'a str)>
str::matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>
str::rmatches<'a, P>(&'a self, pat: P) -> RMatches<'a, P>
str::match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>
str::rmatch_indices<'a, P>(&'a self, pat: P) -> RMatchIndices<'a, P>
str::trim(&self) -> &str
str::trim_start(&self) -> &str
str::trim_end(&self) -> &str
(deprecated)str::trim_left(&self) -> &str
(deprecated)str::trim_right(&self) -> &str
str::trim_matches<'a, P>(&'a self, pat: P) -> &'a str
str::trim_start_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
str::strip_prefix<'a, P: Pattern<'a>>(&'a self, prefix: P) -> Option<&'a str>
bool
.str::strip_suffix<'a, P: Pattern<'a>>(&'a self, suffix: P) -> Option<&'a str>
bool
.str::trim_end_matches<'a, P>(&'a self, pat: P) -> &'a str
(deprecated)str::trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str
(deprecated)str::trim_right_matches<'a, P>(&'a self, pat: P) -> &'a str
str::parse<F: FromStr>(&self) -> Result<F, F::Err>
str::is_ascii(&self) -> bool
str::eq_ignore_ascii_case(&self, other: &str) -> bool
str::make_ascii_uppercase(&mut self)
str::make_ascii_lowercase(&mut self)
str::escape_debug(&self) -> EscapeDebug<'_>
str::escape_default(&self) -> EscapeDefault<'_>
str::escape_unicode(&self) -> EscapeUnicode<'_>