public CloudEvent DecodeGenericRecord(GenericRecord record, IEnumerable <ICloudEventExtension> extensions = null)
        {
            if (!record.TryGetValue("attribute", out var attrObj))
            {
                return(null);
            }
            IDictionary <string, object> recordAttributes = (IDictionary <string, object>)attrObj;
            object data = null;

            if (!record.TryGetValue("data", out data))
            {
                data = null;
            }

            CloudEventsSpecVersion specVersion = CloudEventsSpecVersion.Default;
            var cloudEvent = new CloudEvent(specVersion, extensions);

            cloudEvent.Data = data;

            var attributes = cloudEvent.GetAttributes();

            foreach (var keyValuePair in recordAttributes)
            {
                // skip the version since we set that above
                if (keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_1), StringComparison.InvariantCultureIgnoreCase) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V0_2), StringComparison.InvariantCultureIgnoreCase) ||
                    keyValuePair.Key.Equals(CloudEventAttributes.SpecVersionAttributeName(CloudEventsSpecVersion.V1_0), StringComparison.InvariantCultureIgnoreCase))
                {
                    continue;
                }
                if (keyValuePair.Key == CloudEventAttributes.SourceAttributeName(specVersion) ||
                    keyValuePair.Key == CloudEventAttributes.DataSchemaAttributeName(specVersion))
                {
                    attributes[keyValuePair.Key] = new Uri((string)keyValuePair.Value);
                }
                else if (keyValuePair.Key == CloudEventAttributes.TimeAttributeName(specVersion))
                {
                    attributes[keyValuePair.Key] = Timestamps.Parse((string)keyValuePair.Value);
                }
                else
                {
                    attributes[keyValuePair.Key] = keyValuePair.Value;
                }
            }

            return(cloudEvent);
        }
        static string UrlEncodeAttributeAsHeaderValue(string key, object attributeValue,
                                                      CloudEventsSpecVersion specVersion, IEnumerable <ICloudEventExtension> extensions)
        {
            return(WebUtility.UrlEncode(ConvertToString()));

            string ConvertToString()
            {
                switch (attributeValue)
                {
                case string text: return(text);

                case DateTimeOffset dateTimeOffset: return(Timestamps.Format(dateTimeOffset));

                case Uri uri: return(uri.ToString());

                case int integer: return(integer.ToString(CultureInfo.InvariantCulture));

                default:
                    byte[] binaryValue = jsonFormatter.EncodeAttribute(specVersion, key, attributeValue, extensions);
                    return(Encoding.UTF8.GetString(binaryValue));
                }
            };
        }
        void MapHeaders(CloudEvent cloudEvent, bool includeDataContentType)
        {
            string specVersionAttributeName     = CloudEventAttributes.DataAttributeName(cloudEvent.SpecVersion);
            string dataContentTypeAttributeName = CloudEventAttributes.DataContentTypeAttributeName(cloudEvent.SpecVersion);

            foreach (var attribute in cloudEvent.GetAttributes())
            {
                string key        = attribute.Key;
                string headerName = "ce-" + key;
                object value      = attribute.Value;

                // Never map the spec attribute to a header
                if (key == specVersionAttributeName)
                {
                    continue;
                }
                // Only map the data content type attribute to a header if we've been asked to
                else if (key == dataContentTypeAttributeName && !includeDataContentType)
                {
                    continue;
                }
                else
                {
                    string headerValue = attribute.Value switch
                    {
                        string text => WebUtility.UrlEncode(text),
                        ContentType contentType => contentType.ToString(),
                        DateTimeOffset dto => Timestamps.Format(dto),
                        Uri uri => uri.ToString(),
                        int integer => integer.ToString(),
                        _ => WebUtility.UrlEncode(Encoding.UTF8.GetString(
                                                      jsonFormatter.EncodeAttribute(cloudEvent.SpecVersion, key, value, cloudEvent.Extensions.Values)))
                    };
                    Headers.Add(headerName, headerValue);
                }
            }
        }
 protected override DateTimeOffset ParseImpl(string value) => Timestamps.Parse(value);
 protected override string FormatImpl(DateTimeOffset value) => Timestamps.Format(value);