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