File: TimeValue.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (135 lines) | stat: -rw-r--r-- 4,428 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for Swift project authors
//

// `internal` because `TimeValue.init(_ timespec:)` below is internal and
// references a type (`timespec`) which comes from this import.
internal import _TestingInternals

/// A container type representing a time value that is suitable for storage,
/// conversion, encoding, and decoding.
///
/// This type models time values as durations. When representing a timestamp, an
/// instance of this type represents that timestamp as an offset from an epoch
/// such as the January 1, 1970 POSIX epoch or the system's boot time; which
/// epoch depends on the calling code.
///
/// This type is not part of the public interface of the testing library. Time
/// values exposed to clients of the testing library should generally be
/// represented as instances of ``Test/Clock/Instant`` or a type from the Swift
/// standard library like ``Duration``.
struct TimeValue: Sendable {
  /// The number of whole seconds represented by this instance.
  var seconds: Int64

  /// The number of attoseconds (that is, the subsecond part) represented by
  /// this instance.
  var attoseconds: Int64

  /// The amount of time represented by this instance as a tuple.
  var components: (seconds: Int64, attoseconds: Int64) {
    (seconds, attoseconds)
  }

  init(_ components: (seconds: Int64, attoseconds: Int64)) {
    (seconds, attoseconds) = components
  }

  init(_ timespec: timespec) {
    self.init((Int64(timespec.tv_sec), Int64(timespec.tv_nsec) * 1_000_000_000))
  }

  @available(_clockAPI, *)
  init(_ duration: Duration) {
    self.init(duration.components)
  }

  @available(_clockAPI, *)
  init(_ instant: SuspendingClock.Instant) {
    self.init(unsafeBitCast(instant, to: Duration.self))
  }
}

// MARK: - Equatable, Hashable, Comparable

extension TimeValue: Equatable, Hashable, Comparable {
  static func <(lhs: Self, rhs: Self) -> Bool {
    if lhs.seconds != rhs.seconds {
      return lhs.seconds < rhs.seconds
    }
    return lhs.attoseconds < rhs.attoseconds
  }
}

// MARK: - Codable

extension TimeValue: Codable {}

// MARK: - CustomStringConvertible

extension TimeValue: CustomStringConvertible {
  var description: String {
#if os(WASI)
    // BUG: https://github.com/swiftlang/swift/issues/72398
    return String(describing: Duration(self))
#else
    let (secondsFromAttoseconds, attosecondsRemaining) = attoseconds.quotientAndRemainder(dividingBy: 1_000_000_000_000_000_000)
    let seconds = seconds + secondsFromAttoseconds
    var milliseconds = attosecondsRemaining / 1_000_000_000_000_000
    if seconds == 0 && milliseconds == 0 && attosecondsRemaining > 0 {
      milliseconds = 1
    }

    return withUnsafeTemporaryAllocation(of: CChar.self, capacity: 512) { buffer in
      withVaList([CLongLong(seconds), CInt(milliseconds)]) { args in
        _ = vsnprintf(buffer.baseAddress!, buffer.count, "%lld.%03d seconds", args)
      }
      return String(cString: buffer.baseAddress!)
    }
#endif
  }
}

// MARK: -

@available(_clockAPI, *)
extension Duration {
  init(_ timeValue: TimeValue) {
    self.init(secondsComponent: timeValue.seconds, attosecondsComponent: timeValue.attoseconds)
  }
}

@available(_clockAPI, *)
extension SuspendingClock.Instant {
  init(_ timeValue: TimeValue) {
    self = unsafeBitCast(Duration(timeValue), to: SuspendingClock.Instant.self)
  }
}

extension timespec {
  init(_ timeValue: TimeValue) {
    self.init(tv_sec: .init(timeValue.seconds), tv_nsec: .init(timeValue.attoseconds / 1_000_000_000))
  }
}

extension FloatingPoint {
  /// Initialize this floating-point value with the total number of seconds
  /// (including the subsecond part) represented by an instance of
  /// ``TimeValue``.
  ///
  /// - Parameters:
  ///   - timeValue: The instance of ``TimeValue`` to convert.
  ///
  /// The resulting value may have less precision than `timeValue` as most
  /// floating-point types are unable to represent a time value's
  /// ``TimeValue/attoseconds`` property exactly.
  init(_ timeValue: TimeValue) {
    self = Self(timeValue.seconds) + (Self(timeValue.attoseconds) / (1_000_000_000_000_000_000 as Self))
  }
}