Skip to content

Commit b7cb1ca

Browse files
committed
Added rust/yaml/serde_yaml/internally_tagged.
1 parent be97d56 commit b7cb1ca

File tree

5 files changed

+392
-0
lines changed

5 files changed

+392
-0
lines changed

rust/yaml/serde_yaml/internally_tagged/Cargo.lock

Lines changed: 119 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "firststep"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
serde = { version = "1.0.203", features = ["derive"] }
8+
serde_yaml = "0.9.34"
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
---
2+
title: serde_yaml を使って Rust で YAML をパースするやつを Internally tagged で作り直した
3+
author: mikoto2000
4+
date: 2024/7/5
5+
---
6+
7+
# やること
8+
9+
[firststep](https://github.com/mikoto2000/TIL/tree/master/rust/yaml/serde_yaml/firststep) で YAML のパースを行ったが、 Internally tagged 形式で構造体を定義したほうがその後の処理がやりやすそうだったのでやってみた。
10+
11+
12+
# 前提
13+
14+
- OS: Windows 11 Pro 23H2 ビルド 22631.3737
15+
- Docker Desktop: Version 4.31.1 (153621)
16+
- rust の環境が構築済みであること。
17+
- See: [docker-images/rust/Dockerfile at master · mikoto2000/docker-images](https://github.com/mikoto2000/docker-images/blob/master/rust/Dockerfile)
18+
- rustup: 1.27.0
19+
- cargo: 1.78.0
20+
- rustc: 1.78.0
21+
- [firststep](https://github.com/mikoto2000/TIL/tree/master/rust/yaml/serde_yaml/firststep) から修正を行ったので、差分を取るとわかりやすいかもしれません。
22+
23+
24+
# 実装
25+
26+
`main.rs`:
27+
28+
```rs
29+
use std::{fs::File, io::BufReader};
30+
31+
use serde::{Deserialize, Serialize};
32+
33+
// ビットフラグの 1 ビットを表す構造体
34+
#[derive(Serialize, Deserialize, Debug)]
35+
struct LayoutItem {
36+
// 表示名
37+
name: String,
38+
// ビットフラグのビット位置
39+
position: u8,
40+
// ビットが 1 だった時に表示する値
41+
true_label: Option<String>,
42+
// ビットが 0 だった時に表示する値
43+
false_label: Option<String>,
44+
}
45+
46+
// コンフィグの要素は、以下 5 種類のどれかとなる
47+
// - UINT8
48+
// - UINT16
49+
// - UINT32
50+
// - UINT64
51+
// - FLAGS
52+
#[derive(Serialize, Deserialize, Debug)]
53+
#[serde(tag = "type")]
54+
enum ConfigItem {
55+
UINT8(BasicConfigItem),
56+
UINT16(BasicConfigItem),
57+
UINT32(BasicConfigItem),
58+
UINT64(BasicConfigItem),
59+
FLAGS(BitFlagConfigItem),
60+
}
61+
62+
// 数値データの単位を表す構造体
63+
#[derive(Serialize, Deserialize, Debug)]
64+
struct BasicConfigItem {
65+
// 表示名
66+
name: String,
67+
// ファイル先頭からのオフセット
68+
offset: u8,
69+
// オフセットから何バイト読み込むか
70+
size: u8,
71+
// エンディアン
72+
endianness: Option<String>,
73+
}
74+
75+
// ビットフラグデータの単位を表す構造体
76+
#[derive(Serialize, Deserialize, Debug)]
77+
struct BitFlagConfigItem {
78+
// 表示名
79+
name: String,
80+
// ファイル先頭からのオフセット
81+
offset: u8,
82+
// オフセットから何バイト読み込むか
83+
size: u8,
84+
// エンディアン
85+
endianness: Option<String>,
86+
// type が FLAGS の時のみ利用されるフィールド
87+
layout: Vec<LayoutItem>,
88+
}
89+
90+
fn main() {
91+
// yaml ファイルを読み込み、 Reader 化
92+
let yaml = "./yaml/setting.yaml";
93+
let yaml_file = File::open(yaml).unwrap();
94+
let reader = BufReader::new(yaml_file);
95+
96+
// serde に Reader を渡し、YAML を構造体へデシリアライズ
97+
// 構造体の定義さえできてしまえば 1 行で完了。
98+
let config: Vec<ConfigItem> = serde_yaml::from_reader(reader).unwrap();
99+
100+
// デシリアライズされた構造体を走査して表示
101+
for ci in config {
102+
match ci {
103+
ConfigItem::UINT8(i)
104+
| ConfigItem::UINT16(i)
105+
| ConfigItem::UINT32(i)
106+
| ConfigItem::UINT64(i) => {
107+
println!("name: {}", i.name);
108+
println!("offset: {}", i.offset);
109+
println!("endianness: {}", i.endianness.unwrap_or("".to_string()));
110+
println!("layout:");
111+
}
112+
ConfigItem::FLAGS(i) => {
113+
println!("name: {}", i.name);
114+
println!("offset: {}", i.offset);
115+
println!("endianness: {}", i.endianness.unwrap_or("".to_string()));
116+
println!("layout:");
117+
for l in i.layout {
118+
println!("name: {}", l.name);
119+
println!("position: {}", l.position);
120+
println!("true_label: {}", l.true_label.unwrap_or("".to_string()));
121+
println!("false_label: {}", l.false_label.unwrap_or("".to_string()));
122+
}
123+
}
124+
}
125+
}
126+
}
127+
```
128+
129+
以上。
130+
131+
132+
# 参考資料
133+
134+
- [serde_yaml を使って Rust で YAML をパースするやつを Internally tagged で作り直した](https://github.com/mikoto2000/TIL/tree/master/rust/yaml/serde_yaml/firststep)
135+
- [Field attributes · Serde](https://serde.rs/field-attrs.html)
136+
- [Rust: 構造体 in 構造体 を JSON/YAML パース時に扱う #serde - Qiita](https://qiita.com/takavfx/items/e58481d96f7c62442340)
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
use std::{fs::File, io::BufReader};
2+
3+
use serde::{Deserialize, Serialize};
4+
5+
// ビットフラグの 1 ビットを表す構造体
6+
#[derive(Serialize, Deserialize, Debug)]
7+
struct LayoutItem {
8+
// 表示名
9+
name: String,
10+
// ビットフラグのビット位置
11+
position: u8,
12+
// ビットが 1 だった時に表示する値
13+
true_label: Option<String>,
14+
// ビットが 0 だった時に表示する値
15+
false_label: Option<String>,
16+
}
17+
18+
// コンフィグの要素は、以下 5 種類のどれかとなる
19+
// - UINT8
20+
// - UINT16
21+
// - UINT32
22+
// - UINT64
23+
// - FLAGS
24+
#[derive(Serialize, Deserialize, Debug)]
25+
#[serde(tag = "type")]
26+
enum ConfigItem {
27+
UINT8(BasicConfigItem),
28+
UINT16(BasicConfigItem),
29+
UINT32(BasicConfigItem),
30+
UINT64(BasicConfigItem),
31+
FLAGS(BitFlagConfigItem),
32+
}
33+
34+
// 数値データの単位を表す構造体
35+
#[derive(Serialize, Deserialize, Debug)]
36+
struct BasicConfigItem {
37+
// 表示名
38+
name: String,
39+
// ファイル先頭からのオフセット
40+
offset: u8,
41+
// オフセットから何バイト読み込むか
42+
size: u8,
43+
// エンディアン
44+
endianness: Option<String>,
45+
}
46+
47+
// ビットフラグデータの単位を表す構造体
48+
#[derive(Serialize, Deserialize, Debug)]
49+
struct BitFlagConfigItem {
50+
// 表示名
51+
name: String,
52+
// ファイル先頭からのオフセット
53+
offset: u8,
54+
// オフセットから何バイト読み込むか
55+
size: u8,
56+
// エンディアン
57+
endianness: Option<String>,
58+
// type が FLAGS の時のみ利用されるフィールド
59+
layout: Vec<LayoutItem>,
60+
}
61+
62+
fn main() {
63+
// yaml ファイルを読み込み、 Reader 化
64+
let yaml = "./yaml/setting.yaml";
65+
let yaml_file = File::open(yaml).unwrap();
66+
let reader = BufReader::new(yaml_file);
67+
68+
// serde に Reader を渡し、YAML を構造体へデシリアライズ
69+
// 構造体の定義さえできてしまえば 1 行で完了。
70+
let config: Vec<ConfigItem> = serde_yaml::from_reader(reader).unwrap();
71+
72+
// デシリアライズされた構造体を走査して表示
73+
for ci in config {
74+
match ci {
75+
ConfigItem::UINT8(i)
76+
| ConfigItem::UINT16(i)
77+
| ConfigItem::UINT32(i)
78+
| ConfigItem::UINT64(i) => {
79+
println!("name: {}", i.name);
80+
println!("offset: {}", i.offset);
81+
println!("endianness: {}", i.endianness.unwrap_or("".to_string()));
82+
println!("layout:");
83+
}
84+
ConfigItem::FLAGS(i) => {
85+
println!("name: {}", i.name);
86+
println!("offset: {}", i.offset);
87+
println!("endianness: {}", i.endianness.unwrap_or("".to_string()));
88+
println!("layout:");
89+
for l in i.layout {
90+
println!("name: {}", l.name);
91+
println!("position: {}", l.position);
92+
println!("true_label: {}", l.true_label.unwrap_or("".to_string()));
93+
println!("false_label: {}", l.false_label.unwrap_or("".to_string()));
94+
}
95+
}
96+
}
97+
}
98+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
- type: UINT64
2+
name: UINT64_value
3+
offset: 0
4+
size: 8
5+
endianness: LITTLE
6+
- name: UINT32_value
7+
offset: 8
8+
size: 4
9+
type: UINT32
10+
endianness: LITTLE
11+
- name: UINT16_value
12+
offset: 12
13+
size: 2
14+
type: UINT16
15+
endianness: LITTLE
16+
- name: UINT8_value
17+
offset: 14
18+
size: 1
19+
type: UINT8
20+
endianness: LITTLE
21+
- name: BIT_FLAG
22+
offset: 15
23+
size: 1
24+
type: FLAGS
25+
layout:
26+
- name: LED1
27+
position: 0
28+
- name: LED2
29+
position: 1
30+
true_label: "high"
31+
false_label: "low"

0 commit comments

Comments
 (0)