Rust로 작성한 장난감 프로젝트

내 이 세상 도처에서 쉴 곳을 찾아보았으나, 마침내 찾아낸, 컴퓨터가 있는 구석방보다 나은 곳은 없더라.

Rust로 작성한 장난감 프로젝트

나는 Rust를 좋아한다. 그동안 Rust를 공부하며 여러 장난감 프로젝트를 진행했다. 여기 그동안 Rust로 만들었던 장난감 프로젝트를 정리해 보려 한다.

  1. p-test
  2. lsr
  3. rup
  4. prism-rs
  5. json_parser
  6. reflexive-rs

p-test

Rust에서 매개변수 테스트를 작성하려면 어떻게 해야 할까? 방법이 없는 것은 아니었다. 이미 rstest와 같이 널리 사용되는 크레잇이 있었다. 그러나 rstest로 테스트를 작성하는 방식이 마음에 들지 않았다. 내 마음에 들게 매개변수 테스트를 작성할 수 있도록 매크로를 직접 작성해 보기로 했다.

내 생각에는 내가 작성한 p-test 매크로가 매개변수 테스트를 표현하는데 있어 rstest보다 나은 것 같다. 그러나 p-test는 정말 매개변수 테스트를 표현하는 매크로 하나뿐이고 rstest에는 더 많은 기능이 있다.

장난감 프로젝트로 만든 것이지만, 개인 Rust 프로젝트에서 매개변수 테스트가 필요하면 이 녀석을 활용한다. 이 프로젝트로 Rust에서 절차형 매크로를 만다는 것이 생각보다 어렵지 않음을 알게 되었다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

p-testcrates.io에도 공개되어 있다. 2026-05-22 현재 다운로드 수가 5,800에 조금 못 미친다.

구현과 관련된 자세한 설명은 다음 글에서 확인할 수 있다.

lsr

ls 명령을 Rust로 구현한 다른 프로젝트(eza, lsd 등)가 이미 있지만, ls 같은 명령을 어떻게 구현하는지 직접 확인해보고 싶었다. Command-Line Rust란 책의 마지막 장(14장)을 보면 간단한 ls 클론을 만드는 방법이 나오는데, 구현의 완성도가 조금 부족한 것 같았다. 내가 하면 더 잘할 수 있을 것 같다는 생각이 들어 직접 해보기로 했다. lsr은 책에 나오는 명령어 이름이다. 새로운 이름을 생각하기 귀찮아 그대로 사용했다.

처음에는 외부 라이브러리를 사용하지 않고 구현해보려 했는데, 파일의 user와 group 이름을 얻으려면 libc 바인딩을 사용해야 하는 것으로 보였다. 외부 라이브러리를 사용하기 시작하니 결국은 이것저것 외부 라이브러리를 갖다 쓰게 되었다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

구현과 관련된 자세한 설명은 다음 글에서 확인할 수 있다.

rup

Rust로 간단히 명령행 HTTP 서버를 만들어보기로 했다. 소켓을 열어 대기하고 HTTP 요청을 파싱해 응답하는 모든 기능을 외부 라이브러리 없이 구현했다. 하는 김에 명령행 인자 파싱도 직접 구현했다.

학습 목적으로 구현했지만 실제로도 (Rust 장난감 프로젝트 구현물 중) 가장 많이 사용한 프로그램이 아닐까 싶다. 테스트 결과 등 개발 서버에 생성된 HTML 파일을 보고 싶을 때 매우 유용했다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

구현과 관련된 자세한 설명은 다음 글에서 확인할 수 있다.

위 글에서는 사실 Actix-Web을 사용해 구현하는 방법을 설명했다. 원래는 외부 라이브러리를 사용하지 않고 모든 것을 직접 구현한 명령행 HTTP 서버를 설명하려고 했지만, 글이 너무 길고 복잡해질 것 같아 방향을 바꾸었다.

prism-rs

