빌드 스크립트 build.rs

Rust 프로젝트에서 third-party non-Rust 코드를 함께 컴파일해야 할 때 빌드 스크립트를 이용할 수 있다. 별도의 스크립트를 실행하지 않고 프로젝트에 통합할수 있다는 점이 굉장히 유용한 편! 이 스크립트를 사용하는 예제로는 bindgen, cc 등을 이용하여 non-Rust 코드를 컴파일, Rust 코드와 연결해야 할 때 gRPC, jsonschema 등을 사용해 정의된 타입을 변환할 때 등이 있다. 이 스크립트를 사용할 때 주의해야 하는 소소한 점들을 정리했다. build.rs 예제 Cargo는 컴파일 과정에서 build script를 빌드, 실행한다. 따라서 다음과 같은 빌드 스크립트는 패키지 컴파일 과정에서 hello.rs 파일을 만들게 된다. 패키지의 코드는 hello.rs 내 함수를 사용할 수 있다. ...

2024-02-02 · 4 min · 720 words · Huijeong Kim

Exploring Rust Strings

안녕하세요. 오늘은 Rust의 문자열 개념을 간단하게 알아보고, 코드 작성 시 문자열 관련 혼란스러웠던 포인트들을 정리해 보고자 합니다. 1. String vs. str String 과 str 는 모두 valid UTF-8 문자열을 나타냅니다. Invalid UTF-8 데이터로 String 타입을 생성할 수 없습니다. UTF-8, Unicode 등에 대한 설명은 생략합니다. Rust에서는 C와 같이 null-terminating string 개념을 사용하지 않습니다. 대신 String 타입은 문자열과 그 길이를 갖고 있는 “fat pointer” 입니다. “fat pointer"는 raw pointer과 additional metadata (e.g., length)를 갖고 있는 포인터를 의미합니다. ...

2023-05-07 · 8 min · 1587 words · Huijeong Kim

as operator in Rust

안녕하세요. 오늘은 Rust의 as 를 사용한 type casting에 대해 알아보고자 합니다. C++ 프로그램에서는 잘못된 type 사용 으로 인한 오류를 종종 볼 수 있습니다. uint64_t 값을 uint32_t 값에 대입하여 잘못된 값으로 동작하는 경우가 그 예입니다. 조금은 어이 없는 실수이긴 한데, 생각보다 자주 발견됩니다. 이런 류의 버그는 처음 봤을 때 원인을 가늠하기 힘들기도 하지만, 고치기 귀찮거나 어렵기도 합니다. Type 재정의를 사용하지 않는 경우도 많고, 가끔씩은 통일할 필요가 크게 없는 경우도 있고, 의미 상 같은 변수를 모두 찾아내기 힘든 코드들도 종종 있습니다. 테스트를 더 잘 하면 된다고 하지만, 모든 변수에 대해 boundary test를 하는 건 현실적으로 조금 어렵습니다. ...

2023-05-02 · 8 min · 1558 words · Huijeong Kim

Polymorphism in Rust

안녕하세요. 오늘은 rust에서 polymorphism을 활용하는 방법을 정리해 보고자 합니다. cpp 코드를 작성하던 습관 대로 Rust 코드를 작성하다 보면 막히는 부분 중 하나가 interface 클래스(pure virtual class)와 이를 통한 객체 전달 부분입니다. 단순히 trait으로 변환하여 코드를 작성하다 보면 쉽게 컴파일 에러 지옥에 빠지곤 하는데요.. 아주 간단한 composite design pattern 예제를 구현해 보면서 rust의 polymorphism 에 대해 알아보도록 하겠습니다. Composite pattern 예제로 많이 사용되는 File, Directory 구조를 표현해 보고자 합니다. File은 이름과 크기를 갖고 있는 객체로, Directory는 이름과 하위 파일 및 디렉토리를 갖는 객체로, 그리고 File, Directory 는 모두 Node 라는 interface를 구현하게 만들고자 합니다. ...

2023-01-29 · 9 min · 1707 words · Huijeong Kim

Rust로 Parameterised Test 작성하기

Unit test를 작성 하다 보면 간단한 함수에 대해서도 꽤나 많은 수의 테스트 케이스를 작성하게 됩니다. Input 값의 조합, 특히나 Invalid Input 값의 조합은 무지 많아질 수 있기 때문 입니다. 그 모든 케이스를 하나 씩 테스트로 작성 하는 것은 꽤 귀찮기도 하고, 테스트 함수 작명 지옥에 빠지면서 테스트 가독성도 떨어지게 됩니다. 이럴 때 사용할 수 있는 것이 table-driven test, 혹은 parameterised test 입니다. Input-Output 조합을 table로 표현하는 방식입니다. Rust로 간단한 함수의 parameterised test를 작성해 보고, rust의 test-case, rtest crate를 활용해 이를 더 간편하게 작성하는 방법을 알아보겠습니다. ...

