@@ -677,6 +677,132 @@ impl<LenT: LenType, S: StringStorage + ?Sized> StringInner<LenT, S> {
677
677
pub fn clear ( & mut self ) {
678
678
self . vec . clear ( ) ;
679
679
}
680
+
681
+ /// Inserts a character into this `String` at a byte position.
682
+ ///
683
+ /// This is an *O*(*n*) operation as it requires copying every element in the
684
+ /// buffer.
685
+ ///
686
+ /// # Panics
687
+ ///
688
+ /// Panics if `idx` is larger than the `String`'s length, or if it does not
689
+ /// lie on a [`char`] boundary.
690
+ ///
691
+ /// # Examples
692
+ ///
693
+ /// ```
694
+ /// use heapless::String;
695
+ ///
696
+ /// let mut s: String<4> = String::new();
697
+ ///
698
+ /// s.insert(0, 'f').unwrap();
699
+ /// s.insert(1, 'o').unwrap();
700
+ /// s.insert(2, 'o').unwrap();
701
+ ///
702
+ /// assert_eq!("foo", s);
703
+ /// # Ok::<(), heapless::CapacityError>(())
704
+ /// ```
705
+ #[ inline]
706
+ pub fn insert ( & mut self , idx : usize , ch : char ) -> Result < ( ) , CapacityError > {
707
+ assert ! ( self . is_char_boundary( idx) , "index must be a char boundary" ) ;
708
+
709
+ let len = self . len ( ) ;
710
+ let ch_len = ch. len_utf8 ( ) ;
711
+
712
+ // Check if there is enough capacity
713
+ if len + ch_len > self . capacity ( ) {
714
+ return Err ( CapacityError ) ;
715
+ }
716
+
717
+ // SAFETY: Move the bytes starting from `idx` to their new location `ch_len`
718
+ // bytes ahead. This is safe because we checked `len + ch_len` does not
719
+ // exceed the capacity and `idx` is a char boundary
720
+ unsafe {
721
+ let ptr = self . vec . as_mut_ptr ( ) ;
722
+ core:: ptr:: copy ( ptr. add ( idx) , ptr. add ( idx + ch_len) , len - idx) ;
723
+ }
724
+
725
+ // SAFETY: Copy the encoded character into the vacated region if
726
+ // `idx != len`, or into the uninitialized spare capacity otherwise.
727
+ unsafe {
728
+ // 4 bytes is the maximum length of a UTF-8 character
729
+ let mut buf = [ 0u8 ; 4 ] ;
730
+ let encoded = ch. encode_utf8 ( & mut buf) ;
731
+ core:: ptr:: copy_nonoverlapping (
732
+ encoded. as_ptr ( ) ,
733
+ self . vec . as_mut_ptr ( ) . add ( idx) ,
734
+ ch_len,
735
+ ) ;
736
+ }
737
+
738
+ // SAFETY: Update the length to include the newly added bytes.
739
+ unsafe {
740
+ self . vec . set_len ( len + ch_len) ;
741
+ }
742
+
743
+ Ok ( ( ) )
744
+ }
745
+
746
+ /// Inserts a string slice into this `String` at a byte position.
747
+ ///
748
+ /// This is an *O*(*n*) operation as it requires copying every element in the
749
+ /// buffer.
750
+ ///
751
+ /// # Panics
752
+ ///
753
+ /// Panics if `idx` is larger than the `String`'s length, or if it does not
754
+ /// lie on a [`char`] boundary.
755
+ ///
756
+ /// # Examples
757
+ ///
758
+ /// ```
759
+ /// use heapless::String;
760
+ ///
761
+ /// let mut s: String<8> = String::try_from("bar")?;
762
+ ///
763
+ /// s.insert_str(0, "foo")?;
764
+ ///
765
+ /// assert_eq!("foobar", s);
766
+ /// # Ok::<(), heapless::CapacityError>(())
767
+ /// ```
768
+ #[ inline]
769
+ pub fn insert_str ( & mut self , idx : usize , string : & str ) -> Result < ( ) , CapacityError > {
770
+ assert ! ( self . is_char_boundary( idx) , "index must be a char boundary" ) ;
771
+
772
+ let len = self . len ( ) ;
773
+ let string_len = string. len ( ) ;
774
+
775
+ // Check if there is enough capacity
776
+ if len + string_len > self . capacity ( ) {
777
+ return Err ( CapacityError ) ;
778
+ }
779
+
780
+ // SAFETY: Move the bytes starting from `idx` to their new location
781
+ // `string_len` bytes ahead. This is safe because we checked there is
782
+ // sufficient capacity, and `idx` is a char boundary.
783
+ unsafe {
784
+ let ptr = self . vec . as_mut_ptr ( ) ;
785
+ core:: ptr:: copy ( ptr. add ( idx) , ptr. add ( idx + string_len) , len - idx) ;
786
+ }
787
+
788
+ // SAFETY: Copy the new string slice into the vacated region if `idx != len`,
789
+ // or into the uninitialized spare capacity otherwise. The borrow checker
790
+ // ensures that the source and destination do not overlap.
791
+ unsafe {
792
+ core:: ptr:: copy_nonoverlapping (
793
+ string. as_ptr ( ) ,
794
+ self . vec . as_mut_ptr ( ) . add ( idx) ,
795
+ string_len,
796
+ ) ;
797
+ }
798
+
799
+ // SAFETY: Update the length to include the newly added bytes.
800
+ unsafe {
801
+ self . vec . set_len ( len + string_len) ;
802
+ }
803
+
804
+ Ok ( ( ) )
805
+ }
680
806
}
681
807
682
808
impl < LenT : LenType , const N : usize > Default for String < N , LenT > {
@@ -1240,4 +1366,103 @@ mod tests {
1240
1366
let formatted = format ! ( 2 ; "123" ) ;
1241
1367
assert_eq ! ( formatted, Err ( core:: fmt:: Error ) ) ;
1242
1368
}
1369
+
1370
+ #[ test]
1371
+ fn insert ( ) {
1372
+ let mut s: String < 6 > = String :: try_from ( "123" ) . unwrap ( ) ;
1373
+ assert ! ( s. insert( 0 , 'a' ) . is_ok( ) ) ;
1374
+ assert_eq ! ( s, "a123" ) ;
1375
+
1376
+ assert ! ( s. insert( 2 , 'b' ) . is_ok( ) ) ;
1377
+ assert_eq ! ( s, "a1b23" ) ;
1378
+
1379
+ assert ! ( s. insert( s. len( ) , '4' ) . is_ok( ) ) ;
1380
+ assert_eq ! ( s, "a1b234" ) ;
1381
+
1382
+ assert_eq ! ( s. len( ) , 6 ) ;
1383
+ assert ! ( s. insert( 0 , 'd' ) . is_err( ) ) ;
1384
+ assert_eq ! ( s, "a1b234" ) ;
1385
+ }
1386
+
1387
+ #[ test]
1388
+ fn insert_unicode ( ) {
1389
+ let mut s: String < 21 > = String :: try_from ( "ĝėēƶ" ) . unwrap ( ) ;
1390
+ let idx = s. find ( "ė" ) . unwrap ( ) ;
1391
+
1392
+ assert ! ( s. insert( idx, '🦀' ) . is_ok( ) ) ;
1393
+ assert_eq ! ( s, "ĝ🦀ėēƶ" ) ;
1394
+
1395
+ s. insert ( s. len ( ) , '🦀' ) . unwrap ( ) ;
1396
+ assert_eq ! ( s, "ĝ🦀ėēƶ🦀" ) ;
1397
+
1398
+ s. insert ( 0 , '🦀' ) . unwrap ( ) ;
1399
+ assert_eq ! ( s, "🦀ĝ🦀ėēƶ🦀" ) ;
1400
+
1401
+ assert_eq ! ( s. len( ) , 20 ) ;
1402
+ assert_eq ! ( 'ƶ' . len_utf8( ) , 2 ) ;
1403
+ assert ! ( s. insert( 0 , 'ƶ' ) . is_err( ) ) ;
1404
+ assert_eq ! ( s, "🦀ĝ🦀ėēƶ🦀" ) ;
1405
+ }
1406
+
1407
+ #[ test]
1408
+ #[ should_panic = "index must be a char boundary" ]
1409
+ fn insert_at_non_char_boundary_panics ( ) {
1410
+ let mut s: String < 8 > = String :: try_from ( "é" ) . unwrap ( ) ;
1411
+ _ = s. insert ( 1 , 'a' ) ;
1412
+ }
1413
+
1414
+ #[ test]
1415
+ #[ should_panic = "index must be a char boundary" ]
1416
+ fn insert_beyond_length_panics ( ) {
1417
+ let mut s: String < 8 > = String :: try_from ( "a" ) . unwrap ( ) ;
1418
+ _ = s. insert ( 2 , 'a' ) ;
1419
+ }
1420
+
1421
+ #[ test]
1422
+ fn insert_str ( ) {
1423
+ let mut s: String < 14 > = String :: try_from ( "bar" ) . unwrap ( ) ;
1424
+ assert ! ( s. insert_str( 0 , "foo" ) . is_ok( ) ) ;
1425
+ assert_eq ! ( s, "foobar" ) ;
1426
+
1427
+ assert ! ( s. insert_str( 3 , "baz" ) . is_ok( ) ) ;
1428
+ assert_eq ! ( s, "foobazbar" ) ;
1429
+
1430
+ assert ! ( s. insert_str( s. len( ) , "end" ) . is_ok( ) ) ;
1431
+ assert_eq ! ( s, "foobazbarend" ) ;
1432
+
1433
+ assert_eq ! ( s. len( ) , 12 ) ;
1434
+ assert ! ( s. insert_str( 0 , "def" ) . is_err( ) ) ;
1435
+ assert_eq ! ( s, "foobazbarend" ) ;
1436
+ }
1437
+
1438
+ #[ test]
1439
+ fn insert_str_unicode ( ) {
1440
+ let mut s: String < 20 > = String :: try_from ( "Héllô" ) . unwrap ( ) ;
1441
+ let idx = s. find ( "lô" ) . unwrap ( ) ;
1442
+
1443
+ assert ! ( s. insert_str( idx, "p, í'm " ) . is_ok( ) ) ;
1444
+ assert_eq ! ( s, "Hélp, í'm lô" ) ;
1445
+
1446
+ assert ! ( s. insert_str( s. len( ) , "st" ) . is_ok( ) ) ;
1447
+ assert_eq ! ( s, "Hélp, í'm lôst" ) ;
1448
+
1449
+ assert_eq ! ( s. len( ) , 17 ) ;
1450
+ assert_eq ! ( "🦀" . len( ) , 4 ) ;
1451
+ assert ! ( s. insert_str( 0 , "🦀" ) . is_err( ) ) ;
1452
+ assert_eq ! ( s, "Hélp, í'm lôst" ) ;
1453
+ }
1454
+
1455
+ #[ test]
1456
+ #[ should_panic = "index must be a char boundary" ]
1457
+ fn insert_str_at_non_char_boundary_panics ( ) {
1458
+ let mut s: String < 8 > = String :: try_from ( "é" ) . unwrap ( ) ;
1459
+ _ = s. insert_str ( 1 , "a" ) ;
1460
+ }
1461
+
1462
+ #[ test]
1463
+ #[ should_panic = "index must be a char boundary" ]
1464
+ fn insert_str_beyond_length_panics ( ) {
1465
+ let mut s: String < 8 > = String :: try_from ( "a" ) . unwrap ( ) ;
1466
+ _ = s. insert_str ( 2 , "a" ) ;
1467
+ }
1243
1468
}
0 commit comments