proc-macro-workshop:sorted-7

审题

// The macro won't need to define what it means for other sorts of patterns to
// be sorted. It should be fine to trigger an error if any of the patterns is
// not something that can be compared by path.
//
// Be sure that the resulting error message is understandable and placed
// correctly underlining the unsupported pattern.

#[sorted::check]
fn f(bytes: &[u8]) -> Option<u8> {
    #[sorted]
    match bytes {
        [] => Some(0),
        [a] => Some(*a),
        [a, b] => Some(a + b),
        _other => None,
    }
}

fn main() {}

这里主要说明的是,我们只能排序能排序的。
rustmatch功能十分强大,并非只是简单的字符枚举匹配,还有很多的数据匹配。
对于这种,我们并不需要完全的支持。

题解


impl syn::visit_mut::VisitMut for MatchVisitor {
    fn visit_expr_match_mut(&mut self, i: &mut syn::ExprMatch) {
        let mut target_idx: isize = -1;
        for (idx, attr) in i.attrs.iter().enumerate() {
            if path_to_string(&attr.path) == "sorted" {
                target_idx = idx as isize;
                break;
            }
        }
        if target_idx != -1 {
            i.attrs.remove(target_idx as usize);
            let mut match_arm_names: Vec<(String, &dyn quote::ToTokens)> = Vec::new();
            for arm in i.arms.iter() {
                match &arm.pat {
                    syn::Pat::Path(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::TupleStruct(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::Struct(p) => {
                        match_arm_names.push((path_to_string(&p.path), &p.path));
                    }
                    syn::Pat::Ident(p) => {
                        match_arm_names.push((p.ident.to_string(), &p.ident));
                    }
                    syn::Pat::Wild(p) => {
                        match_arm_names.push(("_".to_string(), &p.underscore_token));
                    }
                    _ => {
                        self.err = std::option::Option::Some(syn::Error::new_spanned(
                            &arm.pat,
                            "unsupported by #[sorted]",
                        ));
                        return;
                    }
                }
            }
            if let Some(e) = check_order(match_arm_names) {
                self.err = std::option::Option::Some(e);
                return;
            }
        }
        syn::visit_mut::visit_expr_match_mut(self, i)
    }
}

sorted-5中我们解析其他类型的时候,最后一个分支我们提示了一个错误。
其实就是这一关的提示错误

error: unsupported by #[sorted]
  --> tests/07-unrecognized-pattern.rs:12:9
   |
12 |         [] => Some(0),
   |  

虽然我是后续整理合二为一的,但是我相信,只要保持良好的编码习惯,这种错误提示的相似性甚至一致性,是必然的结果。多多努力。

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!