Skip to content

Commit d8ae9c8

Browse files
committed
Add initial NSMutableAttributedString
1 parent a789187 commit d8ae9c8

File tree

4 files changed

+130
-1
lines changed

4 files changed

+130
-1
lines changed

objc2-foundation/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
2222
* Added `NSUUID` object.
2323
* Added `NSMutableString` object.
2424
* Added basic `NSAttributedString` object.
25+
* Added basic `NSMutableAttributedString` object.
2526

2627
### Changed
2728
* **BREAKING**: Removed the following helper traits in favor of inherent

objc2-foundation/src/attributed_string.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ use objc2::msg_send;
44
use objc2::rc::{DefaultId, Id, Shared};
55
use objc2::runtime::Object;
66

7-
use crate::{NSCopying, NSDictionary, NSObject, NSString};
7+
use crate::{
8+
NSCopying, NSDictionary, NSMutableAttributedString, NSMutableCopying, NSObject, NSString,
9+
};
810

911
object! {
1012
/// A string that has associated attributes for portions of its text.
@@ -114,6 +116,10 @@ unsafe impl NSCopying for NSAttributedString {
114116
type Output = NSAttributedString;
115117
}
116118

119+
unsafe impl NSMutableCopying for NSAttributedString {
120+
type Output = NSMutableAttributedString;
121+
}
122+
117123
#[cfg(test)]
118124
mod tests {
119125
use alloc::string::ToString;

objc2-foundation/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub use self::copying::{NSCopying, NSMutableCopying};
4747
pub use self::data::{NSData, NSMutableData};
4848
pub use self::dictionary::NSDictionary;
4949
pub use self::enumerator::{NSEnumerator, NSFastEnumeration, NSFastEnumerator};
50+
pub use self::mutable_attributed_string::NSMutableAttributedString;
5051
pub use self::mutable_string::NSMutableString;
5152
pub use self::object::NSObject;
5253
pub use self::process_info::NSProcessInfo;
@@ -74,6 +75,7 @@ mod copying;
7475
mod data;
7576
mod dictionary;
7677
mod enumerator;
78+
mod mutable_attributed_string;
7779
mod mutable_string;
7880
mod object;
7981
mod process_info;
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use core::ptr::NonNull;
2+
3+
use objc2::msg_send;
4+
use objc2::rc::{DefaultId, Id, Owned, Shared};
5+
6+
use crate::{NSAttributedString, NSCopying, NSMutableCopying, NSString};
7+
8+
object! {
9+
/// A mutable string that has associated attributes.
10+
///
11+
/// See [Apple's documentation](https://developer.apple.com/documentation/foundation/nsmutableattributedstring?language=objc).
12+
unsafe pub struct NSMutableAttributedString: NSAttributedString;
13+
}
14+
15+
// TODO: SAFETY
16+
unsafe impl Sync for NSMutableAttributedString {}
17+
unsafe impl Send for NSMutableAttributedString {}
18+
19+
/// Creating mutable attributed strings.
20+
impl NSMutableAttributedString {
21+
unsafe_def_fn! {
22+
/// Construct an empty mutable attributed string.
23+
pub fn new -> Owned;
24+
}
25+
26+
// TODO: new_with_attributes
27+
28+
#[doc(alias = "initWithString:")]
29+
pub fn from_nsstring(string: &NSString) -> Id<Self, Owned> {
30+
unsafe {
31+
let obj: *mut Self = msg_send![Self::class(), alloc];
32+
let obj: *mut Self = msg_send![obj, initWithString: string];
33+
Id::new(NonNull::new_unchecked(obj))
34+
}
35+
}
36+
37+
#[doc(alias = "initWithAttributedString:")]
38+
pub fn from_attributed_nsstring(attributed_string: &NSAttributedString) -> Id<Self, Owned> {
39+
unsafe {
40+
let obj: *mut Self = msg_send![Self::class(), alloc];
41+
let obj: *mut Self = msg_send![obj, initWithAttributedString: attributed_string];
42+
Id::new(NonNull::new_unchecked(obj))
43+
}
44+
}
45+
}
46+
47+
/// Modifying the attributed string.
48+
impl NSMutableAttributedString {
49+
// TODO
50+
// - mutableString
51+
// - replaceCharactersInRange:withString:
52+
// - setAttributes:range:
53+
54+
/// Replaces the entire attributed string.
55+
#[doc(alias = "setAttributedString:")]
56+
pub fn replace(&mut self, attributed_string: &NSAttributedString) {
57+
unsafe { msg_send![self, setAttributedString: attributed_string] }
58+
}
59+
}
60+
61+
impl DefaultId for NSMutableAttributedString {
62+
type Ownership = Owned;
63+
64+
#[inline]
65+
fn default_id() -> Id<Self, Self::Ownership> {
66+
Self::new()
67+
}
68+
}
69+
70+
unsafe impl NSCopying for NSMutableAttributedString {
71+
type Ownership = Shared;
72+
type Output = NSAttributedString;
73+
}
74+
75+
unsafe impl NSMutableCopying for NSMutableAttributedString {
76+
type Output = NSMutableAttributedString;
77+
}
78+
79+
#[cfg(test)]
80+
mod tests {
81+
use alloc::string::ToString;
82+
use objc2::rc::autoreleasepool;
83+
84+
use super::*;
85+
86+
#[test]
87+
fn test_new() {
88+
let s = NSAttributedString::new();
89+
assert_eq!(&s.string().to_string(), "");
90+
}
91+
92+
#[test]
93+
fn test_string_bound_to_attributed() {
94+
let attr_s = {
95+
let source = NSString::from_str("Hello world!");
96+
NSAttributedString::from_nsstring(&source)
97+
};
98+
let s = autoreleasepool(|_| attr_s.string());
99+
assert_eq!(s.len(), 12);
100+
}
101+
102+
#[test]
103+
fn test_from_nsstring() {
104+
let s = NSAttributedString::from_nsstring(&NSString::from_str("abc"));
105+
assert_eq!(&s.string().to_string(), "abc");
106+
}
107+
108+
#[test]
109+
fn test_copy() {
110+
let s1 = NSAttributedString::from_nsstring(&NSString::from_str("abc"));
111+
let s2 = s1.copy();
112+
// NSAttributedString also performs this optimization
113+
assert_eq!(s1.as_ptr(), s2.as_ptr());
114+
assert!(s2.is_kind_of(NSAttributedString::class()));
115+
116+
// let s3 = s1.mutable_copy();
117+
// assert_ne!(s1.as_ptr(), s3.as_ptr() as *mut NSAttributedString);
118+
// assert!(s3.is_kind_of(NSMutableAttributedString::class()));
119+
}
120+
}

0 commit comments

Comments
 (0)