Struct spdx::expression::Expression

source ·
pub struct Expression { /* private fields */ }
Expand description

An SPDX license expression that is both syntactically and semantically valid, and can be evaluated

use spdx::Expression;

let this_is_fine = Expression::parse("MIT OR Apache-2.0").unwrap();
assert!(this_is_fine.evaluate(|req| {
    if let spdx::LicenseItem::Spdx { id, .. } = req.license {
        // Both MIT and Apache-2.0 are OSI approved, so this expression
        // evaluates to true
        return id.is_osi_approved();
    }

   false
}));

assert!(!this_is_fine.evaluate(|req| {
    if let spdx::LicenseItem::Spdx { id, .. } = req.license {
        // This is saying we don't accept any licenses that are OSI approved
        // so the expression will evaluate to false as both sides of the OR
        // are now rejected
        return !id.is_osi_approved();
    }

    false
}));

// `NOPE` is not a valid SPDX license identifier, so this expression
// will fail to parse
let _this_is_not = Expression::parse("MIT OR NOPE").unwrap_err();

Implementations§

source§

impl Expression

source

pub fn minimized_requirements<'lic>( &self, accepted: impl IntoIterator<Item = &'lic Licensee> ) -> Result<Vec<LicenseReq>, MinimizeError>

Given a set of Licensees, attempts to find the minimum number that satisfy this Expression.

The list of licensees should be given in priority order, eg, if you wish to accept the Apache-2.0 license if it is available, and the MIT if not, putting Apache-2.0 before MIT will cause the ubiquitous Apache-2.0 OR MIT expression to minimize to just Apache-2.0 as only 1 of the licenses is required, and Apache-2.0 has priority.

§Errors

This method will fail if more than 64 unique licensees are satisfied by this expression, but such a case is unlikely in a real world scenario. The list of licensees must also actually satisfy this expression, otherwise it can’t be minimized.

§Example
let expr = spdx::Expression::parse("Apache-2.0 OR MIT").unwrap();

let apache_licensee = spdx::Licensee::parse("Apache-2.0").unwrap();
assert_eq!(
    expr.minimized_requirements([&apache_licensee, &spdx::Licensee::parse("MIT").unwrap()]).unwrap(),
    vec![apache_licensee.into_req()],
);
source§

impl Expression

source

pub fn parse(original: &str) -> Result<Self, ParseError>

Given a license expression, attempts to parse and validate it as a valid SPDX expression. Uses ParseMode::Strict.

The validation can fail for many reasons:

  • The expression contains invalid characters
  • An unknown/invalid license or exception identifier was found. Only SPDX short identifiers are allowed
  • The expression contained unbalanced parentheses
  • A license or exception immediately follows another license or exception, without a valid AND, OR, or WITH operator separating them
  • An AND, OR, or WITH doesn’t have a license or ) preceding it
spdx::Expression::parse("MIT OR Apache-2.0 WITH LLVM-exception").unwrap();
source

pub fn canonicalize(original: &str) -> Result<Option<String>, ParseError>

Canonicalizes the input expression into a form that can be parsed with ParseMode::STRICT

§Transforms
  1. ‘/’ is replaced with ’ OR ’
  2. Lower-cased operators (‘or’, ‘and’, ‘with’) are upper-cased
  3. ‘+’ is tranformed to -or-later for GNU licenses
  4. Invalid/imprecise license identifiers (eg. apache2) are replaced with their valid identifiers

If the provided expression is not modified then None is returned

Note that this only does fixup of otherwise valid expressions, passing the resulting string to Expression::parse can still result in additional parse errors, eg. unbalanced parentheses

assert_eq!(spdx::Expression::canonicalize("apache with LLVM-exception/gpl-3.0+").unwrap().unwrap(), "Apache-2.0 WITH LLVM-exception OR GPL-3.0-or-later");
source

pub fn parse_mode(original: &str, mode: ParseMode) -> Result<Self, ParseError>

Parses an expression with the specified ParseMode. With ParseMode::Lax it permits some non-SPDX syntax, such as imprecise license names and “/” used instead of “OR” in exprssions.

spdx::Expression::parse_mode(
    "mit/Apache-2.0 WITH LLVM-exception",
    spdx::ParseMode::LAX
).unwrap();
source§

impl Expression

source

pub fn requirements(&self) -> impl Iterator<Item = &ExpressionReq>

Returns each of the license requirements in the license expression, but not the operators that join them together

let expr = spdx::Expression::parse("MIT AND BSD-2-Clause").unwrap();

assert_eq!(
    &expr.requirements().map(|er| er.req.license.id()).collect::<Vec<_>>(), &[
        spdx::license_id("MIT"),
        spdx::license_id("BSD-2-Clause")
    ]
);
source

pub fn iter(&self) -> impl Iterator<Item = &ExprNode>

Returns both the license requirements and the operators that join them together. Note that the expression is returned in post fix order.

use spdx::expression::{ExprNode, Operator};
let expr = spdx::Expression::parse("Apache-2.0 OR MIT").unwrap();

let mut ei = expr.iter();

assert!(ei.next().is_some()); // Apache
assert!(ei.next().is_some()); // MIT
assert_eq!(*ei.next().unwrap(), ExprNode::Op(Operator::Or));
source

pub fn evaluate<AF: FnMut(&LicenseReq) -> bool>(&self, allow_func: AF) -> bool

Evaluates the expression, using the provided function to determine if the licensee meets the requirements for each license term. If enough requirements are satisfied the evaluation will return true.

use spdx::Expression;

let this_is_fine = Expression::parse("MIT OR Apache-2.0").unwrap();
assert!(this_is_fine.evaluate(|req| {
    // If we find MIT, then we're happy!
    req.license.id() == spdx::license_id("MIT")
}));
source

pub fn evaluate_with_failures<AF: FnMut(&LicenseReq) -> bool>( &self, allow_func: AF ) -> Result<(), Vec<&ExpressionReq>>

Just as with evaluate, the license expression is evaluated to see if enough license requirements in the expression are met for the evaluation to succeed, except this method also keeps track of each failed requirement and returns them, allowing for more detailed error reporting about precisely what terms in the expression caused the overall failure

Trait Implementations§

source§

impl AsRef<str> for Expression

source§

fn as_ref(&self) -> &str

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl Clone for Expression

source§

fn clone(&self) -> Expression

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl Debug for Expression

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Display for Expression

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl PartialEq for Expression

source§

fn eq(&self, o: &Self) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T> ToString for T
where T: Display + ?Sized,

source§

default fn to_string(&self) -> String

Converts the given value to a String. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.