From 673152eebac23659606b34f2ca53e380a4b1349a Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 6 Jun 2026 09:58:01 +0200 Subject: [PATCH 1/5] Add Lift instances for *Char types Fixes #44 --- System/OsString/Internal/Types.hs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/System/OsString/Internal/Types.hs b/System/OsString/Internal/Types.hs index 92c2a8d..b76f631 100644 --- a/System/OsString/Internal/Types.hs +++ b/System/OsString/Internal/Types.hs @@ -115,13 +115,13 @@ type PlatformString = PosixString #endif newtype WindowsChar = WindowsChar { getWindowsChar :: Word16 } - deriving (Eq, Ord, Typeable, Generic, NFData) + deriving (Eq, Ord, Typeable, Generic, NFData, Lift) instance Show WindowsChar where show (WindowsChar wc) = show wc newtype PosixChar = PosixChar { getPosixChar :: Word8 } - deriving (Eq, Ord, Typeable, Generic, NFData) + deriving (Eq, Ord, Typeable, Generic, NFData, Lift) instance Show PosixChar where show (PosixChar pc) = show pc @@ -206,7 +206,7 @@ instance Semigroup OsString where -- On Windows, this is restricted to two-octet codepoints 'Word16', -- on POSIX one-octet ('Word8'). newtype OsChar = OsChar { getOsChar :: PlatformChar } - deriving (Typeable, Generic, NFData) + deriving (Typeable, Generic, NFData, Lift) instance Show OsChar where show (OsChar pc) = show pc From 4c0b8a9ac409784cf204665468d130d4647b7dca Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 6 Jun 2026 11:10:40 +0200 Subject: [PATCH 2/5] Bump mhs in CI --- .github/workflows/mhs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mhs.yaml b/.github/workflows/mhs.yaml index 5eac2cd..a98be3d 100644 --- a/.github/workflows/mhs.yaml +++ b/.github/workflows/mhs.yaml @@ -15,7 +15,7 @@ jobs: matrix: # windows doesn't quite work yet os: [ubuntu-latest, macOS-15-intel, macOS-latest] - mhs: [0.15.0.0] + mhs: [0.16.0.0] steps: From 2a9e26e2a051bb6623b466e52309a97b365408da Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 6 Jun 2026 11:30:32 +0200 Subject: [PATCH 3/5] Bump to 2.0.11 --- changelog.md | 4 ++++ os-string.cabal | 15 ++++++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index eac926f..09296d5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ # Changelog for [`os-string` package](http://hackage.haskell.org/package/os-string) +## 2.0.11 *Jun 2026* + +* Add Lift instance to `OsChar`, `PosixChar` and `WindowsChar` + ## 2.0.10 *Jan 2026* * fix build on GHC 9.14 wrt [#40](https://github.com/haskell/os-string/issues/40) diff --git a/os-string.cabal b/os-string.cabal index 311ff1a..bb8f45b 100644 --- a/os-string.cabal +++ b/os-string.cabal @@ -1,6 +1,6 @@ cabal-version: 2.2 name: os-string -version: 2.0.10 +version: 2.0.11 -- NOTE: Don't forget to update ./changelog.md license: BSD-3-Clause @@ -16,14 +16,11 @@ category: System build-type: Simple synopsis: Library for manipulating Operating system strings. tested-with: - GHC ==8.6.5 - || ==8.8.4 - || ==8.10.7 - || ==9.0.2 - || ==9.2.8 - || ==9.4.8 - || ==9.6.3 - || ==9.8.1 + GHC ==9.6.7 + || ==9.8.4 + || ==9.10.3 + || ==9.12.4 + || ==9.14.1 description: This package provides functionality for manipulating @OsString@ values, and is shipped with . From 3d5f9a4c1c90641f6008df7a948e93e6cf1a0f2b Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Sat, 6 Jun 2026 11:39:27 +0200 Subject: [PATCH 4/5] Add 'fromWord' --- System/OsString.hs | 2 ++ System/OsString/Common.hs | 19 +++++++++++++++++++ System/OsString/Internal.hs | 11 +++++++++++ changelog.md | 1 + 4 files changed, 33 insertions(+) diff --git a/System/OsString.hs b/System/OsString.hs index 65a08c0..5be3764 100644 --- a/System/OsString.hs +++ b/System/OsString.hs @@ -43,6 +43,7 @@ module System.OsString -- * Word construction , unsafeFromChar + , fromWord -- * Word deconstruction , toChar @@ -135,6 +136,7 @@ where import System.OsString.Internal ( unsafeFromChar + , fromWord , toChar , encodeUtf , unsafeEncodeUtf diff --git a/System/OsString/Common.hs b/System/OsString/Common.hs index a6ff920..f605508 100644 --- a/System/OsString/Common.hs +++ b/System/OsString/Common.hs @@ -57,6 +57,7 @@ module System.OsString.MODULE_NAME -- * Word construction , unsafeFromChar + , fromWord -- * Word deconstruction , toChar @@ -210,6 +211,11 @@ import Data.Bifunctor ( bimap ) import qualified System.OsString.Data.ByteString.Short.Word16 as BS16 import qualified System.OsString.Data.ByteString.Short as BS8 +#ifdef WINDOWS +import Data.Word (Word16) +#else +import Data.Word (Word8) +#endif #ifdef WINDOWS_DOC @@ -547,6 +553,19 @@ singleton = coerce BSP.singleton empty :: PLATFORM_STRING empty = mempty +#ifdef WINDOWS +-- | Convert from 'Word16'. +-- +-- @since 2.0.11 +fromWord :: Word16 -> PLATFORM_WORD +fromWord = WindowsChar +#else +-- | Convert from 'Word8'. +-- +-- @since 2.0.11 +fromWord :: Word8 -> PLATFORM_WORD +fromWord = PosixChar +#endif #ifdef WINDOWS -- | Truncates to 2 octets. diff --git a/System/OsString/Internal.hs b/System/OsString/Internal.hs index 41f6a15..3794b5a 100644 --- a/System/OsString/Internal.hs +++ b/System/OsString/Internal.hs @@ -49,6 +49,7 @@ import qualified System.OsString.Posix as PF import GHC.Stack (HasCallStack) import Data.Coerce (coerce) import Data.Type.Coercion (coerceWith) +import Data.Word (Word8) @@ -256,6 +257,16 @@ singleton = coerce PF.singleton unsafeFromChar :: Char -> OsChar unsafeFromChar = coerce PF.unsafeFromChar +-- | Convert from 'Word8'. +-- +-- @since 2.0.11 +fromWord :: Word8 -> OsChar +#if defined(mingw32_HOST_OS) || defined(__MINGW32__) +fromWord = OsChar . WindowsChar . fromIntegral +#else +fromWord = OsChar . PosixChar +#endif + -- | Converts back to a unicode codepoint (total). toChar :: OsChar -> Char toChar = case coercionToPlatformTypes of diff --git a/changelog.md b/changelog.md index 09296d5..c15559c 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ## 2.0.11 *Jun 2026* * Add Lift instance to `OsChar`, `PosixChar` and `WindowsChar` +* Add `fromWord` ## 2.0.10 *Jan 2026* From f51b55e1b1a98fcac64f41622453f03246975e18 Mon Sep 17 00:00:00 2001 From: Julian Ospald Date: Fri, 12 Jun 2026 04:24:36 +0200 Subject: [PATCH 5/5] Improve docs --- System/OsString/Common.hs | 15 +++++++++++++++ System/OsString/Internal.hs | 9 +++++++++ System/OsString/Internal/Types.hs | 11 +++++++++++ 3 files changed, 35 insertions(+) diff --git a/System/OsString/Common.hs b/System/OsString/Common.hs index f605508..5bad84a 100644 --- a/System/OsString/Common.hs +++ b/System/OsString/Common.hs @@ -544,6 +544,9 @@ unpack = coerce BSP.unpack -- Note that using this in conjunction with 'unsafeFromChar' to -- convert from @[Char]@ to platform string is probably not what -- you want, because it will truncate unicode code points. +-- +-- Additionally, a platform word is a byte (or wide char on windows) in an encoded byte sequence, +-- so we're not operating on unicode code points or graphemes here. pack :: [PLATFORM_WORD] -> PLATFORM_STRING pack = coerce BSP.pack @@ -569,10 +572,22 @@ fromWord = PosixChar #ifdef WINDOWS -- | Truncates to 2 octets. +-- +-- Note that 'WindowsChar' is a "wide char" in a UCS-2 encoded byte sequence +-- and is not morally a unicode code point by any means, so +-- this conversion is rarely what you want. +-- +-- Consider using 'fromWord' instead. unsafeFromChar :: Char -> PLATFORM_WORD unsafeFromChar = WindowsChar . fromIntegral . fromEnum #else -- | Truncates to 1 octet. +-- +-- Note that 'PosixChar' is a byte in an encoded byte sequence +-- and is not morally a unicode code point by any means, so +-- this conversion is rarely what you want. +-- +-- Consider using 'fromWord' instead. unsafeFromChar :: Char -> PLATFORM_WORD unsafeFromChar = PosixChar . fromIntegral . fromEnum #endif diff --git a/System/OsString/Internal.hs b/System/OsString/Internal.hs index 3794b5a..246eea2 100644 --- a/System/OsString/Internal.hs +++ b/System/OsString/Internal.hs @@ -243,6 +243,9 @@ unpack = coerce PF.unpack -- Note that using this in conjunction with 'unsafeFromChar' to -- convert from @[Char]@ to 'OsString' is probably not what -- you want, because it will truncate unicode code points. +-- +-- Additionally, 'OsChar' is a byte (or wide char on windows) in an encoded byte sequence, +-- so we're not operating on unicode code points or graphemes here. pack :: [OsChar] -> OsString pack = coerce PF.pack @@ -254,6 +257,12 @@ singleton = coerce PF.singleton -- | Truncates on unix to 1 and on Windows to 2 octets. +-- +-- Note that 'OsChar' is a byte in an encoded byte sequence +-- and is not morally a unicode code point by any means, so +-- this conversion is rarely what you want. +-- +-- Consider using 'fromWord' instead. unsafeFromChar :: Char -> OsChar unsafeFromChar = coerce PF.unsafeFromChar diff --git a/System/OsString/Internal/Types.hs b/System/OsString/Internal/Types.hs index b76f631..6aa28ea 100644 --- a/System/OsString/Internal/Types.hs +++ b/System/OsString/Internal/Types.hs @@ -114,12 +114,20 @@ type PlatformString = WindowsString type PlatformString = PosixString #endif +-- | This represents a "wide char" on windows. +-- +-- A better name would maybe have been @WindowsWord@, since +-- this is just @Word16@ in a UCS-2 sequence. newtype WindowsChar = WindowsChar { getWindowsChar :: Word16 } deriving (Eq, Ord, Typeable, Generic, NFData, Lift) instance Show WindowsChar where show (WindowsChar wc) = show wc +-- | This represents a byte. +-- +-- A better name would maybe have been @PosixWord@, since +-- it is just @Word8@ in an encoded byte sequence. newtype PosixChar = PosixChar { getPosixChar :: Word8 } deriving (Eq, Ord, Typeable, Generic, NFData, Lift) @@ -205,6 +213,9 @@ instance Semigroup OsString where -- -- On Windows, this is restricted to two-octet codepoints 'Word16', -- on POSIX one-octet ('Word8'). +-- +-- This should maybe have been worded @OsWord@, since it is not +-- a unicode code point by any means. It represents a byte in a newtype OsChar = OsChar { getOsChar :: PlatformChar } deriving (Typeable, Generic, NFData, Lift)