File indexing completed on 2024-05-12 04:01:51

0001 /*
0002     SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #ifndef SOLID_PREDICATE_H
0008 #define SOLID_PREDICATE_H
0009 
0010 #include <QSet>
0011 #include <QVariant>
0012 
0013 #include <solid/solid_export.h>
0014 
0015 #include <solid/deviceinterface.h>
0016 
0017 namespace Solid
0018 {
0019 class Device;
0020 
0021 /**
0022  * @class Solid::Predicate predicate.h <Solid/Predicate>
0023  *
0024  * This class implements predicates for devices.
0025  *
0026  * A predicate is a logical condition that a given device can match or not.
0027  * It's a constraint about the value a property must have in a given device
0028  * interface, or any combination (conjunction, disjunction) of such
0029  * constraints.
0030  *
0031  * A predicate can be:
0032  * - a single comparison, or
0033  * - a conjunction ("AND") of exactly two predicates, or
0034  * - a disjunction ("OR") of exactly two predicates.
0035  *
0036  * Since these can be nested, it is possible to express "a StorageVolume
0037  * that is not ignored AND that StorageVolume contains a FileSystem
0038  * AND that StorageVolume is removable". Since conjunctions use exactly
0039  * two predicates (and this expression has three), square brackets are
0040  * used to group the nested predicates when writing them out in full:
0041  *
0042  * ```
0043  *   [ [ StorageVolume.ignored == false AND StorageVolume.usage == 'FileSystem' ]
0044  *     AND StorageVolume.removable == true ]
0045  * ```
0046  *
0047  * Predicates can be constructed programmatically by creating single
0048  * comparisons with the Predicate constructor, and then building
0049  * conjunctions with `operator&` and disjunctions with `operator|`.
0050  *
0051  * Predicates can be constructed from a string by calling `fromString()`
0052  * which parses the given string and returns a predicate. If there
0053  * are any errors in parsing the string, an empty predicate is returned;
0054  * use `isValid()` to detect whether that is the case.
0055  *
0056  * The string language is described exactly in `predicate_parser.y`,
0057  * but boils down to:
0058  *
0059  * - a single comparison is written as `<interface>.<property> == <value>`
0060  * - a single bitmask check is written as `<interface>.<property> & <value>`
0061  * - a conjunction is written as `[ <predicate> AND <predicate> ]`
0062  * - a disjunction is written as `[ <predicate> OR <predicate> ]`
0063  *
0064  * Note the mandatory use of `[` and `]` around conjunctions and disjunctions.
0065  */
0066 class SOLID_EXPORT Predicate
0067 {
0068 public:
0069     /**
0070      * The comparison operator which can be used for matching within the predicate.
0071      *
0072      * - Equals, the property and the value will match for strict equality
0073      * - Mask, the property and the value will match if the bitmasking is not null
0074      */
0075     enum ComparisonOperator { Equals, Mask };
0076 
0077     /**
0078      * The predicate type which controls how the predicate is handled
0079      *
0080      * - PropertyCheck, the predicate contains a comparison that needs to be matched using a ComparisonOperator
0081      * - Conjunction, the two contained predicates need to be true for this predicate to be true
0082      * - Disjunction, either of the two contained predicates may be true for this predicate to be true
0083      * - InterfaceCheck, the device type is compared
0084      */
0085     enum Type { PropertyCheck, Conjunction, Disjunction, InterfaceCheck };
0086 
0087     /**
0088      * Constructs an invalid predicate.
0089      */
0090     Predicate();
0091 
0092     /**
0093      * Copy constructor.
0094      *
0095      * @param other the predicate to copy
0096      */
0097     Predicate(const Predicate &other);
0098 
0099     /**
0100      * Constructs a predicate matching the value of a property in
0101      * a given device interface.
0102      *
0103      * @param ifaceType the device interface type the device must have
0104      * @param property the property name of the device interface
0105      * @param value the value the property must have to make the device match
0106      * @param compOperator the operator to apply between the property and the value when matching
0107      */
0108     Predicate(const DeviceInterface::Type &ifaceType, const QString &property, const QVariant &value, ComparisonOperator compOperator = Equals);
0109 
0110     /**
0111      * Constructs a predicate matching the value of a property in
0112      * a given device interface.
0113      *
0114      * @param ifaceName the name of the device interface the device must have
0115      * @param property the property name of the device interface
0116      * @param value the value the property must have to make the device match
0117      * @param compOperator the operator to apply between the property and the value when matching
0118      */
0119     Predicate(const QString &ifaceName, const QString &property, const QVariant &value, ComparisonOperator compOperator = Equals);
0120 
0121     /**
0122      * Constructs a predicate matching devices being of a particular device interface
0123      *
0124      * @param ifaceType the device interface the device must have
0125      */
0126     explicit Predicate(const DeviceInterface::Type &ifaceType);
0127 
0128     /**
0129      * Constructs a predicate matching devices being of a particular device interface
0130      *
0131      * @param ifaceName the name of the device interface the device must have
0132      */
0133     explicit Predicate(const QString &ifaceName);
0134 
0135     /**
0136      * Destroys a Predicate object.
0137      */
0138     ~Predicate();
0139 
0140     /**
0141      * Assignment operator.
0142      *
0143      * @param other the predicate to assign
0144      * @return this predicate after having assigned 'other' to it
0145      */
0146     Predicate &operator=(const Predicate &other);
0147 
0148     /**
0149      * 'And' operator.
0150      *
0151      * @param other the second operand
0152      * @return a new 'and' predicate having 'this' and 'other' as operands
0153      */
0154     Predicate operator&(const Predicate &other);
0155 
0156     /**
0157      * 'AndEquals' operator.
0158      *
0159      * @param other the second operand
0160      * @return assigns to 'this' a new 'and' predicate having 'this' and 'other' as operands
0161      */
0162     Predicate &operator&=(const Predicate &other);
0163 
0164     /**
0165      * 'Or' operator.
0166      *
0167      * @param other the second operand
0168      * @return a new 'or' predicate having 'this' and 'other' as operands
0169      */
0170     Predicate operator|(const Predicate &other);
0171 
0172     /**
0173      * 'OrEquals' operator.
0174      *
0175      * @param other the second operand
0176      * @return assigns to 'this' a new 'or' predicate having 'this' and 'other' as operands
0177      */
0178     Predicate &operator|=(const Predicate &other);
0179 
0180     /**
0181      * Indicates if the predicate is valid.
0182      *
0183      * Predicate() is the only invalid predicate.
0184      *
0185      * @return true if the predicate is valid, false otherwise
0186      */
0187     bool isValid() const;
0188 
0189     /**
0190      * Checks if a device matches the predicate.
0191      *
0192      * @param device the device to match against the predicate
0193      * @return true if the given device matches the predicate, false otherwise
0194      */
0195     bool matches(const Device &device) const;
0196 
0197     /**
0198      * Retrieves the device interface types used in this predicate.
0199      *
0200      * @return all the device interface types used in this predicate
0201      */
0202     QSet<DeviceInterface::Type> usedTypes() const;
0203 
0204     /**
0205      * Converts the predicate to its string form.
0206      *
0207      * @return a string representation of the predicate
0208      */
0209     QString toString() const;
0210 
0211     /**
0212      * Converts a string to a predicate.
0213      *
0214      * @param predicate the string to convert
0215      * @return a new valid predicate if the given string is syntactically
0216      * correct, Predicate() otherwise
0217      */
0218     static Predicate fromString(const QString &predicate);
0219 
0220     /**
0221      * Retrieves the predicate type, used to determine how to handle the predicate
0222      *
0223      * @since 4.4
0224      * @return the predicate type
0225      */
0226     Type type() const;
0227 
0228     /**
0229      * Retrieves the interface type.
0230      *
0231      * @note This is only valid for InterfaceCheck and PropertyCheck types
0232      * @since 4.4
0233      * @return a device interface type used by the predicate
0234      */
0235     DeviceInterface::Type interfaceType() const;
0236 
0237     /**
0238      * Retrieves the property name used when retrieving the value to compare against
0239      *
0240      * @note This is only valid for the PropertyCheck type
0241      * @since 4.4
0242      * @return a property name
0243      */
0244     QString propertyName() const;
0245 
0246     /**
0247      * Retrieves the value used when comparing a devices property to see if it matches the predicate
0248      *
0249      * @note This is only valid for the PropertyCheck type
0250      * @since 4.4
0251      * @return the value used
0252      */
0253     QVariant matchingValue() const;
0254 
0255     /**
0256      * Retrieves the comparison operator used to compare a property's value
0257      *
0258      * @since 4.4
0259      * @note This is only valid for Conjunction and Disjunction types
0260      * @return the comparison operator used
0261      */
0262     ComparisonOperator comparisonOperator() const;
0263 
0264     /**
0265      * A smaller, inner predicate which is the first to appear and is compared with the second one
0266      *
0267      * @since 4.4
0268      * @note This is only valid for Conjunction and Disjunction types
0269      * @return The predicate used for the first operand
0270      */
0271     Predicate firstOperand() const;
0272 
0273     /**
0274      * A smaller, inner predicate which is the second to appear and is compared with the first one
0275      *
0276      * @since 4.4
0277      * @note This is only valid for Conjunction and Disjunction types
0278      * @return The predicate used for the second operand
0279      */
0280     Predicate secondOperand() const;
0281 
0282 private:
0283     class Private;
0284     Private *const d;
0285 };
0286 }
0287 
0288 #endif