Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/orchetect/SwiftRadix
Easily convert integers to binary/hex/octal strings and back again with clean functional syntax.
https://github.com/orchetect/SwiftRadix
binary generics hex hex-strings hexadecimal hexadecimal-string integer integers ios linux macos octal radix radix-strings swift swift5 tvos watchos
Last synced: 3 months ago
JSON representation
Easily convert integers to binary/hex/octal strings and back again with clean functional syntax.
- Host: GitHub
- URL: https://github.com/orchetect/SwiftRadix
- Owner: orchetect
- License: mit
- Created: 2018-06-10T06:55:27.000Z (over 6 years ago)
- Default Branch: main
- Last Pushed: 2024-06-25T03:50:12.000Z (5 months ago)
- Last Synced: 2024-07-25T20:19:04.968Z (4 months ago)
- Topics: binary, generics, hex, hex-strings, hexadecimal, hexadecimal-string, integer, integers, ios, linux, macos, octal, radix, radix-strings, swift, swift5, tvos, watchos
- Language: Swift
- Homepage:
- Size: 214 KB
- Stars: 52
- Watchers: 5
- Forks: 11
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
![SwiftRadix](Images/swiftradix-banner.png)
# SwiftRadix
[![CI Build Status](https://github.com/orchetect/SwiftRadix/actions/workflows/build.yml/badge.svg)](https://github.com/orchetect/SwiftRadix/actions/workflows/build.yml) [![Platforms - macOS 10.10+ | iOS 9+ | tvOS 9+ | watchOS 2+ | visionOS 1+ | Linux](https://img.shields.io/badge/platforms-macOS%2010.10+%20|%20iOS%209+%20|%20tvOS%209+%20|%20watchOS%202+%20|%20visionOS%201+%20|%20Linux-lightgrey.svg?style=flat)](https://swiftpackageindex.com/orchetect/SwiftRadix/builds) [![License: MIT](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat)](https://github.com/orchetect/SwiftRadix/blob/main/LICENSE)
A lightweight library useful for translating integers to and from radix strings (binary, hex, octal or any base) using simple, clean functional syntax.
Compatible with all Apple platforms and Linux.
## Summary
### Common Usage
Unified library with several constructor methods, all of which in turn provide all of the functionality of the library inline.
| Option 1: Function | Option 2: Category method | Returns |
| ------------------ | ------------------------- | --------------------------------------- |
| `Radix(T, base:)` | `.radix(base:)` | `Radix(base: n)` where n is `2...36` |
| `Binary(T)` | `.binary` | `Radix(base: 2)` |
| `Octal(T)` | `.octal` | `Radix(base: 8)` |
| `Hex(T)` | `.hex` | `Radix(base: 16)` |For the sake of simplifying this documentation, `Hex()` / `.hex` will be used for most examples below.
```swift
// convert to or from hex strings255.hex.stringValue // "FF"
255.hex.stringValue(prefix: true) // "0xFF"
255.hex.stringValue(prefix: true, uppercase: false) // "0xff"
"FF".hex?.value // Optional(255)
"0xFF".hex?.value // Optional(255)
"ZZ".hex?.value // nil (not valid hex string, so init fails)// work with arrays of any integer type, or hex strings and convert between them
[0, 255, 0, 255].hex.stringValue // "00 FF 00 FF"
[0, 255, 0, 255].hex.stringValues // ["00", "FF", "00", "FF"]
[0, 255, 0, 255].hex.stringValue(prefixes: true) // "0x00 0xFF 0x00 0xFF"
[0, 255, 0, 255].hex.stringValues(prefixes: true) // ["0x00", "0xFF", "0x00", "0xFF"][0, 255, 0, 255].hex.stringValueArrayLiteral // "[0x0, 0xFF, 0x0, 0xFF]"
[0, 255, 0, 255].hex.stringValueArrayLiteral(padTo: 2) // "[0x00, 0xFF, 0x00, 0xFF]"[0, 65535, 4000].hex.stringValue // "0 FFFF FA0"
[0, 65535, 4000].hex.stringValue(padTo: 2) // "00 FFFF FA0"
[0, 65535, 4000].hex.stringValue(padToEvery: 2) // "00 FFFF 0FA0"
[0, 65535, 4000].hex.stringValue(padToEvery: 4) // "0000 FFFF 0FA0"["00", "FF", "ZZ"].hex.values // [Optional(0), Optional(255), nil]
// test for equatability or perform math operations with great flexibility,
// without needing to extract the .value first, casting or convertingUInt8(123).hex == Int16(123) // true
"FF".hex == 255 // true123.hex + 10.binary - 10 // 123
```## Installation
### Swift Package Manager (SPM)
1. Add SwiftRadix as a dependency using Swift Package Manager.
- In an app project or framework, in Xcode:
- Select the menu: **File → Swift Packages → Add Package Dependency...**
- Enter this URL: `https://github.com/orchetect/SwiftRadix`- In a Swift Package, add it to the Package.swift dependencies:
```swift
.package(url: "https://github.com/orchetect/SwiftRadix", from: "1.3.0")
```### Cocoapods
```bash
pod 'SwiftRadix'
```## Documentation
### Premise
At its core, a new generic type called `Radix` wraps any `BinaryInteger` value, as well as its associated base (radix).
```swift
Radix// constructors
Radix(0xFF, base: 16) // Radix(255)?
Radix(UInt8(0xFF), base: 16) // Radix(255)?
Radix(0xFF, base: 16) // Radix(255)?Radix(0b1111, base: 2) // Radix(15)?
// category method to construct
0xFF.radix(base: 16) // Radix(255)?
0xFF.radix(base: 16, as: UInt8.self) // Radix(255)?
```However, for common bases (binary base-2, octal base-8, hex base-16) you may never need to construct `Radix` directly. Instead, there are convenient functional category methods on common types and collections to shortcut these.
```swift
255.binary // == Radix(0b11111111, base: 2)
"0b11111111".binary // == Radix(255, base: 2)?255.octal // == Radix(0o377, base: 8)
"0o377".octal // == Radix(255, base: 8)?255.hex // == Radix(0xFF, base: 16)
"0xFF".hex // == Radix(255, base: 16)?255.radix(base: 5) // == Radix(255, base: 5)
"2010".radix(base: 5) // == Radix(255, base: 5)?
```You will see how powerful and elegant these can be when combined, further down the README.
### Proxy Constructors
Two invocation styles, producing the same result.
```swift
// proxy constructor function
Hex(123) // Radix(123, base: 16)// functional category property
123.hex // Radix(123, base: 16)
```Any `BinaryInteger` type can be used.
```swift
Int(123).hex // Radix(123)
Int8(123).hex // Radix(123)
UInt8(123).hex // Radix(123)
Int16(123).hex // Radix(123)
UInt16(123).hex // Radix(123)
Int32(123).hex // Radix(123)
UInt32(123).hex // Radix(123)
Int64(123).hex // Radix(123)
UInt64(123).hex // Radix(123)
```A valid hexadecimal string can be used, either containing the prefix `0x` or without it.
This constructor returns an `Optional`, since if the string is not valid hexadecimal, the constructor will fail and `nil` will be returned.
If no integer type is specified, the type will default to `Int`.
```swift
Hex("FF") // Radix(255)?
"FF".hex // Radix(255)?
"0xFF".hex // Radix(255)?"ZZZZ".hex // nil ; not a valid hex string
```To specify an integer type other than `Int`, specify it using `as:`.
```swift
Hex("FF", as: UInt8.self) // Radix(255)?
"FF".hex(as: UInt8.self) // Radix(255)?Hex("FFFFFF", as: UInt8.self) // nil -- 0xFFFFFF does not fit in UInt8, so init fails
"FFFFFF".hex(as: UInt8.self) // nil -- 0xFFFFFF does not fit in UInt8, so init fails
```### Getting and Setting Values
Various methods become available:
```swift
let h = 255.hex // Radix(255)
h.value // Int(255)
h.stringValue // "FF"
h.stringValue(prefix: true) // "0xFF"
h.stringValue(prefix: true, uppercase: false) // "0xff"h.stringValue = "7F" // can also set the hex String and get value...
h.value // 127, type Int
```Padding to *n* number of leading zeros can be specified if you need uniform string formatting:
```swift
0xF.hex.stringValue // "F"
0xF.hex.stringValue(padTo: 2) // "0F"
0xF.hex.stringValue(padTo: 3) // "00F"0xFFFF.hex.stringValue(padTo: 3) // "FFFF" - has no effect; it's > 3 places
```It is also possible to pad leading zeros to every *n* multiple of digit places.
```swift
0xF.hex.stringValue(padToEvery: 2) // "0F"
0xFF.hex.stringValue(padToEvery: 2) // "FF"
0xFFF.hex.stringValue(padToEvery: 2) // "0FFF"
0xFFFF.hex.stringValue(padToEvery: 2) // "FFFF"0x1.hex.stringValue(padToEvery: 4) // "0001"
0x12345.hex.stringValue(padToEvery: 4) // "00012345"
```In addition to padding, strings can be split every *n* digit places, and also in combination with padding.
```swift
0xF.hex.stringValue(padTo: 8, splitEvery: 4) // "0000 000F"
0x123AB.hex.stringValue(padToEvery: 2, splitEvery: 2) // "01 23 AB"
```### Equatability
`Radix` can be tested for equatability directly using typical operators (`==`, `!=`, `>`, `<`) without needing to access the `.value` property. This makes for cleaner, more convenient syntax.
```swift
let h1 = 10.hex // Radix
let h2 = 20.hex // Radixh1.value == h2.value // this works but it's easier to just do this...
h1 == h2 // false
```They can be compared with great flexibility -- even between different integer types directly without requiring casting or conversions.
```swift
let h1 = 10.hex // Radix
let h2 = 20.hex // Radix
h1 == h2 // false (comparing Radix with Radix)
h1 > 20 // true (comparing Radix with Int)
h1 != UInt8(20) // true (comparing Radix with UInt8)// even though "FF".hex produces an Optional,
// the comparison still works safely without requiring the optional to be unwrapped first
"FF".hex == 255 // true
"FF".hex == 255.hex // true
"ZZ".hex == 255.hex // false - optional is nil
```### Additional Operators
Additional operators supported, allowing assignment and bitwise operations directly.
- `+=`, `-=`, `*=`, `/=`, `<<`, `>>`, `&`
### Bitwise Shifting
Traditional binary bit shift left/right is available directly on `Radix`.
```swift
0b0100.hex << 1 // 0b1000
0b0100.hex >> 1 // 0b0010
```### Extensions on Array and Data
#### [BinaryInteger]
Any integer array can be converted to an equivalent `[Radix]` Array:
```swift
let a = [1, 2].hex // [Radix(1), Radix(2)]let arr: [UInt8] = [3, 4]
let b = arr.hex // [Radix(3), Radix(4)]// and back again:
a.values // [1, 2] of type [Int]
b.values // [3, 4] of type [UInt8]
```It can also be flattened into a concatenated `String` or an array of `String`s:
```swift
[0, 255, 0, 255].hex.stringValue // "00 FF 00 FF"
[0, 255, 0, 255].hex.stringValue(prefix: true) // "0x00 0xFF 0x00 0xFF"[0, 255, 0, 255].hex.stringValues // ["00", "FF", "00", "FF"]
[0, 255, 0, 255].hex.stringValues(prefix: true) // ["0x00", "0xFF", "0x00", "0xFF"]
```#### [String]
`String` arrays can also be translated into an array of `Radix?` . The `.values` property produces an unwrapped array of `[Optional]`.
```swift
["00", "0xFF", "ZZ"].hex.values // [Optional(0), Optional(255), nil]
```It is also possible to easily generate a Swift source-compatible array literal.
```swift
let arr = [0, 2, 255]arr.hex.stringValueArrayLiteral // "[0x0, 0x2, 0xFF]"
arr.binary.stringValueArrayLiteral // "[0b0, 0b10, 0b11111111]"
```#### Data
Useful when debugging binary data to the console, or presenting it in a human-readable format easily.
```swift
let d = Data([0x1, 0x2, 0x3, 0xFF])d.hex.stringValue(padTo: 2) // "01 02 03 FF"
```### Bits and Bytes Accessors
A variety of additional methods for reading and manipulating the underlying integer value.
#### Bit
Method: `.bit(Int)`
Subscript: `[bit: Int] { get set }`
- gets single bit value at specified position right-to-left
- subscript can also be used to get or set bit values
- radix-agnostic```swift
var h = 0b1100.binaryh.bit(0) // 0b0.binary
h.bit(2) // 0b1.binaryh[bit: 0] // 0b0 (type T, which is Int in this case)
h[bit: 2] // 0b1 (type T, which is Int in this case)
h[bit: 2] = 0b0
h.value // == 0b1000
```#### Nibble
Method: `.nibble(Int)`
Subscript: `[nibble: Int] { get set }`
- gets nibble (4-bit) value at specified position right-to-left
- subscript can also be used to get or set nibble values
- radix-agnostic```swift
var h = 0x1234.hexh.nibble(0) // 0x4.hex
h.nibble(3) // 0x1.hexh[nibble: 0] // 0x4 (type T, which is Int in this case)
h[nibble: 3] // 0x1 (type T, which is Int in this case)
h[nibble: 3] = 0xF
h.value // == 0xF234
```#### Bytes
`.bytes`
- A convenience property to return the raw bytes of the value as `[UInt8]` based on system endianness
- radix-agnostic```swift
let bytes = 0xFF00.hex.bytesbytes // [0x00, 0xFF]
```## Author
Coded by a bunch of 🐹 hamsters in a trench coat that calls itself [@orchetect](https://github.com/orchetect).
## License
Licensed under the MIT license. See [LICENSE](LICENSE) for details.
## Contributions
Contributions are welcome. Feel free to post an Issue to discuss.