1use std::error::Error;
2use std::fmt;
3mod spdx;
4
5use self::LicenseExpr::*;
6
7#[derive(Debug, Clone, Copy)]
8pub enum LicenseExpr<'a> {
9 License(&'a str),
10 Exception(&'a str),
11 And,
12 Or,
13 With,
14}
15
16impl<'a> fmt::Display for LicenseExpr<'a> {
17 fn fmt(&self, format: &mut fmt::Formatter) -> Result<(), fmt::Error> {
18 match *self {
19 With => format.write_str("WITH"),
20 And => format.write_str("AND"),
21 Or => format.write_str("OR"),
22 License(info) | Exception(info) => format.write_str(info),
23 }
24 }
25}
26
27#[derive(Debug, Clone, Copy)]
28pub enum ParseError<'a> {
29 UnknownLicenseId(&'a str),
30 InvalidStructure(LicenseExpr<'a>),
31}
32
33impl<'a> fmt::Display for ParseError<'a> {
34 fn fmt(&self, format: &mut fmt::Formatter) -> Result<(), fmt::Error> {
35 match *self {
36 ParseError::UnknownLicenseId(info) => {
37 format.write_fmt(format_args!("{}: {}", self.description(), info))
38 }
39 ParseError::InvalidStructure(info) => {
40 format.write_fmt(format_args!("{}: {}", self.description(), info))
41 }
42 }
43 }
44}
45
46impl<'a> Error for ParseError<'a> {
47 fn description(&self) -> &str {
48 match *self {
49 ParseError::UnknownLicenseId(_) => "unknown license or other term",
50 ParseError::InvalidStructure(_) => "invalid license expression",
51 }
52 }
53}
54
55pub fn validate_license_expr(license_expr: &str) -> Result<(), ParseError> {
56 license_expr
57 .split_whitespace()
58 .map(|word| match word {
59 "AND" => Ok(And),
60 "OR" => Ok(Or),
61 "WITH" => Ok(With),
62 _ if spdx::LICENSES
63 .binary_search(&word.trim_end_matches('+'))
64 .is_ok() =>
65 {
66 Ok(License(word))
67 }
68 _ if spdx::EXCEPTIONS.binary_search(&word).is_ok() => Ok(Exception(word)),
69 _ => Err(ParseError::UnknownLicenseId(word)),
70 })
71 .fold(Ok(Or), |prev, word| match (prev, word) {
72 (err @ Err(_), _) | (_, err @ Err(_)) => err,
73 (Ok(License(_)), Ok(With))
74 | (Ok(License(_)), Ok(And))
75 | (Ok(License(_)), Ok(Or))
76 | (Ok(Exception(_)), Ok(And))
77 | (Ok(Exception(_)), Ok(Or))
78 | (Ok(And), Ok(License(_)))
79 | (Ok(Or), Ok(License(_)))
80 | (Ok(With), Ok(Exception(_))) => word,
81 _ => Err(ParseError::InvalidStructure(word.unwrap())),
82 })
83 .and(Ok(()))
84}
85
86pub fn license_version() -> &'static str {
87 spdx::VERSION
88}