Loading pageā¦
Rust walkthroughs
Loading pageā¦
uuid::Uuid::as_bytes and to_bytes_le for UUID byte representation?uuid::Uuid::as_bytes returns a reference to the UUID's internal big-endian byte representationāthe standard network byte order format used in RFC 4122 and most UUID specificationsāwhile to_bytes_le returns a new array with bytes rearranged to little-endian order, which matches Microsoft's GUID format and some database storage conventions. The difference matters when interoperating with systems that expect one byte order or the other: as_bytes preserves the human-readable field structure when printed as hex (the first four bytes are the time-low field), while to_bytes_le reorganizes bytes so that the time-low field appears in reverse order, matching how some systems store the UUID in memory or binary protocols.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// as_bytes returns &[u8; 16], borrowed reference
let bytes: &[u8; 16] = uuid.as_bytes();
println!("UUID: {}", uuid);
println!("as_bytes: {:?}", bytes);
// [55, 0e, 84, 00, e2, 9b, 41, d4, a7, 16, 44, 66, 55, 44, 00, 00]
// Note: bytes match the string representation order
// "550e8400" -> [55, 0e, 84, 00]
}as_bytes returns a reference to the internal storage in big-endian order.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// to_bytes_le returns [u8; 16], owned array with different order
let bytes_le: [u8; 16] = uuid.to_bytes_le();
println!("UUID: {}", uuid);
println!("to_bytes_le: {:?}", bytes_le);
// [00, 84, 0e, 55, 9b, e2, d4, 41, a7, 16, 44, 66, 55, 44, 00, 00]
// Compare: first 4 bytes are reversed!
// as_bytes: [55, 0e, 84, 00, ...]
// to_bytes_le: [00, 84, 0e, 55, ...]
}to_bytes_le returns an owned array with time-low field bytes reversed.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("00112233-4455-6677-8899-aabbccddeeff").unwrap();
let be_bytes = uuid.as_bytes();
let le_bytes = uuid.to_bytes_le();
println!("UUID string: {}", uuid);
println!();
// Field breakdown from string: 00112233-4455-6677-8899-aabbccddeeff
// Fields: time_low | time_mid | time_hi_version | clock_seq_node
println!("Field structure:");
println!(" time_low: 00112233");
println!(" time_mid: 4455");
println!(" time_hi_version: 6677");
println!(" clock_seq: 8899");
println!(" node: aabbccddeeff");
println!();
println!("as_bytes (big-endian):");
println!(" {:02x?}", be_bytes);
println!(" First 4 bytes: {:02x?}", &be_bytes[0..4]); // 00, 11, 22, 33
println!(" Matches string order for time_low");
println!();
println!("to_bytes_le (little-endian):");
println!(" {:02x?}", le_bytes);
println!(" First 4 bytes: {:02x?}", &le_bytes[0..4]); // 33, 22, 11, 00
println!(" Reversed for time_low");
}Big-endian preserves string order; little-endian reverses the time fields.
use uuid::Uuid;
fn main() {
// UUID: 00112233-4455-6677-8899-aabbccddeeff
// Fields according to RFC 4122:
// - time_low: 32 bits (00112233)
// - time_mid: 16 bits (4455)
// - time_hi_version: 16 bits (6677)
// - clock_seq_hi: 8 bits (88)
// - clock_seq_low: 8 bits (99)
// - node: 48 bits (aabbccddeeff)
let uuid = Uuid::parse_str("00112233-4455-6677-8899-aabbccddeeff").unwrap();
let bytes = uuid.as_bytes();
println!("Big-endian field positions:");
println!(" time_low: bytes[0..4] = {:02x?}", &bytes[0..4];
println!(" time_mid: bytes[4..6] = {:02x?}", &bytes[4..6];
println!(" time_hi_version: bytes[6..8] = {:02x?}", &bytes[6..8];
println!(" clock_seq: bytes[8..10] = {:02x?}", &bytes[8..10];
println!(" node: bytes[10..16]= {:02x?}", &bytes[10..16];
let bytes_le = uuid.to_bytes_le();
println!();
println!("Little-endian field positions:");
println!(" time_low: bytes[0..4] = {:02x?}", &bytes_le[0..4];
println!(" time_mid: bytes[4..6] = {:02x?}", &bytes_le[4..6];
println!(" time_hi_version: bytes[6..8] = {:02x?}", &bytes_le[6..8];
println!(" clock_seq: bytes[8..10] = {:02x?}", &bytes_le[8..10];
println!(" node: bytes[10..16]= {:02x?}", &bytes_le[10..16];
}The first three fields (time fields) are reversed in little-endian.
use uuid::Uuid;
fn main() {
let original = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// Get little-endian bytes
let le_bytes = original.to_bytes_le();
// Create UUID from little-endian bytes
let from_le = Uuid::from_bytes_le(le_bytes);
// The UUID string representation is the same!
println!("Original: {}", original);
println!("From LE: {}", from_le);
assert_eq!(original, from_le);
// But the byte arrays differ
let be_bytes = original.as_bytes();
println!();
println!("BE bytes: {:02x?}", be_bytes);
println!("LE bytes: {:02x?}", le_bytes);
// Only equal if UUID bytes happen to be symmetric
// (which they rarely are)
}from_bytes_le constructs a UUID from little-endian bytes, reversing back to canonical form.
use uuid::Uuid;
fn main() {
// Microsoft GUIDs use mixed-endian format:
// - First 3 fields (time fields) are little-endian
// - Last 2 fields (clock_seq and node) are big-endian
let uuid = Uuid::parse_str("00112233-4455-6677-8899-aabbccddeeff").unwrap();
// to_bytes_le produces Microsoft GUID byte order
let guid_bytes = uuid.to_bytes_le();
println!("UUID for Microsoft GUID compatibility:");
println!(" UUID string: {}", uuid);
println!(" GUID bytes: {:02x?}", guid_bytes);
// When interfacing with Windows APIs or COM:
// - Use to_bytes_le before passing to GUID-expecting code
// - Use from_bytes_le when receiving GUID bytes
// Simulate receiving GUID bytes from Windows
let received_guid: [u8; 16] = guid_bytes;
let parsed = Uuid::from_bytes_le(received_guid);
println!(" Parsed back: {}", parsed);
assert_eq!(uuid, parsed);
}to_bytes_le matches Microsoft's GUID binary format for Windows interop.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// PostgreSQL uses big-endian (as_bytes)
// BINARY(16) column stores bytes in network order
let pg_bytes = uuid.as_bytes();
// SQL Server uses little-endian (to_bytes_le)
// UNIQUEIDENTIFIER stores bytes in GUID order
let mssql_bytes = uuid.to_bytes_le();
println!("PostgreSQL storage (BE): {:02x?}", pg_bytes);
println!("SQL Server storage (LE): {:02x?}", mssql_bytes);
// For correct sorting and comparison:
// - PostgreSQL: as_bytes order matches string sort order
// - SQL Server: to_bytes_le order matches GUID sort order
// Example: sorting by UUID in PostgreSQL
let uuids = vec
![
Uuid::parse_str("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee").unwrap(),
Uuid::parse_str("00000000-0000-0000-0000-000000000000").unwrap(),
Uuid::parse_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap(),
];
// Sort by as_bytes (big-endian) for PostgreSQL-style ordering
let mut sorted_pg: Vec<_> = uuids.iter().collect();
sorted_pg.sort_by_key(|u| u.as_bytes());
println!();
println!("PostgreSQL sort order:");
for u in sorted_pg {
println!(" {}", u);
}
}Database systems differ in UUID byte order; choose the right format.
use uuid::Uuid;
use std::collections::BTreeMap;
fn main() {
// BTreeMap uses Ord, which compares using as_bytes order
let mut map: BTreeMap<Uuid, &str> = BTreeMap::new();
let u1 = Uuid::parse_str("00000000-0000-0000-0000-000000000001").unwrap();
let u2 = Uuid::parse_str("00000000-0000-0000-0000-000000000002").unwrap();
let u3 = Uuid::parse_str("ffffffff-ffff-ffff-ffff-ffffffffffff").unwrap();
map.insert(u1, "first");
map.insert(u2, "second");
map.insert(u3, "last");
println!("BTreeMap iteration (ordered by as_bytes):");
for (uuid, value) in &map {
println!(" {} -> {}", uuid, value);
}
// If you need little-endian ordering, you'd need a custom wrapper
// that implements Ord using to_bytes_le
println!();
println!("Comparison:");
println!(" u1 < u2: {}", u1 < u2); // true
println!(" u2 < u3: {}", u2 < u3); // true
// Ordering is based on as_bytes comparison
}UUID ordering uses big-endian comparison by default.
use uuid::Uuid;
fn main() {
let uuid = Uuid::new_v4();
// Most network protocols use big-endian (network byte order)
// RFC 4122 specifies big-endian for UUIDs in protocols
// For network transmission:
let network_bytes = uuid.as_bytes().to_owned(); // Vec<u8> for sending
// Receiving and parsing:
let received_uuid = Uuid::from_slice(&network_bytes).unwrap();
assert_eq!(uuid, received_uuid);
println!("Network format: {:02x?}", network_bytes);
println!("UUID: {}", received_uuid);
// from_slice expects big-endian order
// Use from_bytes_le if you receive little-endian bytes
}Network protocols typically use big-endian; as_bytes is the default choice.
use uuid::Uuid;
use std::io::{self, Read, Write, Cursor};
fn main() -> io::Result<()> {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// Write UUID to binary format (big-endian)
let mut buffer = Vec::new();
buffer.write_all(uuid.as_bytes())?;
// Read UUID from binary format
let mut cursor = Cursor::new(&buffer);
let mut bytes = [0u8; 16];
cursor.read_exact(&mut bytes)?;
let parsed = Uuid::from_bytes(bytes);
println!("Written: {:02x?}", uuid.as_bytes());
println!("Read: {:02x?}", bytes);
println!("Parsed: {}", parsed);
assert_eq!(uuid, parsed);
// For formats that use little-endian:
let le_bytes = uuid.to_bytes_le();
println!();
println!("LE format: {:02x?}", le_bytes);
let parsed_le = Uuid::from_bytes_le(le_bytes);
println!("Parsed LE: {}", parsed_le);
Ok(())
}Choose byte order based on the file format specification.
use uuid::Uuid;
fn main() {
let uuid = Uuid::new_v4();
// as_bytes is essentially free - just returns a reference
let bytes_ref: &[u8; 16] = uuid.as_bytes();
// No allocation, no copying
// to_bytes_le creates a new array and copies bytes
let bytes_owned: [u8; 16] = uuid.to_bytes_le();
// Stack allocation + byte rearrangement
// If you need owned bytes anyway:
let bytes_from_ref: [u8; 16] = *uuid.as_bytes(); // Copy from reference
let bytes_from_le: [u8; 16] = uuid.to_bytes_le(); // Copy + rearrange
println!("as_bytes() reference: {:p}", bytes_ref);
println!("to_bytes_le() owned: {:02x?}", bytes_owned);
// Use as_bytes when you can work with a reference
// Use to_bytes_le only when little-endian is required
}as_bytes is cheaper; to_bytes_le allocates and copies.
use uuid::Uuid;
fn main() {
// Create from big-endian bytes
let be_bytes: [u8; 16] = [
0x55, 0x0e, 0x84, 0x00, 0xe2, 0x9b, 0x41, 0xd4,
0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
];
let from_be = Uuid::from_bytes(be_bytes);
println!("from_bytes (BE): {}", from_be);
// UUID: 550e8400-e29b-41d4-a716-446655440000
// Create from little-endian bytes
let le_bytes: [u8; 16] = [
0x00, 0x84, 0x0e, 0x55, 0x9b, 0xe2, 0xd4, 0x41,
0xa7, 0x16, 0x44, 0x66, 0x55, 0x44, 0x00, 0x00,
];
let from_le = Uuid::from_bytes_le(le_bytes);
println!("from_bytes_le (LE): {}", from_le);
// UUID: 550e8400-e29b-41d4-a716-446655440000
// Same UUID, different byte input!
assert_eq!(from_be, from_le);
// from_slice for &[u8]
let slice = &be_bytes[..];
let from_slice = Uuid::from_slice(slice).unwrap();
println!("from_slice: {}", from_slice);
}Use the from_* method that matches your byte source format.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// RFC 4122 stores version in the high nibble of byte 6
// and variant in the high bits of byte 8
let be_bytes = uuid.as_bytes();
// Version is in byte 6 (time_hi_version)
// 41 d4 -> high nibble is 4 (version 4 = random)
println!("Byte 6: {:02x}", be_bytes[6]);
println!("Version nibble: {:x}", be_bytes[6] >> 4);
// Variant is in byte 8 (clock_seq_hi)
println!("Byte 8: {:02x}", be_bytes[8]);
println!("Variant bits: {:02b}", be_bytes[8] >> 6);
// In little-endian, these positions are the same
// (only time fields are reordered, not clock_seq)
let le_bytes = uuid.to_bytes_le();
println!();
println!("LE byte 6: {:02x} (same)", le_bytes[6]);
println!("LE byte 8: {:02x} (same)", le_bytes[8]);
}Version and variant fields remain in the same byte positions in both formats.
use uuid::Uuid;
fn main() {
let uuid = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap();
// Hyphenated representation always uses big-endian field order
let hyphenated = uuid.hyphenated().to_string();
println!("Hyphenated: {}", hyphenated);
// Always: 550e8400-e29b-41d4-a716-446655440000
// Regardless of internal representation
// Simple (no hyphens)
let simple = uuid.simple().to_string();
println!("Simple: {}", simple);
// Urn format
let urn = uuid.urn().to_string();
println!("URN: {}", urn);
// All these use big-endian byte order in string representation
// The byte order differences only matter for binary formats
}String representations always use big-endian field order.
Method comparison:
| Aspect | as_bytes | to_bytes_le |
|--------|------------|---------------|
| Return type | &[u8; 16] (reference) | [u8; 16] (owned) |
| Byte order | Big-endian (network) | Little-endian (GUID) |
| Time fields | Original order | Reversed |
| Clock/node | Original order | Original order |
| Performance | Reference only | Allocates + copies |
| Use case | Network, PostgreSQL | SQL Server, COM |
Field ordering:
| Field | as_bytes order | to_bytes_le order |
|-------|-----------------|--------------------|
| time_low | bytes 0-3, big-endian | bytes 0-3, little-endian |
| time_mid | bytes 4-5, big-endian | bytes 4-5, little-endian |
| time_hi_version | bytes 6-7, big-endian | bytes 6-7, little-endian |
| clock_seq | bytes 8-9 | bytes 8-9 (unchanged) |
| node | bytes 10-15 | bytes 10-15 (unchanged) |
When to use each:
| Scenario | Method |
|----------|--------|
| Network protocols | as_bytes |
| PostgreSQL binary | as_bytes |
| Standard file formats | as_bytes |
| Microsoft GUID interop | to_bytes_le |
| SQL Server storage | to_bytes_le |
| COM/Windows APIs | to_bytes_le |
Key insight: as_bytes and to_bytes_le provide access to the same UUID in two different binary encodings that arise from historical differences in how systems store multi-byte integers. as_bytes returns a reference to the internal big-endian representation where the bytes appear in the same order as the hyphenated string formatāthe first four bytes are exactly 550e8400 for UUID 550e8400-.... This is the RFC 4122 standard and works for most network protocols, PostgreSQL, and general binary storage. to_bytes_le creates a new array with the time fields reversed into little-endian order, matching Microsoft's GUID format where 550e8400 becomes bytes 00 84 0e 55. Use as_bytes for standard network and database interop; use to_bytes_le specifically for Windows API compatibility, COM interfaces, or SQL Server binary storage. The corresponding from_bytes and from_bytes_le constructors parse bytes in each format back to a canonical UUID object, so the same UUID value can be reconstructed from either byte order.