> > +/*
> > + * Refer to the description of ALLOWED_TYPES in
> > + * scripts/tracetool/__init__.py.
> 
> Please don't reference the Python implementation because this will not
> age well. It may bitrot if the Python code changes or if the Python
> implementation is deprecated then the source file will go away
> altogether. Make the Rust implementation self-contained. If there are
> common file format concerns shared by implementations, then move that
> information to a separate document in docs/interop/ (i.e. a simpletrace
> file format specification).

Thanks for your guidance, will do.

> > + */
> > +const ALLOWED_TYPES: [&str; 20] = [
> > +    "int",
> > +    "long",
> > +    "short",
> > +    "char",
> > +    "bool",
> > +    "unsigned",
> > +    "signed",
> > +    "int8_t",
> > +    "uint8_t",
> > +    "int16_t",
> > +    "uint16_t",
> > +    "int32_t",
> > +    "uint32_t",
> > +    "int64_t",
> > +    "uint64_t",
> > +    "void",
> > +    "size_t",
> > +    "ssize_t",
> > +    "uintptr_t",
> > +    "ptrdiff_t",
> > +];
> > +
> > +const STRING_TYPES: [&str; 4] =
> > +    ["const char*", "char*", "const char *", "char *"];
> > +
> > +/* TODO: Support 'vcpu' property. */
> 
> The vcpu property was removed in commit d9a6bad542cd ("docs: remove
> references to TCG tracing"). Is this comment outdated or are you
> planning to bring it back?

Thanks! I have no plan for this, I just follow _VALID_PROPS[] in
scripts/tracetool/__init__.py. As you commented above, I think I should
just ignore it. ;-)

> > +const VALID_PROPS: [&str; 1] = ["disable"];

[snip]

> > +    pub fn build(arg_str: &str) -> Result<Arguments>
> > +    {
> > +        let mut args = Arguments::new();
> > +        for arg in arg_str.split(',').map(|s| s.trim()) {
> > +            if arg.is_empty() {
> > +                return Err(Error::EmptyArg);
> > +            }
> > +
> > +            if arg == "void" {
> > +                continue;
> > +            }
> > +
> > +            let (arg_type, identifier) = if arg.contains('*') {
> > +                /* FIXME: Implement rsplit_inclusive(). */
> > +                let p = arg.rfind('*').unwrap();
> > +                (
> > +                    /* Safe because arg contains "*" and p exists. */
> > +                    unsafe { arg.get_unchecked(..p + 1) },
> > +                    /* Safe because arg contains "*" and p exists. */
> > +                    unsafe { arg.get_unchecked(p + 1..) },
> > +                )
> > +            } else {
> > +                arg.rsplit_once(' ').unwrap()
> > +            };
> 
> Can you write this without unsafe? Maybe rsplit_once(' ') followed by a
> check for (_, '*identifier'). If the identifier starts with '*', then
> arg_type += ' *' and identifier = identifier[1:].

Clever idea! It should work, will try this way.

> > +
> > +            validate_c_type(arg_type)?;
> > +            args.props.push(ArgProperty::new(arg_type, identifier));
> > +        }
> > +        Ok(args)
> > +    }
> > +}
> > +

[snip]

> > +    pub fn build(line_str: &str, lineno: u32, filename: &str) -> 
> > Result<Event>
> > +    {
> > +        static RE: Lazy<Regex> = Lazy::new(|| {
> > +            Regex::new(
> > +                r#"(?x)
> > +                ((?P<props>[\w\s]+)\s+)?
> > +                (?P<name>\w+)
> > +                \((?P<args>[^)]*)\)
> > +                \s*
> > +                (?:(?:(?P<fmt_trans>".+),)?\s*(?P<fmt>".+))?
> 
> What is the purpose of fmt_trans?
> 
> > +                \s*"#,
> > +            )
> > +            .unwrap()
> 
> I wonder if regular expressions help here. It's not easy to read this
> regex and there is a bunch of logic that takes apart the matches
> afterwards. It might even be clearer to use string methods to split
> fields.

Yes, regular matching is a burden here (it's a "lazy simplification" on
my part), and I'll think if it's possible to avoid regular matching with
string methods.

> Please add a comment showing the format that's being parsed:
> 
>  // [disable] <name>(<type1> <arg1>[, <type2> <arg2>] ...) "<format-string>"
> 

OK.

> > +        });
> > +
> > +        let caps_res = RE.captures(line_str);
> > +        if caps_res.is_none() {
> > +            return Err(Error::UnknownEvent(line_str.to_owned()));
> > +        }
> > +        let caps = caps_res.unwrap();
> > +        let name = caps.name("name").map_or("", |m| m.as_str());
> > +        let props: Vec<String> = if caps.name("props").is_some() {
> > +            caps.name("props")
> > +                .unwrap()
> > +                .as_str()
> > +                .split_whitespace()
> > +                .map(|s| s.to_string())
> > +                .collect()
> > +        } else {
> > +            Vec::new()
> > +        };
> > +        let fmt: String =
> > +            caps.name("fmt").map_or("", |m| m.as_str()).to_string();
> > +        let fmt_trans: String = caps
> > +            .name("fmt_trans")
> > +            .map_or("", |m| m.as_str())
> > +            .to_string();
> > +
> > +        if fmt.contains("%m") || fmt_trans.contains("%m") {
> > +            return Err(Error::InvalidFormat(
> > +                "Event format '%m' is forbidden, pass the error 
> > +                as an explicit trace argument"
> > +                    .to_string(),
> > +            ));
> > +        }
> 
> I'm not sure simpletrace needs to check this. That's a job for tracetool
> the build-time tool that generates code from trace-events files.

Thanks for the clarification, this item has bothered me before, I also
noticed that simpletrace doesn't use it, but don't feel confident about
deleting it completely, I'll clean it up!

> > +        if fmt.ends_with(r"\n") {
> > +            return Err(Error::InvalidFormat(
> > +                "Event format must not end with a newline 
> > +                character"
> > +                    .to_string(),
> > +            ));
> > +        }

Thanks,
Zhao


Reply via email to