스캐너와 파서를 구현할 수 있게 되니 그전에는 상상도 못 했던 것을 할 수 있게 되었다. 그중 하나가 코드를 읽어 문법을 강조하는 코드 하이라이터다.

코드 하이라이터는 코드를 스캔해 토큰 목록을 구한 다음 토큰 타입에 따라 적절히 렌더링 하면 되므로 파싱은 필요하지 않다.

보통 코드 하이라이터는 여러 언어를 지원하지만, prism-rs는 Rust만 지원한다. 다른 언어도 지원하게 만다는 것은 아주 어려워 보이지는 않지만 그렇다고 아주 간단해 보이지도 않는다.

언어를 모를 경우 코드를 읽어서 언어를 알아내는 좋은 방법이 있을까? 흥미로운 문제인 것 같다. 나중에 시도해 봐야겠다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

구현과 관련된 자세한 설명은 다음 글에서 확인할 수 있다.

json_parser

예전에 어느 회사 면접 코딩에서 주어진 문자열이 유효한 JSON인지 검사하는 함수를 작성하는 문제가 주어진 적이 있다. 몇 가지 조건을 생각해 구현하긴 했지만 면접관을 만족시키지는 못했다. 나도 내 답이 만족스럽지 않아 면접관에게 어떻게 하면 되냐고 했더니 면접관이 몇 가지 조건을 확인하면 된다고 설명했다. 내 생각에 면접관의 답도 별반 나은 것 같지 않았다.

면접에는 떨어졌지만 문제를 제대로 풀어보고 싶었다. 얼마 후 Crafting Interpreter란 책으로 스캐너와 파서를 구현하는 방법을 알게 되었고 JSON 파서를 제대로 구현해 보기로 했다. 처음에는 Java로 구현했고, 나중에 Rust를 공부하면서 Rust로 구현했다. Rust로 구현할 때 enum을 활용했는데, 나중에 보니 Programming Rust에서도 enum을 설명하면서 JSON을 예로 들어 설명하는데 비슷한 방법을 사용한 것을 보고 은근히 기분이 좋았다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

물론 두 구현이 완벽한 것은 아니다. 예를 들어 JSON에서는 6.02 e23과 같은 식으로 숫자를 표현할 수 있지만, 위 두 JSON 파서는 이런 식의 숫자 표현을 파싱하지 못하고 에러를 내뱉는다.

다음 글에서 JSON 파서 구현 방법을 설명했다.

reflexive-rs

Rust로 간단한 웹 요청을 처리하는 프로그램을 만들어보고 싶었지만 특별한 아이디어가 떠오르지 않았다. 예전에 일했던 팀에 테스트를 위한 에코 서비스가 있었는데, HTTP 요청이 들어오면 바로 "OK"를 응답하는 서비스였다. 물론 다른 기능이 있기는 했지만. 생각해 보니 HTTP 요청을 받으면 HTTP 요청에 들어있는 데이터를 모두 꺼내 JSON 형태로 응답하는 에코 서비스를 만들어보는 것도 재미있을 것 같았다.

Rust 웹 프레임워크 사용법을 배울 수 있고, 요청 헤더, 쿼리 파라미터, 요청 본문 등을 요청에서 뽑아내는 방법도 익힐 수 있고, JSON으로 응답하려면 Rust에서 JSON을 어떻게 다루는 지도 익힐 수 있다. 웹 프레임워크로는 Actix-Web을, JSON 처리에는 Serde를 사용했다.

HTTP 요청에서 헤더와 쿼리 파라미터는 중복될 수 있다. 이를 처리하기 위해 SingleOrMulti라는 enum을 정의했다. 값이 하나일 때는 Single을, 값이 여럿일 때는 Multi를 사용하도록 했는데, 내가 생각해도 우아한 접근법인 것 같다.

코드는 다음 깃헙 저장소에서 확인할 수 있다.

다음 글에서 구현과 관련된 자세한 설명을 확인할 수 있다.