Skip to content
This repository was archived by the owner on Dec 15, 2024. It is now read-only.

Commit

Permalink
Fixed Date for WASM
Browse files Browse the repository at this point in the history
Use JS implementation for now
  • Loading branch information
colemancda committed Jun 6, 2020
1 parent ae7093c commit 71f6970
Show file tree
Hide file tree
Showing 3 changed files with 170 additions and 61 deletions.
46 changes: 39 additions & 7 deletions Sources/SwiftFoundation/Date.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,60 @@ public struct Date: Equatable, Hashable {
The distant past is in terms of centuries.
*/
public static var distantPast: SwiftFoundation.Date { return Date(timeIntervalSinceReferenceDate: -63114076800.0) }

/// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time.
public static var timeIntervalSinceReferenceDate: TimeInterval {
return self.timeIntervalSince1970 - self.timeIntervalBetween1970AndReferenceDate
}

// MARK: - Properties

/// The time interval between the date and the reference date (1 January 2001, GMT).
public var timeIntervalSinceReferenceDate: TimeInterval

/// The time interval between the current date and 1 January 1970, GMT.
/**
The time interval between the date and the current date and time.

If the date is earlier than the current date and time, the this property’s value is negative.

- SeeAlso: `timeIntervalSince(_:)`
- SeeAlso: `timeIntervalSince1970`
- SeeAlso: `timeIntervalSinceReferenceDate`
*/
public var timeIntervalSinceNow: TimeInterval {
return timeIntervalSinceReferenceDate - Date.timeIntervalSinceReferenceDate
}

/**
The interval between the date object and 00:00:00 UTC on 1 January 1970.

This property’s value is negative if the date object is earlier than 00:00:00 UTC on 1 January 1970.

- SeeAlso: `timeIntervalSince(_:)`
- SeeAlso: `timeIntervalSinceNow`
- SeeAlso: `timeIntervalSinceReferenceDate`
*/
public var timeIntervalSince1970: TimeInterval {
get { return timeIntervalSinceReferenceDate + Date.timeIntervalBetween1970AndReferenceDate }
set { timeIntervalSinceReferenceDate = newValue - Date.timeIntervalBetween1970AndReferenceDate }
return timeIntervalSinceReferenceDate + Date.timeIntervalBetween1970AndReferenceDate
}

// MARK: - Initialization

/// Returns a `Date` initialized to the current date and time.
public init() {
self.init(timeIntervalSinceReferenceDate: Date.timeIntervalSinceReferenceDate)
}

/// Returns an `Date` initialized relative to 00:00:00 UTC on 1 January 2001 by a given number of seconds.
public init(timeIntervalSinceReferenceDate timeInterval: TimeInterval) {
self.timeIntervalSinceReferenceDate = timeInterval
}

/// Returns a `Date` initialized relative to the current date and time by a given number of seconds.
public init(timeIntervalSinceNow: TimeInterval) {
self.timeIntervalSinceReferenceDate = timeIntervalSinceNow + Date.timeIntervalSinceReferenceDate
}

/// Returns a `Date` initialized relative to 00:00:00 UTC on 1 January 1970 by a given number of seconds.
public init(timeIntervalSince1970: TimeInterval) {
self.timeIntervalSinceReferenceDate = timeIntervalSince1970 - Date.timeIntervalBetween1970AndReferenceDate
Expand Down Expand Up @@ -95,13 +130,12 @@ public struct Date: Equatable, Hashable {
}
}

#if !arch(wasm32)

// MARK: - CustomStringConvertible

extension SwiftFoundation.Date: CustomStringConvertible {

public var description: String {
// TODO: Custom date printing
return timeIntervalSinceReferenceDate.description
}
}
Expand All @@ -115,8 +149,6 @@ extension SwiftFoundation.Date: CustomDebugStringConvertible {
}
}

#endif

// MARK: - Comparable

