         if self === info {
             return true
         }
-        if self.identifier != info.identifier && (self.identifier != info.identifier) {
-            return false
-        }
-        if self.isActive != info.isActive {
-            return false
-        }
-        if self.willRenew != info.willRenew {
-            return false
-        }
-        if self.periodType != info.periodType {
-            return false
-        }
-        if self.latestPurchaseDate != info.latestPurchaseDate {
-            return false
-        }
-        if self.originalPurchaseDate != info.originalPurchaseDate {
-            return false
-        }
-        if self.expirationDate != info.expirationDate {
-            return false
-        }
-        if self.store != info.store {
-            return false
-        }
-        if self.productIdentifier != info.productIdentifier {
-            return false
-        }
-        if self.isSandbox != info.isSandbox {
-            return false
-        }
-        if self.unsubscribeDetectedAt != info.unsubscribeDetectedAt {
-            return false
-        }
-        if self.billingIssueDetectedAt != info.billingIssueDetectedAt {
-            return false
-        }
-        if self.ownershipType != info.ownershipType {
-            return false
-        }
-        return true
+
+        return self.contents == info.contents
     }
 
     public override var hash: Int {
         var hasher = Hasher()
-
-        hasher.combine(self.identifier)
-        hasher.combine(self.isActive)
-        hasher.combine(self.willRenew)
-        hasher.combine(self.periodType)
-        hasher.combine(self.latestPurchaseDate)
-        hasher.combine(self.originalPurchaseDate)
-        hasher.combine(self.expirationDate)
-        hasher.combine(self.store)
-        hasher.combine(self.productIdentifier)
-        hasher.combine(self.isSandbox)
-        hasher.combine(self.unsubscribeDetectedAt)
-        hasher.combine(self.billingIssueDetectedAt)
-        hasher.combine(self.ownershipType)
+        hasher.combine(self.contents)
 
         return hasher.finalize()
     }

    /**
     The entitlement identifier configured in the RevenueCat dashboard
     */
    @objc public let identifier: String

    /**
     True if the user has access to this entitlement
     */
    @objc public let isActive: Bool

    /**
     True if the underlying subscription is set to renew at the end of
     the billing period (``expirationDate``).
     */
    @objc public let willRenew: Bool

    /**
     The last period type this entitlement was in
     Either: ``PeriodType/normal``, ``PeriodType/intro``, ``PeriodType/trial``
     */
    @objc public let periodType: PeriodType

    /**
     The latest purchase or renewal date for the entitlement.
     */
    @objc public let latestPurchaseDate: Date?

    /**
     The first date this entitlement was purchased
     */
    @objc public let originalPurchaseDate: Date?

    /**
     The expiration date for the entitlement, can be `nil` for lifetime access.
     If the ``periodType`` is ``PeriodType/trial``, this is the trial expiration date.
     */
    @objc public let expirationDate: Date?

    /**
     * The store where this entitlement was unlocked from either: ``Store/appStore``, ``Store/macAppStore``,
     * ``Store/playStore``, ``Store/stripe``, ``Store/promotional``, or ``Store/unknownStore``.
     */
    @objc public let store: Store

    /**
     The product identifier that unlocked this entitlement
     */
    @objc public let productIdentifier: String

    /**
     False if this entitlement is unlocked via a production purchase
     */
    @objc public let isSandbox: Bool

    /**
     The date an unsubscribe was detected. Can be `nil`.

     - Note: Entitlement may still be active even if user has unsubscribed. Check the ``isActive`` property.
     */
    @objc public let unsubscribeDetectedAt: Date?

    /**
     The date a billing issue was detected. Can be `nil` if there is no

        subscription: CustomerInfoResponse.Subscription,
        requestDate: Date?
    ) {
        self.contents = .init(
            identifier: identifier,
            isActive: Self.isDateActive(expirationDate: entitlement.expiresDate, forRequestDate: requestDate),
            willRenew: Self.willRenewWithExpirationDate(expirationDate: subscription.expiresDate,
                                                        store: subscription.store,
                                                        unsubscribeDetectedAt: subscription.unsubscribeDetectedAt,
                                                        billingIssueDetectedAt: subscription.billingIssuesDetectedAt),
            periodType: subscription.periodType,
            latestPurchaseDate: entitlement.purchaseDate,
            originalPurchaseDate: subscription.originalPurchaseDate,
            expirationDate: subscription.expiresDate,
            store: subscription.store,
            productIdentifier: entitlement.productIdentifier,
            isSandbox: subscription.isSandbox,
            unsubscribeDetectedAt: subscription.unsubscribeDetectedAt,
            billingIssueDetectedAt: subscription.billingIssuesDetectedAt,
            ownershipType: subscription.ownershipType
        )

        self.rawData = entitlement.rawData
    }

    private let contents: Contents

}

extension EntitlementInfo: RawDataContainer {}

private extension EntitlementInfo {

