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