// At this point we have an enum and we need to check whether the variants
// appear in sorted order!
//
// When your implementation notices a variant that compares lexicographically
// less than one of the earlier variants, you'll want to construct a syn::Error
// that gets converted to TokenStream by the already existing code that handled
// this conversion during the previous test case.
//
// The "span" of your error, which determines where the compiler places the
// resulting error message, will be the span of whichever variant name that is
// not in the right place. Ideally the error message should also identify which
// other variant the user needs to move this one to be in front of.
use sorted::sorted;
#[sorted]
pub enum Error {
ThatFailed,
ThisFailed,
SomethingFailed,
WhoKnowsWhatFailed,
}
fn main() {}
這裡我們終於接觸到sorted
的核心功能了,那就是排序檢查。
參考錯誤
error: SomethingFailed should sort before ThatFailed
--> tests/03-out-of-order.rs:20:5
|
20 | SomethingFailed,
| ^^^^^^^^^^^^^^^
我們需要找出列舉欄位中的名稱,然後對比排序結果,不符合順序就要提示。
pub(crate) fn check_order(
names: Vec<(String, &dyn quote::ToTokens)>,
) -> std::option::Option<syn::Error> {
let origin_names = names;
let mut sorted_names = origin_names.clone();
// 排序
sorted_names.sort_by(|a, b| a.0.cmp(&b.0));
for (a, b) in origin_names.iter().zip(sorted_names.iter()) {
// 順序不對就報錯
if a.0 != b.0 {
return std::option::Option::Some(syn::Error::new_spanned(
b.1,
format!("{} should sort before {}", b.0, a.0),
));
}
}
std::option::Option::None
}
這裡我們直接使用的是ToTokens
,雖然可以直接使用ident
獲取span
,但是後續的一些情況就得重寫,乾脆用頂級的ToTokens
,相容兩者,避免重複勞動。
pub(crate) fn solution(item: &syn::ItemEnum) -> syn::Result<proc_macro2::TokenStream> {
let mut names: Vec<(String, &dyn quote::ToTokens)> = Vec::new();
for i in item.variants.iter() {
names.push((i.ident.to_string(), &i.ident));
}
match crate::common::check_order(names) {
Some(e) => syn::Result::Err(e),
None => syn::Result::Ok(crate::common::to_token_stream(item)),
}
}
獲取(string, ToTokens)
之後,透過排序檢查即可。
因為上層會自動新增錯誤時候的程式碼解析,這裡直接報錯沒啥問題。
正常來說,涉及錯誤時候都應該使用
Result
,但是我們並沒有想得到任何結果。
因此這裡我使用的是Option<Error>
,正規一點應該是Result<(), Error>
。
本作品採用《CC 協議》,轉載必須註明作者和本文連結