Skip to content

Commit 959e483

Browse files
committed
auto merge of #5235 : yjh0502/rust/io_float, r=graydon
When parsing bytes from a wire, there is a need to parse floating-point bytes to float values ([u8*4] to f32, [u8*8] to f64). This can be done via cast::transmute, but there is no way to do it safely. It's quite common, so I think I't better to support it in core library.
2 parents 165cc9e + ce23c8c commit 959e483

File tree

1 file changed

+108
-0
lines changed

1 file changed

+108
-0
lines changed

src/libcore/io.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ pub trait ReaderUtil {
144144
/// Read a big-endian i16 (2 bytes).
145145
fn read_be_i16(&self) -> i16;
146146

147+
/// Read a big-endian IEEE754 double-precision floating-point (8 bytes).
148+
fn read_be_f64(&self) -> f64;
149+
150+
/// Read a big-endian IEEE754 single-precision floating-point (4 bytes).
151+
fn read_be_f32(&self) -> f32;
152+
147153
/// Read a little-endian u64 (8 bytes).
148154
fn read_le_u64(&self) -> u64;
149155

@@ -162,6 +168,14 @@ pub trait ReaderUtil {
162168
/// Read a litle-endian i16 (2 bytes).
163169
fn read_le_i16(&self) -> i16;
164170

171+
/// Read a litten-endian IEEE754 double-precision floating-point
172+
/// (8 bytes).
173+
fn read_le_f64(&self) -> f64;
174+
175+
/// Read a litten-endian IEEE754 single-precision floating-point
176+
/// (4 bytes).
177+
fn read_le_f32(&self) -> f32;
178+
165179
/// Read a u8 (1 byte).
166180
fn read_u8(&self) -> u8;
167181

@@ -368,6 +382,18 @@ impl<T:Reader> ReaderUtil for T {
368382
self.read_be_int_n(2) as i16
369383
}
370384

385+
fn read_be_f64(&self) -> f64 {
386+
unsafe {
387+
cast::transmute::<u64, f64>(self.read_be_u64())
388+
}
389+
}
390+
391+
fn read_be_f32(&self) -> f32 {
392+
unsafe {
393+
cast::transmute::<u32, f32>(self.read_be_u32())
394+
}
395+
}
396+
371397
fn read_le_u64(&self) -> u64 {
372398
self.read_le_uint_n(8) as u64
373399
}
@@ -392,6 +418,18 @@ impl<T:Reader> ReaderUtil for T {
392418
self.read_le_int_n(2) as i16
393419
}
394420

421+
fn read_le_f64(&self) -> f64 {
422+
unsafe {
423+
cast::transmute::<u64, f64>(self.read_le_u64())
424+
}
425+
}
426+
427+
fn read_le_f32(&self) -> f32 {
428+
unsafe {
429+
cast::transmute::<u32, f32>(self.read_le_u32())
430+
}
431+
}
432+
395433
fn read_u8(&self) -> u8 {
396434
self.read_byte() as u8
397435
}
@@ -874,6 +912,12 @@ pub trait WriterUtil {
874912
/// Write a big-endian i16 (2 bytes).
875913
fn write_be_i16(&self, n: i16);
876914

915+
/// Write a big-endian IEEE754 double-precision floating-point (8 bytes).
916+
fn write_be_f64(&self, f: f64);
917+
918+
/// Write a big-endian IEEE754 single-precision floating-point (4 bytes).
919+
fn write_be_f32(&self, f: f32);
920+
877921
/// Write a little-endian u64 (8 bytes).
878922
fn write_le_u64(&self, n: u64);
879923

@@ -892,6 +936,14 @@ pub trait WriterUtil {
892936
/// Write a little-endian i16 (2 bytes).
893937
fn write_le_i16(&self, n: i16);
894938

939+
/// Write a little-endian IEEE754 double-precision floating-point
940+
/// (8 bytes).
941+
fn write_le_f64(&self, f: f64);
942+
943+
/// Write a litten-endian IEEE754 single-precision floating-point
944+
/// (4 bytes).
945+
fn write_le_f32(&self, f: f32);
946+
895947
/// Write a u8 (1 byte).
896948
fn write_u8(&self, n: u8);
897949

@@ -948,6 +1000,16 @@ impl<T:Writer> WriterUtil for T {
9481000
fn write_be_i16(&self, n: i16) {
9491001
u64_to_be_bytes(n as u64, 2u, |v| self.write(v))
9501002
}
1003+
fn write_be_f64(&self, f:f64) {
1004+
unsafe {
1005+
self.write_be_u64(cast::transmute(f))
1006+
}
1007+
}
1008+
fn write_be_f32(&self, f:f32) {
1009+
unsafe {
1010+
self.write_be_u32(cast::transmute(f))
1011+
}
1012+
}
9511013
fn write_le_u64(&self, n: u64) {
9521014
u64_to_le_bytes(n, 8u, |v| self.write(v))
9531015
}
@@ -966,9 +1028,20 @@ impl<T:Writer> WriterUtil for T {
9661028
fn write_le_i16(&self, n: i16) {
9671029
u64_to_le_bytes(n as u64, 2u, |v| self.write(v))
9681030
}
1031+
fn write_le_f64(&self, f:f64) {
1032+
unsafe {
1033+
self.write_le_u64(cast::transmute(f))
1034+
}
1035+
}
1036+
fn write_le_f32(&self, f:f32) {
1037+
unsafe {
1038+
self.write_le_u32(cast::transmute(f))
1039+
}
1040+
}
9691041

9701042
fn write_u8(&self, n: u8) { self.write([n]) }
9711043
fn write_i8(&self, n: i8) { self.write([n as u8]) }
1044+
9721045
}
9731046

9741047
#[allow(non_implicitly_copyable_typarams)]
@@ -1421,6 +1494,41 @@ mod tests {
14211494
}
14221495
}
14231496

1497+
#[test]
1498+
fn test_read_f32() {
1499+
let path = Path("tmp/lib-io-test-read-f32.tmp");
1500+
//big-endian floating-point 8.1250
1501+
let buf = ~[0x41, 0x02, 0x00, 0x00];
1502+
1503+
{
1504+
let file = io::file_writer(&path, [io::Create]).get();
1505+
file.write(buf);
1506+
}
1507+
1508+
{
1509+
let file = io::file_reader(&path).get();
1510+
let f = file.read_be_f32();
1511+
assert f == 8.1250;
1512+
}
1513+
}
1514+
1515+
#[test]
1516+
fn test_read_write_f32() {
1517+
let path = Path("tmp/lib-io-test-read-write-f32.tmp");
1518+
let f:f32 = 8.1250;
1519+
1520+
{
1521+
let file = io::file_writer(&path, [io::Create]).get();
1522+
file.write_be_f32(f);
1523+
file.write_le_f32(f);
1524+
}
1525+
1526+
{
1527+
let file = io::file_reader(&path).get();
1528+
assert file.read_be_f32() == 8.1250;
1529+
assert file.read_le_f32() == 8.1250;
1530+
}
1531+
}
14241532
}
14251533

14261534
//

0 commit comments

Comments
 (0)