And Brain said,

엔디언(Endian) 행진곡. 2 - Rust로 다시 쓰여지다 본문

IT/엔디언 행진곡

엔디언(Endian) 행진곡. 2 - Rust로 다시 쓰여지다

The Man 2023. 6. 28. 12:37
반응형

엔디언(Endian) 행진곡

0. 멀티바이트의 질서있는 행진
1. 빅이냐 리틀이냐 그것이 문제로다
2. Rust로 다시 쓰여지다
3. 제1장: Network
4. 제2장: FIle
5. 행진이 끝나고

예제 코드

 
이제 Rust를 이용해 실제로 엔디언 변환을 해보도록 합시다.
 
Rust에서는 'byteorder' 라는 crate를 이용해 간편하게 엔디언 변환을 할 수 있습니다. 이 crate를 사용하여, 쉽게 데이터 바이트의 순서를 변경해보도록 합시다.
 
먼저, Cargo.toml 파일에 라이브러리를 추가해줍시다.

[dependencies]
byteorder = "1.4.3"

 
자, 이제 간단한 엔디언 변환 예제를 작성해봅시다.

use byteorder::{BigEndian, ByteOrder, LittleEndian};

fn main() {
    let mut buf = [0; 4];
    BigEndian::write_u32(&mut buf, 12345);
    let n = BigEndian::read_u32(&buf);
    buf.reverse(); // 바이트 배열 반전
    let m = LittleEndian::read_u32(&buf);
    assert_eq!(n, m); // 두 방식으로 읽은 값이 같음
}

 
n과 m은 각각 빅 엔디언과 리틀 엔디언 방식으로 바이트 배열을 읽은 변수입니다. 간단히 바이트 배열을 반전시키는 것만으로도 이 둘은 같아집니다.
 
 
이번엔 좀 더 복잡한 데이터 구조에서 엔디언 변환을 해봅시다. 구조체의 각 필드에 대한 엔디언 변환이 필요한 경우에는 'byteorde' crate의 'ReadBytesExt'와 'WriteBytesExt' 트레이트를 사용하면 편리합니다.
 

use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;

#[derive(Debug)]
struct SimpleStruct {
    field1: u32,
    field2: u16,
    field3: u8
}

fn main() {
    let mut data = vec![];


    let simple_struct = SimpleStruct {
        field1: 12345,
        field2: 6789,
        field3: 101,
    };

    data.write_u32::<LittleEndian>(simple_struct.field1).unwrap();
    data.write_u16::<LittleEndian>(simple_struct.field2).unwrap();
    data.write_u8(simple_struct.field3).unwrap();

    let mut cursor = Cursor::new(data);
    let mut data_be = vec![];
    let field1_le = cursor.read_u32::<LittleEndian>().unwrap();
    let field2_le = cursor.read_u16::<LittleEndian>().unwrap();
    let field3_le = cursor.read_u8().unwrap();

    data_be.write_u32::<BigEndian>(field1_le).unwrap();
    data_be.write_u16::<BigEndian>(field2_le).unwrap();
    data_be.write_u8(field3_le).unwrap();

    let mut cursor = Cursor::new(&data_be);

    let simple_struct_be = SimpleStruct {
        field1: cursor.read_u32::<BigEndian>().unwrap(),
        field2: cursor.read_u16::<BigEndian>().unwrap(),
        field3: cursor.read_u8().unwrap(),
    };

    println!("리틀 엔디언 {:?}", simple_struct);
    println!("빅 엔디언 {:?}", simple_struct_be);
}

 

 
이렇게 구조체의 각 필드를 한 엔디언에서 다른 엔디언으로 변환할 수 있습니다.
 
 
이번엔 더 복잡한 구조체를 정의하고, 이를 빅 엔디언 형식의 바이트 배열로 변환한 후 다시 구조체로 변환해보도록 하겠습니다.
 

use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt};
use std::io::Cursor;

#[derive(Debug)]
struct ComplexStruct {
    field1: u32,
    field2: u16,
    field3: u8,
    field4: Vec<u32>,
}

impl ComplexStruct {
    fn new() -> Self {
        ComplexStruct {
            field1: 12345,
            field2: 6789,
            field3: 101,
            field4: vec![1, 2, 3, 4, 5],
        }
    }

    fn to_big_endian(&self) -> Vec<u8> {
        let mut data_be = vec![];

        data_be.write_u32::<BigEndian>(self.field1).unwrap();
        data_be.write_u16::<BigEndian>(self.field2).unwrap();
        data_be.write_u8(self.field3).unwrap();
        for &item in &self.field4 {
            data_be.write_u32::<BigEndian>(item).unwrap();
        }
        data_be
    }

    fn from_big_endian(data: &[u8]) -> Self {
        let mut cursor = Cursor::new(data);
        let field1_be = cursor.read_u32::<BigEndian>().unwrap();
        let field2_be = cursor.read_u16::<BigEndian>().unwrap();
        let field3_be = cursor.read_u8().unwrap();

        let mut field4_be = vec![];

        while cursor.position() < data.len() as u64 {
            field4_be.push(cursor.read_u32::<BigEndian>().unwrap());
        }

        ComplexStruct {
            field1: field1_be,
            field2: field2_be,
            field3: field3_be,
            field4: field4_be,
        }
    }
}

fn main() {
    let complex_struct = ComplexStruct::new();
    let data_be = complex_struct.to_big_endian();

    println!("Original data: {:?}", complex_struct);
    println!("BigEndian data: {:?}", data_be);

    let complex_struct_be = ComplexStruct::from_big_endian(&data_be);

    println!("Data from BigEndian: {:?}", complex_struct_be)
}

위 예제는 ComplexStruct라는 복잡한 구조체를 정의하고, 필드의 초기값과 직렬화/역직렬화 메서드를 제공합니다. to_big_endian() 메서드를 사용하여 ComplexStruct 인스턴스의 데이터를 빅 엔디언으로 직렬화하고, from_big_endian() 함수를 사용하여 빅 엔디언 데이터를 역직렬화하는 방법을 보여줍니다. main() 함수에서는 원본 데이터와 빅 엔디언 데이터를 출력하고, 역직렬화된 데이터를 다시 얻어 출력하여 작동을 확인합니다.
 
이와 같은 방식으로 더 복잡한 데이터 구조의 엔디언 변환도 처리할 수 있습니다.
 

<- 이전으로

다음으로 ->

 

Thanks for watching, Have a nice day.

 

반응형
Comments