extension SwiftFoundation.Date: Comparable {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftFoundation/POSIXError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal extension POSIXError {
function: StaticString = #function) -> POSIXError {

guard let code = POSIXErrorCode(rawValue: errno)
else { fatalError("Invalid POSIX Error \(errno)") }
else { fatalError("Invalid POSIX Error \(errno)", file: file, line: line) }

return POSIXError(code: code)
}
Expand Down
183 changes: 130 additions & 53 deletions Sources/SwiftFoundation/POSIXTime.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,98 +12,84 @@ import Darwin.C
import Glibc
#endif

#if !arch(wasm32)

// MARK: - Date

public extension Date {

/// The interval between 00:00:00 UTC on 1 January 2001 and the current date and time.
static var timeIntervalSinceReferenceDate: TimeInterval {
do { return try timeval.timeOfDay().timeInterval - Date.timeIntervalBetween1970AndReferenceDate }
catch { fatalError("Unable to load current time") }
}

/// Returns a `Date` initialized to the current date and time.
init() {
self.timeIntervalSinceReferenceDate = Date.timeIntervalSinceReferenceDate
}
internal extension Date {

/// Returns a `Date` initialized relative to the current date and time by a given number of seconds.
init(timeIntervalSinceNow: TimeInterval) {
self.timeIntervalSinceReferenceDate = timeIntervalSinceNow + Date.timeIntervalSinceReferenceDate
/// Get seconds since Unix epoch (01/01/1970).
static var timeIntervalSince1970: TimeInterval {

do {
#if arch(wasm32)
return WebAssembly.timeIntervalSince1970()
#else
if #available(macOS 10.12, iOS 10, tvOS 10.0, *) {
return try SystemClock.realTime.time().timeInterval
} else {
return try timeval.now().timeInterval
}
#endif
}
catch { fatalError("Unable to get current date \(error)") }
}
}

// MARK: - WASM Fix

#if arch(wasm32)
public extension Date {

/**
The time interval between the date and the current date and time.

If the date is earlier than the current date and time, the this property’s value is negative.

- SeeAlso: `timeIntervalSince(_:)`
- SeeAlso: `timeIntervalSince1970`
- SeeAlso: `timeIntervalSinceReferenceDate`
*/
var timeIntervalSinceNow: TimeInterval {
return timeIntervalSinceReferenceDate - Date.timeIntervalSinceReferenceDate
public enum WebAssembly {

public static var timeIntervalSince1970: () -> TimeInterval = { return try! timeval.now().timeInterval } // won't work
}
}
#endif

// MARK: - POSIX Time

internal extension timeval {

static func timeOfDay() throws -> timeval {
static func now() throws -> timeval {

var timeStamp = timeval()
guard gettimeofday(&timeStamp, nil) == 0
else { throw POSIXError.fromErrno() }
return timeStamp
}

init(timeInterval: SwiftFoundation.TimeInterval) {
init(timeInterval: Double) {

let (integerValue, decimalValue) = modf(timeInterval)

let million: SwiftFoundation.TimeInterval = 1000000.0

let million: Double = 1000000.0
let microseconds = decimalValue * million

self.init(tv_sec: .init(integerValue), tv_usec: .init(microseconds))
}

var timeInterval: SwiftFoundation.TimeInterval {

let secondsSince1970 = SwiftFoundation.TimeInterval(self.tv_sec)

let million: SwiftFoundation.TimeInterval = 1000000.0

let microseconds = SwiftFoundation.TimeInterval(self.tv_usec) / million
var timeInterval: Double {

let secondsSince1970 = Double(self.tv_sec)
let million: Double = 1000000.0
let microseconds = Double(self.tv_usec) / million
return secondsSince1970 + microseconds
}
}

internal extension timespec {

init(timeInterval: SwiftFoundation.TimeInterval) {
init(timeInterval: Double) {

let (integerValue, decimalValue) = modf(timeInterval)

let billion: SwiftFoundation.TimeInterval = 1000000000.0

let billion: Double = 1000000000.0
let nanoseconds = decimalValue * billion

self.init(tv_sec: .init(integerValue), tv_nsec: .init(nanoseconds))
}

var timeInterval: SwiftFoundation.TimeInterval {

let secondsSince1970 = SwiftFoundation.TimeInterval(self.tv_sec)

let billion: SwiftFoundation.TimeInterval = 1000000000.0

let nanoseconds = SwiftFoundation.TimeInterval(self.tv_nsec) / billion
var timeInterval: Double {

let secondsSince1970 = Double(self.tv_sec)
let billion: Double = 1000000000.0
let nanoseconds = Double(self.tv_nsec) / billion
return secondsSince1970 + nanoseconds
}
}
Expand All @@ -123,8 +109,99 @@ internal extension tm {
}
}

#if arch(wasm32)
internal struct SystemClock: RawRepresentable, Equatable, Hashable {
let rawValue: UInt32
init(rawValue: UInt32) {
self.rawValue = rawValue
}
}
#else
@available(macOS 10.12, iOS 10, tvOS 10.0, *)
internal typealias SystemClock = clockid_t
#endif

#if !arch(wasm32)
@available(macOS 10.12, iOS 10, tvOS 10.0, *)
internal extension SystemClock {


func time() throws -> timespec {
var time = timespec()
guard clock_gettime(self, &time) == 0
else { throw POSIXError.fromErrno() }
return time
}

#if os(macOS) || os(Linux) // not supported on iOS
func setTime(_ newValue: timespec) throws {
guard withUnsafePointer(to: newValue, { clock_settime(self, $0) == 0 })
else { throw POSIXError.fromErrno() }
}
#endif
}

#endif

#if arch(wasm32)
@_silgen_name("clock_gettime")
internal func wasm_clock_gettime() -> Int32 // crashes with current swift-wasm

/**

Return the time value of a clock. Note: This is similar to clock_gettime in POSIX.

`clock_time_get(id: clockid, precision: timestamp) -> (errno, timestamp)`

- Parameter id: clockid The clock for which to return the time.
- Parameter precision: timestamp The maximum lag (exclusive) that the returned time value may have, compared to its actual value.
- Returns: error: errno
time: timestamp The time value of the clock.

https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
*/
@_silgen_name("clock_time_get")
internal func wasm_clock_time_get(_ id: UInt32, _ precision: UInt64, _ time: inout UInt64) -> Int16
#endif

@available(macOS 10.12, iOS 10, tvOS 10.0, *)
internal extension SystemClock {

/**
System-wide clock that measures real (i.e., wall-clock) time. Setting this clock requires appropriate privileges. This clock is affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), and by the incremental adjustments performed by adjtime(3) and NTP.
*/
static var realTime: SystemClock {
#if arch(wasm32)
return .init(rawValue: 0)
#else
return CLOCK_REALTIME
#endif
}

/**
Clock that cannot be set and represents monotonic time since some unspecified starting point. This clock is not affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP.
*/
static var monotonic: SystemClock {
#if arch(wasm32)
return .init(rawValue: 1)
#else
return CLOCK_MONOTONIC
#endif
}

#if os(Linux)
/// A faster but less precise version of CLOCK_REALTIME. Use when you need very fast, but not fine-grained timestamps.
static var realTimeCourse: SystemClock { // (since Linux 2.6.32; Linux-specific)
return CLOCK_REALTIME_COARSE
}

/// A faster but less precise version of CLOCK_MONOTONIC. Use when you need very fast, but not fine-grained timestamps.
static var monotonicCourse: SystemClock { // (since Linux 2.6.32; Linux-specific)
return CLOCK_MONOTONIC_COARSE
}
#endif
}

// MARK: - Cross-Platform Support

#if canImport(Darwin)
Expand Down

0 comments on commit 71f6970

Please sign in to comment.