Skip to content

Parity: NSCoding: DateIntervalFormatter #2154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 74 additions & 2 deletions CoreFoundation/Locale.subproj/CFDateIntervalFormatter.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,14 @@ CF_INLINE void __CFReleaseIfNotNull(CFTypeRef object) {
}
}

CF_INLINE CFTypeRef __CFRetainIfNotNull(CFTypeRef object) {
if (object) {
CFRetain(object);
}

return object;
}

struct __CFDateIntervalFormatter {
CFRuntimeBase _base;
CFLocaleRef _locale;
Expand Down Expand Up @@ -184,7 +192,7 @@ CFDateIntervalFormatterRef CFDateIntervalFormatterCreate(CFAllocatorRef allocato
__CFGenericValidateType(allocator, CFAllocatorGetTypeID());
memory = (struct __CFDateIntervalFormatter *)_CFRuntimeCreateInstance(allocator, _kCFRuntimeIDCFDateIntervalFormatter, size, NULL);
if (!memory) {
return NULL;
return (CFDateIntervalFormatterRef _Nonnull)NULL;
}

switch (dateStyle) {
Expand All @@ -210,6 +218,9 @@ CFDateIntervalFormatterRef CFDateIntervalFormatterCreate(CFAllocatorRef allocato
break;
}

memory->_dateStyle = dateStyle;
memory->_timeStyle = timeStyle;

memory->_locale = locale ? CFRetain(locale) : NULL;

memory->_calendar = NULL;
Expand All @@ -225,6 +236,67 @@ CFDateIntervalFormatterRef CFDateIntervalFormatterCreate(CFAllocatorRef allocato
return (CFDateIntervalFormatterRef)memory;
}

void _CFDateIntervalFormatterInitializeFromCoderValues(CFDateIntervalFormatterRef formatter,
int64_t dateStyle,
int64_t timeStyle,
CFStringRef _Nullable dateTemplate,
CFStringRef _Nullable dateTemplateFromStyles,
bool modified,
bool useTemplate,
CFLocaleRef _Nullable locale,
CFCalendarRef _Nullable calendar,
CFTimeZoneRef _Nullable timeZone) {
LOCK();
formatter->_dateStyle = dateStyle;
formatter->_timeStyle = timeStyle;

#define __CFSetObjectField(field, value) \
{ \
__auto_type _value = value; \
if (field != _value) { \
__CFReleaseIfNotNull(field); \
field = (__typeof(_value))__CFRetainIfNotNull(_value); \
} \
}

__CFSetObjectField(formatter->_dateTemplate, dateTemplate);
__CFSetObjectField(formatter->_dateTemplateFromStyles, dateTemplateFromStyles);

formatter->_modified = modified;
formatter->_useTemplate = useTemplate;

__CFSetObjectField(formatter->_locale, locale);
__CFSetObjectField(formatter->_calendar, calendar);
__CFSetObjectField(formatter->_timeZone, timeZone);

UNLOCK();
}

void _CFDateIntervalFormatterCopyCoderValues(CFDateIntervalFormatterRef formatter,
int64_t *dateStyle,
int64_t *timeStyle,
CFStringRef _Nullable *dateTemplate,
CFStringRef _Nullable *dateTemplateFromStyles,
bool *modified,
bool *useTemplate,
CFLocaleRef _Nullable *locale,
CFCalendarRef _Nullable *calendar,
CFTimeZoneRef _Nullable *timeZone) {
LOCK();

*dateStyle = formatter->_dateStyle;
*timeStyle = formatter->_timeStyle;
*dateTemplate = __CFRetainIfNotNull(formatter->_dateTemplate);
*dateTemplateFromStyles = __CFRetainIfNotNull(formatter->_dateTemplateFromStyles);
*modified = formatter->_modified;
*useTemplate = formatter->_useTemplate;
*locale = __CFRetainIfNotNull(formatter->_locale);
*calendar = (CFCalendarRef)__CFRetainIfNotNull(formatter->_calendar);
*timeZone = __CFRetainIfNotNull(formatter->_timeZone);

UNLOCK();
}

CFDateIntervalFormatterRef CFDateIntervalFormatterCreateCopy(CFAllocatorRef _Nullable allocator, CFDateIntervalFormatterRef formatter) {
LOCK();
CFDateIntervalFormatterRef newFormatter = CFDateIntervalFormatterCreate(allocator, formatter->_locale, formatter->_dateStyle, formatter->_timeStyle);
Expand Down Expand Up @@ -294,7 +366,7 @@ void CFDateIntervalFormatterSetLocale(CFDateIntervalFormatterRef formatter, CFLo

CFCalendarRef CFDateIntervalFormatterCopyCalendar(CFDateIntervalFormatterRef formatter) {
LOCK();
CFCalendarRef calendar = formatter->_calendar;
CFCalendarRef calendar = (CFCalendarRef)__CFRetainIfNotNull(formatter->_calendar);
if (!calendar) {
if (formatter->_locale) {
calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendar);
Expand Down
22 changes: 22 additions & 0 deletions CoreFoundation/Locale.subproj/CFDateIntervalFormatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ CF_EXPORT CFStringRef CFDateIntervalFormatterCreateStringFromDateInterval(CFDate
CF_EXPORT _CFDateIntervalFormatterBoundaryStyle _CFDateIntervalFormatterGetBoundaryStyle(CFDateIntervalFormatterRef formatter);
CF_EXPORT void _CFDateIntervalFormatterSetBoundaryStyle(CFDateIntervalFormatterRef formatter, _CFDateIntervalFormatterBoundaryStyle boundaryStyle);

CF_EXPORT void _CFDateIntervalFormatterInitializeFromCoderValues(CFDateIntervalFormatterRef formatter,
int64_t dateStyle,
int64_t timeStyle,
CFStringRef _Nullable dateTemplate,
CFStringRef _Nullable dateTemplateFromStyles,
bool modified,
bool useTemplate,
CFLocaleRef _Nullable locale,
CFCalendarRef _Nullable calendar,
CFTimeZoneRef _Nullable timeZone);

CF_EXPORT void _CFDateIntervalFormatterCopyCoderValues(CFDateIntervalFormatterRef formatter,
int64_t *dateStyle,
int64_t *timeStyle,
CFStringRef _Nullable *_Nonnull dateTemplate,
CFStringRef _Nullable *_Nonnull dateTemplateFromStyles,
bool *modified,
bool *useTemplate,
CFLocaleRef _Nullable *_Nonnull locale,
CFCalendarRef _Nullable *_Nonnull calendar,
CFTimeZoneRef _Nullable *_Nonnull timeZone);

CF_EXTERN_C_END
CF_IMPLICIT_BRIDGING_DISABLED
CF_ASSUME_NONNULL_END
Expand Down
24 changes: 23 additions & 1 deletion Foundation/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -550,11 +550,33 @@ internal class __NSSwiftData : NSData {
var _backing: __DataStorage!
var _range: Range<Data.Index>!

override var classForCoder: AnyClass {
return NSData.self
}

override init() {
fatalError()
}

private init(_correctly: Void) {
super.init()
}

convenience init(backing: __DataStorage, range: Range<Data.Index>) {
self.init()
self.init(_correctly: ())
_backing = backing
_range = range
}

public required init?(coder aDecoder: NSCoder) {
fatalError("This should have been encoded as NSData.")
}

override func encode(with aCoder: NSCoder) {
// This should encode this object just like NSData does, and .classForCoder should do the rest.
super.encode(with: aCoder)
}

override var length: Int {
return _range.upperBound - _range.lowerBound
}
Expand Down
75 changes: 73 additions & 2 deletions Foundation/DateIntervalFormatter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ open class DateIntervalFormatter: Formatter {
let core: CFDateIntervalFormatter

public override init() {
core = CFDateIntervalFormatterCreate(nil, nil, kCFDateIntervalFormatterMediumStyle, kCFDateIntervalFormatterMediumStyle)
core = CFDateIntervalFormatterCreate(nil, nil, kCFDateIntervalFormatterShortStyle, kCFDateIntervalFormatterShortStyle)
super.init()
}

Expand All @@ -98,7 +98,78 @@ open class DateIntervalFormatter: Formatter {
}

public required init?(coder: NSCoder) {
NSUnimplemented()
guard coder.allowsKeyedCoding else { fatalError("Requires a keyed coding-capable archiver.") }

func cfObject<T: NSObject & _CFBridgeable>(of aClass: T.Type, from coder: NSCoder, forKey key: String) -> T.CFType? {
if coder.containsValue(forKey: key) {
let object = coder.decodeObject(forKey: key) as? T
return object?._cfObject
} else {
return nil
}
}

let core = CFDateIntervalFormatterCreate(nil, nil, kCFDateIntervalFormatterMediumStyle, kCFDateIntervalFormatterMediumStyle)
_CFDateIntervalFormatterInitializeFromCoderValues(core,
coder.decodeInt64(forKey: "NS.dateStyle"),
coder.decodeInt64(forKey: "NS.timeStyle"),
cfObject(of: NSString.self, from: coder, forKey: "NS.dateTemplate"),
cfObject(of: NSString.self, from: coder, forKey: "NS.dateTemplateFromStyle"),
coder.decodeBool(forKey: "NS.modified"),
coder.decodeBool(forKey: "NS.useTemplate"),
cfObject(of: NSLocale.self, from: coder, forKey: "NS.locale"),
cfObject(of: NSCalendar.self, from: coder, forKey: "NS.calendar"),
cfObject(of: NSTimeZone.self, from: coder, forKey: "NS.timeZone"))
self.core = core

super.init(coder: coder)
}

open override func encode(with aCoder: NSCoder) {
guard aCoder.allowsKeyedCoding else { fatalError("Requires a keyed coding-capable archiver.") }
super.encode(with: aCoder)

var dateStyle: Int64 = 0
var timeStyle: Int64 = 0
var dateTemplate: Unmanaged<CFString>?
var dateTemplateFromStyles: Unmanaged<CFString>?
var modified: Bool = false
var useTemplate: Bool = false
var locale: Unmanaged<CFLocale>?
var calendar: Unmanaged<CFCalendar>?
var timeZone: Unmanaged<CFTimeZone>?

_CFDateIntervalFormatterCopyCoderValues(core,
&dateStyle,
&timeStyle,
&dateTemplate,
&dateTemplateFromStyles,
&modified,
&useTemplate,
&locale,
&calendar,
&timeZone);

aCoder.encode(dateStyle, forKey: "NS.dateStyle")
aCoder.encode(timeStyle, forKey: "NS.timeStyle")

let dateTemplateNS = dateTemplate?.takeRetainedValue()._nsObject
aCoder.encode(dateTemplateNS, forKey: "NS.dateTemplate")

let dateTemplateFromStylesNS = dateTemplateFromStyles?.takeRetainedValue()._nsObject
aCoder.encode(dateTemplateFromStylesNS, forKey: "NS.dateTemplateFromStyles")

aCoder.encode(modified, forKey: "NS.modified");
aCoder.encode(useTemplate, forKey: "NS.useTemplate")

let localeNS = locale?.takeRetainedValue()._nsObject
aCoder.encode(localeNS, forKey: "NS.locale")

let calendarNS = calendar?.takeRetainedValue()._nsObject
aCoder.encode(calendarNS, forKey: "NS.calendar")

let timeZoneNS = timeZone?.takeRetainedValue()._nsObject
aCoder.encode(timeZoneNS, forKey: "NS.timeZone")
}

/*@NSCopying*/ open var locale: Locale! {
Expand Down
19 changes: 13 additions & 6 deletions Foundation/NSCalendar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -174,16 +174,23 @@ open class NSCalendar : NSObject, NSCopying, NSSecureCoding {

self.init(identifier: NSCalendar.Identifier.init(rawValue: calendarIdentifier._swiftObject))

if let timeZone = aDecoder.decodeObject(of: NSTimeZone.self, forKey: "NS.timezone") {
self.timeZone = timeZone._swiftObject
if aDecoder.containsValue(forKey: "NS.timezone") {
if let timeZone = aDecoder.decodeObject(of: NSTimeZone.self, forKey: "NS.timezone") {
self.timeZone = timeZone._swiftObject
}
}
if let locale = aDecoder.decodeObject(of: NSLocale.self, forKey: "NS.locale") {
self.locale = locale._swiftObject
if aDecoder.containsValue(forKey: "NS.locale") {
if let locale = aDecoder.decodeObject(of: NSLocale.self, forKey: "NS.locale") {
self.locale = locale._swiftObject
}
}
self.firstWeekday = aDecoder.decodeInteger(forKey: "NS.firstwkdy")
self.minimumDaysInFirstWeek = aDecoder.decodeInteger(forKey: "NS.mindays")
if let startDate = aDecoder.decodeObject(of: NSDate.self, forKey: "NS.gstartdate") {
self.gregorianStartDate = startDate._swiftObject

if aDecoder.containsValue(forKey: "NS.gstartdate") {
if let startDate = aDecoder.decodeObject(of: NSDate.self, forKey: "NS.gstartdate") {
self.gregorianStartDate = startDate._swiftObject
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Foundation/NSLocale.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import CoreFoundation

open class NSLocale: NSObject, NSCopying, NSSecureCoding {
open class NSLocale: NSObject, NSCopying, NSSecureCoding, _CFBridgeable {
typealias CFType = CFLocale
private var _base = _CFInfo(typeID: CFLocaleGetTypeID())
private var _identifier: UnsafeMutableRawPointer? = nil
Expand Down
8 changes: 7 additions & 1 deletion Foundation/NSTimeZone.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,14 @@ open class NSTimeZone : NSObject, NSCopying, NSSecureCoding, NSCoding {
#endif
}
#endif

super.init()
if !_CFTimeZoneInit(_cfObject, tzName._cfObject, aData?._cfObject) {

/* From https://developer.apple.com/documentation/foundation/nstimezone/1387250-init:
"Discussion
As of macOS 10.6, the underlying implementation of this method has been changed to ignore the specified data parameter."
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cc @compnerd Is this going to be a problem for your implementation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually for Windows, it is the inverse - that is more inline with the current implementation.

*/
if !_CFTimeZoneInit(_cfObject, tzName._cfObject, nil) {
return nil
}
}
Expand Down
Loading