Skip to main content

nom_kconfig/attribute/
depends_on.rs

1#[cfg(feature = "display")]
2use std::fmt::Display;
3
4use nom::{
5    bytes::complete::tag,
6    combinator::{map, opt},
7    IResult, Parser,
8};
9
10use super::expression::parse_expression;
11use crate::{
12    attribute::{expression::parse_if_expression, Expression},
13    util::wsi,
14    KconfigInput,
15};
16#[cfg(feature = "deserialize")]
17use serde::Deserialize;
18#[cfg(feature = "serialize")]
19use serde::Serialize;
20
21/// While normal dependencies reduce the upper limit of a symbol, reverse dependencies can be used to force a lower limit of another symbol. The value of the current menu symbol is used as the minimal value [symbol](crate::Symbol) can be set to. If [symbol](crate::Symbol) is selected multiple times, the limit is set to the largest selection. Reverse dependencies can only be used with boolean or tristate symbols.
22#[derive(Debug, Clone, PartialEq)]
23#[cfg_attr(feature = "hash", derive(Hash))]
24#[cfg_attr(feature = "serialize", derive(Serialize))]
25#[cfg_attr(feature = "deserialize", derive(Deserialize))]
26pub struct DependsOn {
27    pub expression: Expression,
28    #[cfg_attr(
29        any(feature = "serialize", feature = "deserialize"),
30        serde(skip_serializing_if = "Option::is_none")
31    )]
32    pub r#if: Option<Expression>,
33}
34
35/// Parses a `depends on` attribute.
36/// If multiple dependencies are defined, they are connected with '&&'.
37/// Dependencies are applied to all other options within this menu entry (which also accept an "if" expression).
38/// See [https://www.kernel.org/doc/html/next/kbuild/kconfig-language.html#menu-attributes](https://www.kernel.org/doc/html/next/kbuild/kconfig-language.html#menu-attributes) for more information.
39///
40/// # Example
41/// ```
42/// use nom_kconfig::{
43///     assert_parsing_eq,
44///     attribute::{
45///         parse_depends_on,
46///         depends_on::DependsOn,
47///         AndExpression, Atom, Expression, OrExpression, Term,
48///     },
49///     symbol::Symbol,
50///     Attribute
51/// };
52///
53/// assert_parsing_eq!(
54///     parse_depends_on,
55///     "depends on PCI",
56///     Ok((
57///         "",
58///         DependsOn { expression: Expression::Term(AndExpression::Term(
59///             Term::Atom(Atom::Symbol(Symbol::NonConstant("PCI".to_string())))
60///         )), r#if: None }
61///     ))
62/// )
63/// ```
64pub fn parse_depends_on(input: KconfigInput) -> IResult<KconfigInput, DependsOn> {
65    map(
66        (
67            tag("depends"),
68            wsi(opt(tag("on"))),
69            wsi(parse_expression),
70            opt(parse_if_expression),
71        ),
72        |(_, _, e, r#if)| DependsOn {
73            expression: e,
74            r#if,
75        },
76    )
77    .parse(input)
78}
79
80#[cfg(feature = "display")]
81impl Display for DependsOn {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        match &self.r#if {
84            Some(i) => write!(f, "{} if {}", self.expression, i),
85            None => write!(f, "{}", self.expression),
86        }
87    }
88}