@@ -677,6 +677,132 @@ 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: 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+ }
680806}
681807
682808impl < LenT : LenType , const N : usize > Default for String < N , LenT > {
@@ -1240,4 +1366,103 @@ mod tests {
12401366 let formatted = format ! ( 2 ; "123" ) ;
12411367 assert_eq ! ( formatted, Err ( core:: fmt:: Error ) ) ;
12421368 }
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+ }
12431468}
0 commit comments