LCOV - code coverage report
Current view: top level - src/lib - shapeid.cpp (source / functions) Coverage Total Hit
Project: Smithy Qt Lines: 92.2 % 153 141
Version: 0.1.0-pre Functions: 85.9 % 64 55

            Line data    Source code
       1              : // SPDX-FileCopyrightText: 2013-2025 Paul Colby <git@colby.id.au>
       2              : // SPDX-License-Identifier: LGPL-3.0-or-later
       3              : 
       4              : /*!
       5              :  * \file
       6              :  * Defines the ShapeId and ShapeIdPrivate classes.
       7              :  */
       8              : 
       9              : #include <qtsmithy/shapeid.h>
      10              : #include "shapeid_p.h"
      11              : 
      12              : #include <QRegularExpression>
      13              : 
      14              : QTSMITHY_BEGIN_NAMESPACE
      15              : 
      16              : /*!
      17              :  * \class ShapeId
      18              :  *
      19              :  * The ShapeId class provides a Qt representation of a Smithy Shape ID.
      20              :  *
      21              :  * \see https://awslabs.github.io/smithy/2.0/spec/model.html#shape-id
      22              :  */
      23              : 
      24              : /*!
      25              :  * Constructs an empty ShapeId object.
      26              :  */
      27         9372 : ShapeId::ShapeId() : d_ptr(new ShapeIdPrivate(this))
      28         7656 : {
      29              : 
      30        14124 : }
      31              : 
      32              : /*!
      33              :  * Constructs a ShapeId object by moving resources from \a other.
      34              :  */
      35          852 : ShapeId::ShapeId(ShapeId &&other) : d_ptr(new ShapeIdPrivate(this))
      36          696 : {
      37          696 :     Q_D(ShapeId);
      38         1284 :     d->memberName = std::move(other.d_ptr->memberName);
      39          696 :     d->nameSpace = std::move(other.d_ptr->nameSpace);
      40          696 :     d->shapeName = std::move(other.d_ptr->shapeName);
      41         1284 : }
      42              : 
      43              : /*!
      44              :  * Constructs a ShapeId object by copying \a other.
      45              :  */
      46          852 : ShapeId::ShapeId(const ShapeId &other) : d_ptr(new ShapeIdPrivate(this))
      47          696 : {
      48          696 :     Q_D(ShapeId);
      49         1284 :     d->memberName = other.d_ptr->memberName;
      50         1284 :     d->nameSpace = other.d_ptr->nameSpace;
      51         1284 :     d->shapeName = other.d_ptr->shapeName;
      52         1284 : }
      53              : 
      54              : /*!
      55              :  * Constructs a ShapeId object by parsing the Smithy Shape ID given by \a shapeId.
      56              :  *
      57              :  * To be considered valid, \a shapeId must contain at least a valid shape name, but may also contain
      58              :  * optional namespace and member name components. Use isValid() to verify \a shapeId's validity.
      59              :  *
      60              :  * \see isValid
      61              :  * \see https://awslabs.github.io/smithy/2.0/spec/model.html#shape-id
      62              :  */
      63        13916 : ShapeId::ShapeId(const QString &shapeId) : d_ptr(new ShapeIdPrivate(this))
      64        11368 : {
      65        11368 :     Q_D(ShapeId);
      66        20972 :     d->setShapeId(shapeId);
      67        20972 : }
      68              : 
      69              : /*!
      70              :  * Assigns the specified \a shapeId to this object.
      71              :  */
      72          588 : ShapeId& ShapeId::operator=(const ShapeId &shapeId)
      73          696 : {
      74          696 :     Q_D(ShapeId);
      75         1284 :     d->memberName = shapeId.d_ptr->memberName;
      76         1284 :     d->nameSpace = shapeId.d_ptr->nameSpace;
      77         1284 :     d->shapeName = shapeId.d_ptr->shapeName;
      78         1284 :     return *this;
      79          696 : }
      80              : 
      81              : /*!
      82              :  * Moves the specified \a shapeId to this object.
      83              :  */
      84          588 : ShapeId& ShapeId::operator=(const ShapeId &&shapeId)
      85          696 : {
      86          696 :     Q_D(ShapeId);
      87         1284 :     d->memberName = std::move(shapeId.d_ptr->memberName);
      88          696 :     d->nameSpace = std::move(shapeId.d_ptr->nameSpace);
      89          696 :     d->shapeName = std::move(shapeId.d_ptr->shapeName);
      90         1284 :     return *this;
      91          696 : }
      92              : 
      93              : /*!
      94              :  * Assigns the specified \a shapeId to this object.
      95              :  */
      96          588 : ShapeId& ShapeId::operator=(const QString &shapeId)
      97          696 : {
      98          696 :     Q_D(ShapeId);
      99         1284 :     d->setShapeId(shapeId);
     100         1284 :     return *this;
     101          696 : }
     102              : 
     103              : /*!
     104              :  * Destroys this ShapeId object.
     105              :  */
     106        17248 : ShapeId::~ShapeId()
     107        20416 : {
     108        37664 :     delete d_ptr;
     109        37664 : }
     110              : 
     111              : /*!
     112              :  * Returns the Shape ID's member name, if it has one, otherwise a null string.
     113              :  */
     114        12322 : QString ShapeId::memberName() const
     115        17110 : {
     116        17110 :     Q_D(const ShapeId);
     117        29432 :     return d->memberName;
     118        17110 : }
     119              : 
     120              : /*!
     121              :  * Returns the Shape ID's namespace, if it has one, otherwise a null string.
     122              :  */
     123        12212 : QString ShapeId::nameSpace() const
     124        16820 : {
     125        16820 :     Q_D(const ShapeId);
     126        29032 :     return d->nameSpace;
     127        16820 : }
     128              : 
     129              : /*!
     130              :  * Returns the Shape ID's shape name, if it has one, otherwise a null string.
     131              :  *
     132              :  * Note, a Shape ID is considered invalid if it has no shape name.
     133              :  *
     134              :  * \see isValid
     135              :  */
     136        11266 : QString ShapeId::shapeName() const
     137        14326 : {
     138        14326 :     Q_D(const ShapeId);
     139        23337 :     return d->shapeName;
     140        14326 : }
     141              : 
     142              : /*!
     143              :  * Set the Shape ID's member name to \a name, which may be an empty or null string.
     144              :  */
     145          588 : void ShapeId::setMemberName(const QString &name)
     146          696 : {
     147          696 :     Q_D(ShapeId);
     148         1284 :     d->memberName = name;
     149         1284 : }
     150              : 
     151              : /*!
     152              :  * Set the Shape ID's namespace to \a name, which may be an empty or null string.
     153              :  */
     154          588 : void ShapeId::setNameSpace(const QString &name)
     155          696 : {
     156          696 :     Q_D(ShapeId);
     157         1284 :     d->nameSpace = name;
     158         1284 : }
     159              : 
     160              : /*!
     161              :  * Set the Shape ID's shape name to \a name.
     162              :  *
     163              :  * Note, a Shape ID is considered invalid if it has no shape name, so \a name should typically be
     164              :  * non-empty.
     165              :  */
     166          588 : void ShapeId::setShapeName(const QString &name)
     167          696 : {
     168          696 :     Q_D(ShapeId);
     169         1284 :     d->shapeName = name;
     170         1284 : }
     171              : 
     172              : /*!
     173              :  * Returns this object as an absolute Smithy Shape ID if this object has a namespace, otherwise a
     174              :  * null string.
     175              :  *
     176              :  * \note, Smithy defines an absolute Shape ID as one that begins with a namespace, therefore it is
     177              :  * not possible to return an absolute Shape ID if no namespace has been set.
     178              :  *
     179              :  * \note, if the Shape ID is invalid (ie isValid() returns \c false) it still safe to invoke this
     180              :  * method, but the result is undefined.
     181              :  *
     182              :  * \see setNameSpace
     183              :  * \see isValid
     184              :  */
     185          931 : QString ShapeId::absoluteShapeId() const
     186         1102 : {
     187         3818 :     return hasNameSpace() ? QStringLiteral("%1#%2").arg(nameSpace(), relativeShapeId()) : QString();
     188         1102 : }
     189              : 
     190              : /*!
     191              :  * Returns this object as a relative Smithy Shape ID, that one without a leading namespace.
     192              :  *
     193              :  * \note, if the Shape ID is invalid (ie isValid() returns \c false) it still safe to invoke this
     194              :  * method, but the result is undefined.
     195              :  *
     196              :  * \see isValid
     197              :  */
     198         1519 : QString ShapeId::relativeShapeId() const
     199         1798 : {
     200         5814 :     return hasMemberName() ? QStringLiteral("%1$%2").arg(shapeName(), memberName()) : shapeName();
     201         1798 : }
     202              : 
     203              : /*!
     204              :  * Returns this object as an *absolute* Smithy Shape ID if this object has a namespace, otherwise a
     205              :  * *relative* Smithy Shape ID.
     206              :  *
     207              :  * \note, if the Shape ID is invalid (ie isValid() returns \c false) it still safe to invoke this
     208              :  * method, but the result is undefined.
     209              :  *
     210              :  * \see absoluteShapeId
     211              :  * \see relativeShapeId
     212              :  * \see isValid
     213              :  */
     214          588 : QString ShapeId::toString() const
     215          696 : {
     216         1284 :     return hasNameSpace() ? absoluteShapeId() : relativeShapeId();
     217          696 : }
     218              : 
     219              : /*!
     220              :  * Returns \c true if this Shape ID has a non-empty namespace, otherwise \c false otherwise.
     221              :  *
     222              :  * \see nameSpace.
     223              :  * \see setNameSpace.
     224              :  */
     225         2940 : bool ShapeId::hasNameSpace() const
     226         3480 : {
     227         6420 :     return !nameSpace().isEmpty();
     228         3480 : }
     229              : 
     230              : /*!
     231              :  * Returns \c true if this Shape ID has a non-empty member name, otherwise \c false otherwise.
     232              :  *
     233              :  * \see memberName.
     234              :  * \see setMemberName.
     235              :  */
     236         2891 : bool ShapeId::hasMemberName() const
     237         3422 : {
     238         6313 :     return !memberName().isEmpty();
     239         3422 : }
     240              : 
     241              : /*!
     242              :  * Returns \c true if this Shape ID is a *root* Shape ID, and has a namespace, \c false otherwise.
     243              :  *
     244              :  * \see isRootShapeId.
     245              :  * \see hasNameSpace.
     246              :  */
     247          588 : bool ShapeId::isAbsoluteRootShapeId() const
     248          696 : {
     249         1284 :     return isRootShapeId() && hasNameSpace();
     250          696 : }
     251              : 
     252              : /*!
     253              :  * Returns \c true if this Shape ID is a *root* Shape ID, \c false otherwise.
     254              :  *
     255              :  * \note, Smithy defines a root Shape ID as one that does not have a member name.
     256              :  *
     257              :  * \see hasMemberName.
     258              :  */
     259          460 : bool ShapeId::isRootShapeId() const
     260          928 : {
     261         1712 :     return !hasMemberName();
     262          928 : }
     263              : 
     264              : /*!
     265              :  * Returns \c true if this Shape ID is a *relative* Shape ID, \c false otherwise.
     266              :  *
     267              :  * \note, Smithy defines a relative Shape ID as one that does not have a namespace.
     268              :  *
     269              :  * \see hasNameSpace.
     270              :  */
     271          588 : bool ShapeId::isRelativeShapeId() const
     272          696 : {
     273         1284 :     return !hasNameSpace();
     274          696 : }
     275              : 
     276              : /*!
     277              :  * Returns true if this object represents a valid, non-empty Smithy Shape ID.
     278              :  *
     279              :  * \see https://awslabs.github.io/smithy/2.0/spec/model.html#shape-id
     280              :  */
     281         8820 : bool ShapeId::isValid() const
     282        10440 : {
     283        10440 :     Q_D(const ShapeId);
     284              :     // Validate the (optional) namespace.
     285        19260 :     if (!d->nameSpace.isEmpty()) {
     286         8268 :         static QRegularExpression namespacePattern(QStringLiteral("^(_*[a-zA-Z]\\w*\\.?)+(?<!\\.)$"));
     287         4466 :         Q_ASSERT(namespacePattern.isValid());
     288         8239 :         if (!namespacePattern.match(d->nameSpace).hasMatch()) {
     289         1276 :             return false;
     290         1276 :         }
     291         4466 :     }
     292              : 
     293              :     // Validate the (required) shape name.
     294        16935 :     static QRegularExpression identifierPattern(QStringLiteral("^_*[a-zA-Z]\\w*$"));
     295         9164 :     Q_ASSERT(identifierPattern.isValid());
     296        19601 :     if ((d->shapeName.isEmpty()) || (!identifierPattern.match(d->shapeName).hasMatch())) {
     297         5974 :         return false;
     298         5974 :     }
     299              : 
     300              :     // Validate the (optional) member name.
     301         6424 :     if ((!d->memberName.isEmpty()) && (!identifierPattern.match(d->memberName).hasMatch())) {
     302          638 :         return false;
     303          638 :     }
     304         2552 :     return true; // Valid.
     305         3190 : }
     306              : 
     307            0 : bool ShapeId::operator==(const ShapeId &other) const
     308            0 : {
     309            0 :     Q_D(const ShapeId);
     310            0 :     return (d->memberName == other.d_ptr->memberName) &&
     311            0 :            (d->nameSpace == other.d_ptr->nameSpace)   &&
     312            0 :            (d->shapeName == other.d_ptr->shapeName);
     313            0 : }
     314              : 
     315              : #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
     316            0 : uint qHash(const ShapeId &key, uint seed)
     317              : #else
     318            0 : size_t qHash(const ShapeId &key, size_t seed)
     319              : #endif
     320            0 : {
     321            0 :     return ::qHash(key.toString(), seed);
     322            0 : }
     323              : 
     324              : /*!
     325              :  * \cond internal
     326              :  * \class ShapeIdPrivate
     327              :  *
     328              :  * The ShapeIdPrivate class provides private implementation for ShapeId.
     329              :  */
     330              : 
     331              : /*!
     332              :  * \internal
     333              :  * Constructs a new ShapeIdPrivate object with public implementation \a q.
     334              :  */
     335        21104 : ShapeIdPrivate::ShapeIdPrivate(ShapeId * const q) : q_ptr(q)
     336        20416 : {
     337              : 
     338        28160 : }
     339              : 
     340              : /*!
     341              :  * Splits \a shapeId into its components (namespace, shape name and member name) and assigns them
     342              :  * to the equivalent object members.
     343              :  *
     344              :  * Both the namespace and member name are optional; their equivalent object members will be set to
     345              :  * empty strings if not present in \a shapeId.
     346              :  */
     347        10780 : void ShapeIdPrivate::setShapeId(const QString &shapeId)
     348        12760 : {
     349        23540 :     const int sep1 = shapeId.indexOf(QLatin1Char('#'));
     350        23540 :     const int sep2 = shapeId.lastIndexOf(QLatin1Char('$'));
     351        26868 :     if (sep1 > 0) nameSpace = shapeId.mid(0, sep1);
     352        27336 :     if (sep2 > 0) memberName = shapeId.mid(sep2+1);
     353        23540 :     shapeName = shapeId.mid(sep1+1, sep2-sep1-1);
     354        23540 : }
     355              : 
     356              : /// \endcond
     357              : 
     358              : QTSMITHY_END_NAMESPACE
        

Generated by: LCOV version 2.2-1