2022-08-28 · 6 min · 1114 words · Huijeong Kim

Actix actor의 AsyncContext 활용하기 (2)

지난 글에 이어 Actix actor의 AsyncContext 함수를 사용하는 방법을 알아봅니다. add_stream, add_message_stream 1 2 3 4 5 6 7 8 9 10 fn add_stream<S>(&mut self, fut: S) -> SpawnHandle where S: Stream + 'static, A: StreamHandler<S::Item>; fn add_message_stream<S>(&mut self, fut: S) where S: Stream + 'static, S::Item: Message, A: Handler<S::Item>; Context에 stream을 등록하는 함수입니다. 두 함수는 거의 비슷하나 차이점은 add_message_stream은 stream error를 무시한다는 점입니다. ...

2022-08-27 · 3 min · 468 words · Huijeong Kim

Actix actor의 AsyncContext 활용하기 (1)

Actix에서 actor를 생성하면 해당 actor를 실행시키는 문맥(context)에 해당하는 Context가 생성 되고, Context는 다양한 actor의 동작을 정의합니다. 그 중 Context를 활용해서 actor가 future를 실행, 취소, 기다리는 방법을 알아봅니다. 아래 예제 코드들은 actix 0.13.0 버전을 사용했습니다. Actor Context 먼저, Actor의 Context의 정의, 생성 시기를 알아보겠습니다. 사용자가 정의한 struct를 actor로 만들기 위해서 최소로 필요한 것은 Actor trait을 구현(implement) 하고 Context를 정의하는 것 입니다. 1 2 3 4 5 struct MyActor; impl Actor for MyActor { type Context = Context<Self>; } 위 actor는 다음과 같이 생성되고 시작될 수 있습니다. ...

2022-08-21 · 8 min · 1541 words · Huijeong Kim

Actix actor를 사용하는 두 가지 방법

Actix에서 actor를 사용하는 방법은 두 가지로 나눌 수 있을 것 같습니다. 첫 번째는 특정 task를 실행시키는 용도로, client가 message를 보내면 이를 받아서 처리하는 actor를 만드는 것 이고, 두 번째는 주기적으로 task를 실행시키는 actor를 만드는 것 입니다. 두 경우 각각 actor를 사용하는 방법에 대해 알아봅니다. 1. Message를 처리하는 actor Actor를 시작하면 Addr가 리턴됩니다. Addr는 해당 actor에게 message를 전달할 수 있는 channel 입니다. Client module은 이 addr를 통해서 message를 전달할 수 있습니다. ...

2022-08-17 · 8 min · 1494 words · Huijeong Kim

Expand Rust Macros

Rust에서 사용 된 macro의 구현이 궁금할 때 cargo expand를 사용할 수 있습니다. 설치 $ cargo install cargo-expand 사용법 이전 글에서 사용한 코드를 expand해 봅시다. cargo expand 시 expand 된 코드가 stdout으로 출력됩니다. $ cargo expand --bin actix-and-tonic 이 예제는 하나의 파일로 이루어져 있어 binary를 지정했지만, 특정 module 코드를 expand하기 위해서 module을 지정할 수도 있습니다. $ cargo expand path::to:module Message 구현에 사용했던 Message macro는 1 2 3 #[derive(Default, Message)] #[rtype(result = "String")] struct GetName; 이렇게 풀어쓸 수 있습니다. ...

2022-08-14 · 1 min · 132 words · Huijeong Kim

Actix에서 gRPC Server 시작하기

Rust로 gRPC로 외부와 통신하는 Actix 기반 application을 작성하는 방법을 알아봅니다. gRPC Server는 Tonic을 사용해 구현합니다. Tonic과 Actix는 둘 다 tokio 기반 application으로, tokio Runtime 위에서 동작합니다. 같은 tokio Runtime에 gRPC Server와 Actor System을 실행시켜 보겠습니다. Tonic을 사용해 gRPC Server 시작하기 Tonic을 사용하면 다음과 같은 간단한 Server 실행 코드를 포함한 Async Block(Future)을 Tokio Runtime에서 실행하여 gRPC Server를 시작할 수 있습니다. 아래 코드는 Tonic repo 내 helloworld exmaple에서 tonic::main 매크로를 풀어 쓴 것입니다. ...

2022-08-14 · 4 min · 699 words · Huijeong Kim