1use std::fs;
2use std::fs::DirEntry;
3use std::io;
4use std::io::prelude::*;
5use std::io::Cursor;
6use std::path::Path;
7use std::str::FromStr;
8
9pub struct KeywordReader<R: AsRef<[u8]>>(Cursor<R>);
10
11pub struct PartReader<R: AsRef<[u8]>>(pub KeywordReader<R>);
12
13impl<R: AsRef<[u8]>> Iterator for PartReader<R> {
15 type Item = Option<(String, u64)>;
16
17 fn next(&mut self) -> Option<Self::Item> {
18 match self.0.read_keyword_a().1 {
19 Keyword::Part => Some(Some(self.0.process_part())),
20 Keyword::End => None,
21 _ => Some(None),
22 }
23 }
24}
25
26impl<R: AsRef<[u8]>> KeywordReader<R> {
27 pub fn new(stream: R) -> Self {
28 KeywordReader(Cursor::new(stream))
29 }
30 pub fn read_char(&mut self) -> u8 {
32 let mut char_buf = [b' '; 1];
33 self.0.read_exact(&mut char_buf).expect("!reading a char!");
34 char_buf[0]
35 }
36 pub fn read_line(&mut self) -> String {
38 let mut buf = String::new();
39 self.0.read_line(&mut buf).expect("!reading a line!");
40 buf
41 }
42 pub fn seek_head(&self) -> u64 {
44 self.0.position()
45 }
46 pub fn seek_foward(&mut self, n: u64) {
47 self.0.set_position(self.seek_head() + n)
48 }
49 pub fn seek_back(&mut self, n: u64) {
50 self.0.set_position(self.seek_head() - n)
51 }
52 fn find_keyword(&mut self) {
54 while self.read_char() != b'*' {
55 continue;
56 }
57 }
58 pub fn read_keyword_a(&mut self) -> (u64, Keyword) {
60 self.find_keyword();
61 (
62 self.seek_head() - 1,
63 self.read_line()
64 .parse::<Keyword>()
65 .expect("parse readed keyword"),
66 )
67 }
68 pub fn find_kwd_a(&mut self, kwd: Keyword) -> u64 {
70 let (head, k) = self.read_keyword_a();
71 if kwd as i32 == k as i32 {
72 head
73 } else {
74 self.find_kwd_a(kwd)
75 }
76 }
77 fn consume_comment_line(&mut self) {
79 loop {
80 if self.read_char() == b'$' {
81 self.read_line();
83 } else {
84 self.seek_back(1);
85 break;
86 }
87 }
88 }
89 fn consume_prefix(&mut self) -> String {
91 let ln = self.read_line();
92 let v: Vec<&str> = ln.trim().split(|c| c == '-' || c == '_').collect();
93 v.first().expect("keyword should has title").to_string()
95 }
96 pub fn process_part_attri(&mut self) -> u64 {
99 self.find_keyword();
100 let pref = self.consume_prefix();
101 let s = pref.as_str();
102 match s {
103 "MAT" | "SECTION" => {
104 self.consume_comment_line();
105 self.seek_head()
106 }
107 _ => self.process_part_attri(),
108 }
109 }
110 pub fn process_part(&mut self) -> (String, u64) {
112 self.consume_comment_line();
114 let name = self.read_line().trim().to_string();
115 self.consume_comment_line();
117 dbg!(name, self.seek_head())
119 }
120}
121
122#[derive(Debug, Clone, Copy)]
123pub enum Keyword {
124 Part,
126 Shell,
127 Solid,
128 SetNode,
129 End,
130 Undefined,
131}
132
133#[derive(Debug)]
134pub enum KwdErr {
135 Undefined,
136}
137
138impl FromStr for Keyword {
139 type Err = KwdErr;
140
141 fn from_str(s: &str) -> Result<Self, Self::Err> {
142 match s.trim() {
143 "PART" => Ok(Self::Part),
144 "SECTION_SHELL" => Ok(Self::Shell),
145 "SECTION_SOLID" => Ok(Self::Solid),
146 "SET_NODE_LIST" => Ok(Self::SetNode),
147 "END" => Ok(Self::End),
148 _ => Ok(Self::Undefined),
149 }
150 }
151}
152
153pub fn visit_dirs(dir: &Path, cb: &dyn Fn(&DirEntry)) -> io::Result<()> {
155 if dir.is_dir() {
156 for entry in fs::read_dir(dir)? {
157 let entry = entry?;
158 let path = entry.path();
159 if path.is_dir() {
160 visit_dirs(&path, cb)?;
161 } else {
162 cb(&entry);
163 }
164 }
165 }
166 Ok(())
167}
168
169pub fn print_dir(dir: &Path) -> io::Result<()> {
170 let print_path = |f: &DirEntry| println!("{}", f.path().display());
171 visit_dirs(dir, &print_path)?;
172 Ok(())
173}