[string] add String::AppendHexBytes() (#5212)

This method appends a given array of bytes in hex representation
(`%02x` style) to a `String` object. This method helps simplify the
`ToString()` methods in simpler types (e.g., `Mac::ExtAddress`).
diff --git a/src/core/common/string.hpp b/src/core/common/string.hpp
index d15d24a..661272e 100644
--- a/src/core/common/string.hpp
+++ b/src/core/common/string.hpp
@@ -212,6 +212,29 @@
         return error;
     }
 
+    /**
+     * This method appends an array of bytes in hex representation (using "%02x" style) to the `String` object.
+     *
+     * @param[in] aBytes    A pointer to buffer containing the bytes to append.
+     * @param[in] aLength   The length of @p aBytes buffer (in bytes).
+     *
+     * @retval OT_ERROR_NONE           Updated the string successfully.
+     * @retval OT_ERROR_NO_BUFS        String could not fit in the storage.
+     *
+     */
+    otError AppendHexBytes(const uint8_t *aBytes, uint16_t aLength)
+    {
+        otError error = OT_ERROR_NONE;
+
+        while (aLength--)
+        {
+            SuccessOrExit(error = Append("%02x", *aBytes++));
+        }
+
+    exit:
+        return error;
+    }
+
 private:
     uint16_t mLength;
     char     mBuffer[kSize];
diff --git a/src/core/mac/mac_types.cpp b/src/core/mac/mac_types.cpp
index a1fa20d..f787322 100644
--- a/src/core/mac/mac_types.cpp
+++ b/src/core/mac/mac_types.cpp
@@ -65,7 +65,11 @@
 
 ExtAddress::InfoString ExtAddress::ToString(void) const
 {
-    return InfoString("%02x%02x%02x%02x%02x%02x%02x%02x", m8[0], m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
+    InfoString string;
+
+    IgnoreError(string.AppendHexBytes(m8, sizeof(ExtAddress)));
+
+    return string;
 }
 
 void ExtAddress::CopyAddress(uint8_t *aDst, const uint8_t *aSrc, CopyByteOrder aByteOrder)
@@ -94,7 +98,11 @@
 
 ExtendedPanId::InfoString ExtendedPanId::ToString(void) const
 {
-    return InfoString("%02x%02x%02x%02x%02x%02x%02x%02x", m8[0], m8[1], m8[2], m8[3], m8[4], m8[5], m8[6], m8[7]);
+    InfoString string;
+
+    IgnoreError(string.AppendHexBytes(m8, sizeof(ExtendedPanId)));
+
+    return string;
 }
 
 uint8_t NameData::CopyTo(char *aBuffer, uint8_t aMaxSize) const
diff --git a/src/core/net/ip6_address.cpp b/src/core/net/ip6_address.cpp
index 7b59f28..c6ceea3 100644
--- a/src/core/net/ip6_address.cpp
+++ b/src/core/net/ip6_address.cpp
@@ -148,8 +148,11 @@
 
 InterfaceIdentifier::InfoString InterfaceIdentifier::ToString(void) const
 {
-    return InfoString("%02x%02x%02x%02x%02x%02x%02x%02x", mFields.m8[0], mFields.m8[1], mFields.m8[2], mFields.m8[3],
-                      mFields.m8[4], mFields.m8[5], mFields.m8[6], mFields.m8[7]);
+    InfoString string;
+
+    IgnoreError(string.AppendHexBytes(mFields.m8, kSize));
+
+    return string;
 }
 
 //---------------------------------------------------------------------------------------------------------------------