packages feed

yamlstar (empty) → 0.1.11.0

raw patch · 7 files changed

+313/−0 lines, 7 filesdep +aesondep +aeson-prettydep +base

Dependencies added: aeson, aeson-pretty, base, bytestring, hspec, text, unix, vector, yamlstar

Files

+ License view
@@ -0,0 +1,21 @@+MIT License++Copyright (c) 2024-2026 yaml.com++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ lib/YAMLStar.hs view
@@ -0,0 +1,66 @@+{-# LANGUAGE OverloadedStrings #-}++module YAMLStar+  ( YAMLStarError(..)+  , loadYAMLStar+  , loadYAMLStarAll+  , dumpYAMLStar+  , dumpYAMLStarAll+  , versionYAMLStar+  ) where++import Control.Exception (Exception, throwIO)+import Control.Monad.IO.Class (MonadIO, liftIO)+import qualified Data.Aeson as Aeson+import qualified Data.Aeson.Key as Key+import qualified Data.Aeson.KeyMap as KeyMap+import qualified Data.ByteString.Lazy as LBS+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import YAMLStar.FFI++data YAMLStarError+  = YAMLStarParseError String+  | YAMLStarRuntimeError String+  | YAMLStarFFIError String+  deriving (Show, Eq)++instance Exception YAMLStarError++loadYAMLStar :: MonadIO m => T.Text -> m Aeson.Value+loadYAMLStar input =+  liftIO $ handleData =<< yamlstarLoadFFI (TE.encodeUtf8 input)++loadYAMLStarAll :: MonadIO m => T.Text -> m Aeson.Value+loadYAMLStarAll input =+  liftIO $ handleData =<< yamlstarLoadAllFFI (TE.encodeUtf8 input)++dumpYAMLStar :: MonadIO m => Aeson.Value -> m T.Text+dumpYAMLStar value =+  liftIO $ handleTextData =<< yamlstarDumpFFI (LBS.toStrict $ Aeson.encode value)++dumpYAMLStarAll :: MonadIO m => Aeson.Value -> m T.Text+dumpYAMLStarAll value =+  liftIO $ handleTextData =<< yamlstarDumpAllFFI (LBS.toStrict $ Aeson.encode value)++versionYAMLStar :: MonadIO m => m T.Text+versionYAMLStar =+  liftIO $ TE.decodeUtf8 <$> yamlstarVersionFFI++handleData :: LBS.ByteString -> IO Aeson.Value+handleData response =+  case Aeson.eitherDecode response of+    Left err -> throwIO $ YAMLStarParseError err+    Right (Aeson.Object obj) ->+      case (KeyMap.lookup (Key.fromString "error") obj, KeyMap.lookup (Key.fromString "data") obj) of+        (Just err, _) -> throwIO $ YAMLStarRuntimeError (show err)+        (_, Just value) -> return value+        _ -> throwIO $ YAMLStarFFIError "Unexpected response from 'libyamlstar'"+    Right _ -> throwIO $ YAMLStarFFIError "Unexpected response from 'libyamlstar'"++handleTextData :: LBS.ByteString -> IO T.Text+handleTextData response = do+  value <- handleData response+  case value of+    Aeson.String text -> return text+    _ -> throwIO $ YAMLStarFFIError "Expected text response from 'libyamlstar'"
+ lib/YAMLStar/FFI.hs view
@@ -0,0 +1,98 @@+{-# LANGUAGE ForeignFunctionInterface #-}+{-# LANGUAGE ScopedTypeVariables #-}++module YAMLStar.FFI+  ( yamlstarLoadFFI+  , yamlstarLoadAllFFI+  , yamlstarDumpFFI+  , yamlstarDumpAllFFI+  , yamlstarVersionFFI+  ) where++import Control.Exception (bracket)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import qualified Data.ByteString.Unsafe as BSU+import Foreign+import Foreign.C.String+import Foreign.C.Types++data GraalCreateIsolateParams+data GraalIsolate+data GraalIsolateThread++type GraalIsolateThreadPtr = Ptr GraalIsolateThread++foreign import ccall "graal_create_isolate"+  c_graal_create_isolate+    :: Ptr GraalCreateIsolateParams+    -> Ptr (Ptr GraalIsolate)+    -> Ptr GraalIsolateThreadPtr+    -> IO CInt++foreign import ccall "graal_tear_down_isolate"+  c_graal_tear_down_isolate :: GraalIsolateThreadPtr -> IO CInt++foreign import ccall "yamlstar_load"+  c_yamlstar_load :: CLLong -> CString -> IO CString++foreign import ccall "yamlstar_load_all"+  c_yamlstar_load_all :: CLLong -> CString -> IO CString++foreign import ccall "yamlstar_dump"+  c_yamlstar_dump :: CLLong -> CString -> IO CString++foreign import ccall "yamlstar_dump_all"+  c_yamlstar_dump_all :: CLLong -> CString -> IO CString++foreign import ccall "yamlstar_version"+  c_yamlstar_version :: CLLong -> IO CString++withGraalIsolate :: (GraalIsolateThreadPtr -> IO a) -> IO a+withGraalIsolate action =+  alloca $ \(isolateThreadPtr :: Ptr GraalIsolateThreadPtr) -> do+    rc <- c_graal_create_isolate nullPtr nullPtr isolateThreadPtr+    if rc /= 0+      then error $ "Failed to create GraalVM isolate (code " ++ show rc ++ ")"+      else do+        isolateThread <- peek isolateThreadPtr+        bracket+          (return isolateThread)+          (\thread -> do+            rc' <- c_graal_tear_down_isolate thread+            if rc' /= 0+              then error $ "Failed to tear down GraalVM isolate (code " ++ show rc' ++ ")"+              else return ())+          action++yamlstarLoadFFI :: BS.ByteString -> IO LBS.ByteString+yamlstarLoadFFI = callWithInput c_yamlstar_load++yamlstarLoadAllFFI :: BS.ByteString -> IO LBS.ByteString+yamlstarLoadAllFFI = callWithInput c_yamlstar_load_all++yamlstarDumpFFI :: BS.ByteString -> IO LBS.ByteString+yamlstarDumpFFI = callWithInput c_yamlstar_dump++yamlstarDumpAllFFI :: BS.ByteString -> IO LBS.ByteString+yamlstarDumpAllFFI = callWithInput c_yamlstar_dump_all++yamlstarVersionFFI :: IO BS.ByteString+yamlstarVersionFFI =+  withGraalIsolate $ \isolateThread -> do+    cResult <- c_yamlstar_version (threadId isolateThread)+    if cResult == nullPtr+      then return BS.empty+      else BS.packCString cResult++callWithInput :: (CLLong -> CString -> IO CString) -> BS.ByteString -> IO LBS.ByteString+callWithInput func input =+  withGraalIsolate $ \isolateThread ->+    BSU.unsafeUseAsCString input $ \cInput -> do+      cResult <- func (threadId isolateThread) cInput+      if cResult == nullPtr+        then return LBS.empty+        else LBS.fromStrict <$> BS.packCString cResult++threadId :: GraalIsolateThreadPtr -> CLLong+threadId = fromIntegral . ptrToIntPtr
+ test/Main.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import qualified Data.Aeson.Encode.Pretty as Aeson+import qualified Data.ByteString.Lazy.Char8 as LBS+import qualified Data.Text as T+import System.Environment (getArgs)+import YAMLStar++main :: IO ()+main = do+  args <- getArgs+  case args of+    [] -> putStrLn "Usage: yamlstar-test <yaml-code>"+    (code:_) -> do+      result <- loadYAMLStar (T.pack code)+      LBS.putStrLn $ Aeson.encodePretty result
+ test/Test.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import qualified Data.Aeson as Aeson+import qualified Data.Text as T+import Test.Hspec+import YAMLStar+import YAMLStar.Tests++main :: IO ()+main = hspec $ do+  describe "YAMLStar" $ do+    basicTests++    it "dumps a mapping" $ do+      result <- dumpYAMLStar $ Aeson.object [("key", Aeson.String "value")]+      result `shouldBe` "key: value\n"++    it "reports the library version" $ do+      result <- versionYAMLStar+      T.unpack result `shouldSatisfy` (not . null)
+ test/YAMLStar/Tests.hs view
@@ -0,0 +1,26 @@+{-# LANGUAGE OverloadedStrings #-}++module YAMLStar.Tests where++import qualified Data.Aeson as Aeson+import qualified Data.Vector as V+import Test.Hspec+import YAMLStar++basicTests :: Spec+basicTests = describe "Basic YAML" $ do+  it "parses simple key-value pairs" $ do+    result <- loadYAMLStar "key: value"+    result `shouldBe` Aeson.object [("key", Aeson.String "value")]++  it "parses lists" $ do+    result <- loadYAMLStar "list: [1, 2, 3]"+    result `shouldBe` Aeson.object+      [ ("list", Aeson.Array $ V.fromList+          [Aeson.Number 1, Aeson.Number 2, Aeson.Number 3])+      ]++  it "loads multiple documents" $ do+    result <- loadYAMLStarAll "---\ndoc1\n---\na: 1\n"+    result `shouldBe` Aeson.Array (V.fromList+      [Aeson.String "doc1", Aeson.object [("a", Aeson.Number 1)]])
+ yamlstar.cabal view
@@ -0,0 +1,62 @@+cabal-version:      3.0+name:               yamlstar+version:            0.1.11.0+synopsis:           Haskell bindings for YAMLStar+description:        Haskell bindings for YAMLStar, a pure YAML 1.2 loader.+license:            MIT+license-file:       License+author:             Ingy dot Net <ingy@ingy.net>+maintainer:         Ingy dot Net <ingy@ingy.net>+category:           Data, Text, YAML+homepage:           https://yamlstar.org+bug-reports:        https://github.com/yaml/yamlstar/issues+tested-with:        GHC==9.4.7, GHC==9.6.3, GHC==9.8.1, GHC==9.12.1++library+    exposed-modules:    YAMLStar+    other-modules:      YAMLStar.FFI+    build-depends:      base >=4.17.0.0 && <5,+                        bytestring ^>=0.11.0.0,+                        text >=2.0.0.0 && <3,+                        aeson >=2.0.0.0 && <3,+                        unix >=2.7.0.0 && <3+    hs-source-dirs:     lib+    default-language:   Haskell2010+    default-extensions: ForeignFunctionInterface+    ghc-options:        -Wall -Wcompat -Widentities+                        -Wincomplete-record-updates+                        -Wincomplete-uni-patterns+                        -Wmissing-home-modules+                        -Wpartial-fields+                        -Wredundant-constraints+    include-dirs:       /tmp/libyamlstar/lib+    extra-libraries:    yamlstar+    extra-lib-dirs:     /tmp/libyamlstar/lib++executable yamlstar-test+    main-is:            Main.hs+    build-depends:      base >=4.17.0.0 && <5,+                        yamlstar,+                        text >=2.0.0.0 && <3,+                        aeson >=2.0.0.0 && <3,+                        aeson-pretty >=0.8.0.0 && <1,+                        bytestring ^>=0.11.0.0+    hs-source-dirs:     test+    default-language:   Haskell2010+    ghc-options:        -Wall++test-suite yamlstar-tests+    type:               exitcode-stdio-1.0+    main-is:            Test.hs+    other-modules:      YAMLStar.Tests+    build-depends:      base >=4.17.0.0 && <5,+                        yamlstar,+                        hspec >=2.8.0.0 && <3,+                        aeson >=2.0.0.0 && <3,+                        text >=2.0.0.0 && <3,+                        unix >=2.7.0.0 && <3,+                        vector >=0.13.0.0 && <1+    hs-source-dirs:     test+    default-language:   Haskell2010+    ghc-options:        -Wall+