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: 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..5bad84a 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 @@ -538,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 @@ -547,13 +556,38 @@ 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. +-- +-- 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 41f6a15..246eea2 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) @@ -242,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 @@ -253,9 +257,25 @@ 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 +-- | 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/System/OsString/Internal/Types.hs b/System/OsString/Internal/Types.hs index 92c2a8d..6aa28ea 100644 --- a/System/OsString/Internal/Types.hs +++ b/System/OsString/Internal/Types.hs @@ -114,14 +114,22 @@ 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) + 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) + deriving (Eq, Ord, Typeable, Generic, NFData, Lift) instance Show PosixChar where show (PosixChar pc) = show pc @@ -205,8 +213,11 @@ 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) + deriving (Typeable, Generic, NFData, Lift) instance Show OsChar where show (OsChar pc) = show pc diff --git a/changelog.md b/changelog.md index eac926f..c15559c 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,10 @@ # 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` +* Add `fromWord` + ## 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 .