iri 0.4 → 0.5
raw patch · 39 files changed
+1545/−1197 lines, 39 filesdep +cerealdep +mtldep +wide-worddep −QuickCheckdep −punycodedep −quickcheck-instancesdep ~attoparsecdep ~basedep ~bytestringsetup-changed
Dependencies added: cereal, mtl, wide-word
Dependencies removed: QuickCheck, punycode, quickcheck-instances, semigroups, tasty-quickcheck
Dependency ranges changed: attoparsec, base, bytestring, ip, template-haskell, text, text-builder, th-lift, th-lift-instances, vector
Files
- Setup.hs +0/−2
- iri.cabal +162/−69
- library/Iri/CodePointPredicates/Core.hs +13/−11
- library/Iri/CodePointPredicates/Rfc3986.hs +123/−120
- library/Iri/CodePointPredicates/Rfc3987.hs +208/−154
- library/Iri/Data.hs +15/−18
- library/Iri/Data/Functions.hs +4/−6
- library/Iri/Data/Instances/Eq.hs +4/−4
- library/Iri/Data/Instances/Generic.hs +4/−4
- library/Iri/Data/Instances/Hashable.hs +7/−13
- library/Iri/Data/Instances/Lift.hs +40/−34
- library/Iri/Data/Instances/Ord.hs +5/−5
- library/Iri/Data/Instances/Show.hs +8/−9
- library/Iri/Data/Types.hs +56/−71
- library/Iri/MonadPlus.hs +19/−18
- library/Iri/Optics.hs +8/−10
- library/Iri/Optics/Basics.hs +3/−5
- library/Iri/Optics/Defs.hs +21/−17
- library/Iri/Parsing/Attoparsec/ByteString.hs +98/−95
- library/Iri/Parsing/Attoparsec/Text.hs +101/−84
- library/Iri/Parsing/ByteString.hs +29/−31
- library/Iri/Parsing/Text.hs +57/−20
- library/Iri/PercentEncoding.hs +7/−6
- library/Iri/Prelude.hs +31/−74
- library/Iri/QuasiQuoter.hs +34/−41
- library/Iri/Rendering/ByteString.hs +6/−8
- library/Iri/Rendering/Ptr/Poke.hs +3/−5
- library/Iri/Rendering/Ptr/Poking.hs +54/−54
- library/Iri/Rendering/Text.hs +2/−4
- library/Iri/Rendering/Text/Internal.hs +6/−8
- library/Iri/Rendering/TextBuilder.hs +2/−4
- library/Iri/Rendering/TextBuilder/Internal.hs +56/−56
- library/Iri/Utf8CodePoint.hs +17/−21
- library/Iri/Vector.hs +3/−5
- punycode/Data/Text/Punycode.hs +4/−0
- punycode/Data/Text/Punycode/Decode.hs +106/−0
- punycode/Data/Text/Punycode/Encode.hs +96/−0
- punycode/Data/Text/Punycode/Shared.hs +39/−0
- test/Main.hs +94/−111
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
iri.cabal view
@@ -1,96 +1,189 @@-name: iri-version: 0.4-category: URI, URL, IRI, Network-synopsis: RFC-based resource identifier library+cabal-version: 3.0+name: iri+version: 0.5+category: URI, URL, IRI, Network+synopsis: RFC-based resource identifier library description: This library provides a universal data model for representation of URI, URL and IRI. It comes packed with parsing, rendering and serialisation functionality. It is implemented in conformance with the RFC-3986 and RFC-3987 specifications and is intended as a standard tool for all tasks related to resource identifiers.-homepage: https://github.com/nikita-volkov/iri-bug-reports: https://github.com/nikita-volkov/iri/issues-author: Nikita Volkov <nikita.y.volkov@mail.ru>-maintainer: Metrix.AI Tech Team <tech@metrix.ai>-copyright: (c) 2017 Nikita Volkov-license: MIT-license-file: LICENSE-build-type: Simple-cabal-version: >=1.10 +homepage: https://github.com/nikita-volkov/iri+bug-reports: https://github.com/nikita-volkov/iri/issues+author: Nikita Volkov <nikita.y.volkov@mail.ru>+maintainer: Nikita Volkov <nikita.y.volkov@mail.ru>+copyright: (c) 2017 Nikita Volkov+license: MIT+license-file: LICENSE+ source-repository head- type: git+ type: git location: git://github.com/nikita-volkov/iri.git library- hs-source-dirs: library- default-extensions: Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, PatternSynonyms, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples- default-language: Haskell2010+ hs-source-dirs: library+ default-language: Haskell2010+ default-extensions:+ NoImplicitPrelude+ NoMonomorphismRestriction+ Arrows+ BangPatterns+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveTraversable+ EmptyDataDecls+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ LiberalTypeSynonyms+ MagicHash+ MultiParamTypeClasses+ MultiWayIf+ OverloadedStrings+ ParallelListComp+ PatternGuards+ PatternSynonyms+ QuasiQuotes+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ TemplateHaskell+ TupleSections+ TypeFamilies+ TypeOperators+ UnboxedTuples+ exposed-modules:- Iri.Rendering.Text- Iri.Rendering.TextBuilder- Iri.Rendering.Ptr.Poking- Iri.Rendering.ByteString- Iri.Parsing.ByteString+ Iri.Data+ Iri.Optics Iri.Parsing.Attoparsec.ByteString Iri.Parsing.Attoparsec.Text+ Iri.Parsing.ByteString Iri.Parsing.Text Iri.QuasiQuoter- Iri.Data- Iri.Optics+ Iri.Rendering.ByteString+ Iri.Rendering.Ptr.Poking+ Iri.Rendering.Text+ Iri.Rendering.TextBuilder+ other-modules:- Iri.Rendering.Text.Internal- Iri.Rendering.TextBuilder.Internal- Iri.Data.Types+ Iri.CodePointPredicates.Core+ Iri.CodePointPredicates.Rfc3986+ Iri.CodePointPredicates.Rfc3987 Iri.Data.Functions- Iri.Data.Instances.Lift- Iri.Data.Instances.Show Iri.Data.Instances.Eq+ Iri.Data.Instances.Generic Iri.Data.Instances.Hashable+ Iri.Data.Instances.Lift Iri.Data.Instances.Ord- Iri.Data.Instances.Generic- Iri.Prelude- Iri.Utf8CodePoint- Iri.Vector+ Iri.Data.Instances.Show+ Iri.Data.Types Iri.MonadPlus- Iri.CodePointPredicates.Core- Iri.CodePointPredicates.Rfc3986- Iri.CodePointPredicates.Rfc3987- Iri.Rendering.Ptr.Poke- Iri.PercentEncoding Iri.Optics.Basics Iri.Optics.Defs+ Iri.PercentEncoding+ Iri.Prelude+ Iri.Rendering.Ptr.Poke+ Iri.Rendering.Text.Internal+ Iri.Rendering.TextBuilder.Internal+ Iri.Utf8CodePoint+ Iri.Vector+ build-depends:- attoparsec >=0.13 && <0.14,- base >=4.9 && <5,- bytestring >=0.10 && <0.11,- contravariant >=1.4 && <2,- hashable >=1.2 && <2,- ip >=1.1 && <2,- profunctors >=5.2 && <6,- ptr >=0.16.1 && <0.17,- punycode >=2 && <3,- semigroups >=0.18 && <0.20,- template-haskell >=2.9 && <3,- text ==1.*,- text-builder >=0.6.5 && <0.7,- th-lift >=0.7.7 && <0.8,- th-lift-instances >=0.1.11 && <0.2,- unordered-containers >=0.2 && <0.3,- vector >=0.10 && <0.13,- vector-builder >=0.3.4 && <0.4,- vector-instances >=3.4 && <4+ , attoparsec >=0.13 && <0.15+ , base >=4.15 && <5+ , bytestring >=0.10 && <0.13+ , contravariant >=1.4 && <2+ , hashable >=1.2 && <2+ , ip >=1.7.8 && <2+ , iri:punycode+ , profunctors >=5.2 && <6+ , ptr >=0.16.1 && <0.17+ , template-haskell >=2.17 && <3+ , text >=2 && <3+ , text-builder >=0.6.7.2 && <0.7+ , th-lift >=0.8 && <0.9+ , th-lift-instances >=0.1.20 && <0.2+ , unordered-containers >=0.2 && <0.3+ , vector >=0.13 && <0.14+ , vector-builder >=0.3.4 && <0.4+ , vector-instances >=3.4 && <4+ , wide-word >=0.1.6 && <2 -test-suite test- type: exitcode-stdio-1.0- hs-source-dirs: test- main-is: Main.hs- default-extensions: Arrows, BangPatterns, ConstraintKinds, DataKinds, DefaultSignatures, DeriveDataTypeable, DeriveFoldable, DeriveFunctor, DeriveGeneric, DeriveTraversable, EmptyDataDecls, FlexibleContexts, FlexibleInstances, FunctionalDependencies, GADTs, GeneralizedNewtypeDeriving, LambdaCase, LiberalTypeSynonyms, MagicHash, MultiParamTypeClasses, MultiWayIf, NoImplicitPrelude, NoMonomorphismRestriction, OverloadedStrings, PatternGuards, PatternSynonyms, ParallelListComp, QuasiQuotes, RankNTypes, RecordWildCards, ScopedTypeVariables, StandaloneDeriving, TemplateHaskell, TupleSections, TypeFamilies, TypeOperators, UnboxedTuples+library punycode+ hs-source-dirs: punycode default-language: Haskell2010 build-depends:- iri,- QuickCheck >=2.8.1 && <3,- quickcheck-instances >=0.3.11 && <0.4,- rerebase <2,- tasty >=0.12 && <2,- tasty-hunit >=0.9 && <0.11,- tasty-quickcheck >=0.9 && <0.11+ , base >=4.15 && <5+ , bytestring >=0.10 && <0.13+ , cereal >=0.5.8.3 && <0.6+ , mtl >=2 && <3+ , text >=2 && <3++ exposed-modules: Data.Text.Punycode+ other-modules:+ Data.Text.Punycode.Decode+ Data.Text.Punycode.Encode+ Data.Text.Punycode.Shared++test-suite test+ type: exitcode-stdio-1.0+ hs-source-dirs: test+ main-is: Main.hs+ default-language: Haskell2010+ default-extensions:+ NoImplicitPrelude+ NoMonomorphismRestriction+ Arrows+ BangPatterns+ ConstraintKinds+ DataKinds+ DefaultSignatures+ DeriveDataTypeable+ DeriveFoldable+ DeriveFunctor+ DeriveGeneric+ DeriveTraversable+ EmptyDataDecls+ FlexibleContexts+ FlexibleInstances+ FunctionalDependencies+ GADTs+ GeneralizedNewtypeDeriving+ ImportQualifiedPost+ LambdaCase+ LiberalTypeSynonyms+ MagicHash+ MultiParamTypeClasses+ MultiWayIf+ OverloadedStrings+ ParallelListComp+ PatternGuards+ PatternSynonyms+ QuasiQuotes+ RankNTypes+ RecordWildCards+ ScopedTypeVariables+ StandaloneDeriving+ TemplateHaskell+ TupleSections+ TypeFamilies+ TypeOperators+ UnboxedTuples++ build-depends:+ , iri+ , rerebase <2+ , tasty >=0.12 && <2+ , tasty-hunit >=0.9 && <0.11
library/Iri/CodePointPredicates/Core.hs view
@@ -1,9 +1,7 @@-module Iri.CodePointPredicates.Core-where--import Iri.Prelude hiding ((|||), (&&&), inRange, Predicate)-import qualified Data.Vector.Unboxed as A+module Iri.CodePointPredicates.Core where +import Data.Vector.Unboxed qualified as A+import Iri.Prelude hiding (Predicate, inRange, (&&&), (|||)) type Predicate = Int -> Bool@@ -19,11 +17,13 @@ elem i (fmap ord string) infixr 2 |||+ (|||) :: Predicate -> Predicate -> Predicate (|||) left right i = left i || right i infixr 3 &&&+ (&&&) :: Predicate -> Predicate -> Predicate (&&&) left right i = left i && right i@@ -36,7 +36,7 @@ inCharRange min max = inRange (ord min) (ord max) -{-| 7-bit -}+-- | 7-bit septimal :: Predicate septimal i = i < 0x80@@ -47,11 +47,13 @@ control :: Predicate control i =- i <= 0x1F ||- i == 0x7F+ i+ <= 0x1F+ || i+ == 0x7F asciiAlphanumeric :: Predicate asciiAlphanumeric =- inCharRange 'a' 'z' |||- inCharRange 'A' 'Z' |||- inCharRange '0' '9'+ inCharRange 'a' 'z'+ ||| inCharRange 'A' 'Z'+ ||| inCharRange '0' '9'
library/Iri/CodePointPredicates/Rfc3986.hs view
@@ -1,104 +1,100 @@-{-|-References:-- <https://www.ietf.org/rfc/rfc3986 RFC3986: Uniform Resource Identifier (URI): Generic Syntax>--@-URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]--hier-part = "//" authority path-abempty- / path-absolute- / path-rootless- / path-empty--URI-reference = URI / relative-ref--absolute-URI = scheme ":" hier-part [ "?" query ]--relative-ref = relative-part [ "?" query ] [ "#" fragment ]--relative-part = "//" authority path-abempty- / path-absolute- / path-noscheme- / path-empty--scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )--authority = [ userinfo "@" ] host [ ":" port ]-userinfo = *( unreserved / pct-encoded / sub-delims / ":" )-host = IP-literal / IPv4address / reg-name-port = *DIGIT--IP-literal = "[" ( IPv6address / IPvFuture ) "]"--IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )--IPv6address = 6( h16 ":" ) ls32- / "::" 5( h16 ":" ) ls32- / [ h16 ] "::" 4( h16 ":" ) ls32- / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32- / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32- / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32- / [ *4( h16 ":" ) h16 ] "::" ls32- / [ *5( h16 ":" ) h16 ] "::" h16- / [ *6( h16 ":" ) h16 ] "::"--h16 = 1*4HEXDIG-ls32 = ( h16 ":" h16 ) / IPv4address-IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet-dec-octet = DIGIT ; 0-9- / %x31-39 DIGIT ; 10-99- / "1" 2DIGIT ; 100-199- / "2" %x30-34 DIGIT ; 200-249- / "25" %x30-35 ; 250-255--reg-name = *( unreserved / pct-encoded / sub-delims )--path = path-abempty ; begins with "/" or is empty- / path-absolute ; begins with "/" but not "//"- / path-noscheme ; begins with a non-colon segment- / path-rootless ; begins with a segment- / path-empty ; zero characters--path-abempty = *( "/" segment )-path-absolute = "/" [ segment-nz *( "/" segment ) ]-path-noscheme = segment-nz-nc *( "/" segment )-path-rootless = segment-nz *( "/" segment )-path-empty = 0<pchar>--segment = *pchar-segment-nz = 1*pchar-segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )- ; non-zero-length segment without any colon ":"--pchar = unreserved / pct-encoded / sub-delims / ":" / "@"--query = *( pchar / "/" / "?" )--fragment = *( pchar / "/" / "?" )--pct-encoded = "%" HEXDIG HEXDIG--unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"-reserved = gen-delims / sub-delims-gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"-sub-delims = "!" / "$" / "&" / "'" / "(" / ")"- / "*" / "+" / "," / ";" / "="-@---}-module Iri.CodePointPredicates.Rfc3986-where+-- |+-- References:+-- - <https://www.ietf.org/rfc/rfc3986 RFC3986: Uniform Resource Identifier (URI): Generic Syntax>+--+-- @+-- URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]+--+-- hier-part = "//" authority path-abempty+-- / path-absolute+-- / path-rootless+-- / path-empty+--+-- URI-reference = URI / relative-ref+--+-- absolute-URI = scheme ":" hier-part [ "?" query ]+--+-- relative-ref = relative-part [ "?" query ] [ "#" fragment ]+--+-- relative-part = "//" authority path-abempty+-- / path-absolute+-- / path-noscheme+-- / path-empty+--+-- scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )+--+-- authority = [ userinfo "@" ] host [ ":" port ]+-- userinfo = *( unreserved / pct-encoded / sub-delims / ":" )+-- host = IP-literal / IPv4address / reg-name+-- port = *DIGIT+--+-- IP-literal = "[" ( IPv6address / IPvFuture ) "]"+--+-- IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )+--+-- IPv6address = 6( h16 ":" ) ls32+-- / "::" 5( h16 ":" ) ls32+-- / [ h16 ] "::" 4( h16 ":" ) ls32+-- / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32+-- / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32+-- / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32+-- / [ *4( h16 ":" ) h16 ] "::" ls32+-- / [ *5( h16 ":" ) h16 ] "::" h16+-- / [ *6( h16 ":" ) h16 ] "::"+--+-- h16 = 1*4HEXDIG+-- ls32 = ( h16 ":" h16 ) / IPv4address+-- IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet+-- dec-octet = DIGIT ; 0-9+-- / %x31-39 DIGIT ; 10-99+-- / "1" 2DIGIT ; 100-199+-- / "2" %x30-34 DIGIT ; 200-249+-- / "25" %x30-35 ; 250-255+--+-- reg-name = *( unreserved / pct-encoded / sub-delims )+--+-- path = path-abempty ; begins with "/" or is empty+-- / path-absolute ; begins with "/" but not "//"+-- / path-noscheme ; begins with a non-colon segment+-- / path-rootless ; begins with a segment+-- / path-empty ; zero characters+--+-- path-abempty = *( "/" segment )+-- path-absolute = "/" [ segment-nz *( "/" segment ) ]+-- path-noscheme = segment-nz-nc *( "/" segment )+-- path-rootless = segment-nz *( "/" segment )+-- path-empty = 0<pchar>+--+-- segment = *pchar+-- segment-nz = 1*pchar+-- segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )+-- ; non-zero-length segment without any colon ":"+--+-- pchar = unreserved / pct-encoded / sub-delims / ":" / "@"+--+-- query = *( pchar / "/" / "?" )+--+-- fragment = *( pchar / "/" / "?" )+--+-- pct-encoded = "%" HEXDIG HEXDIG+--+-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"+-- reserved = gen-delims / sub-delims+-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"+-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"+-- / "*" / "+" / "," / ";" / "="+-- @+module Iri.CodePointPredicates.Rfc3986 where -import Iri.Prelude hiding ((|||), (&&&), inRange, Predicate) import Iri.CodePointPredicates.Core--{-|-Reference:+import Iri.Prelude hiding (Predicate, inRange, (&&&), (|||)) -@-unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"-@--}+-- |+-- Reference:+--+-- @+-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"+-- @ unreserved :: Predicate unreserved = asciiAlphanumeric ||| oneOfChars "-._~"@@ -110,14 +106,16 @@ {-# NOINLINE scheme #-} scheme :: Predicate scheme =- cached $- asciiAlphanumeric ||| oneOfChars "+.-"+ cached+ $ asciiAlphanumeric+ ||| oneOfChars "+.-" {-# NOINLINE domainLabel #-} domainLabel :: Predicate domainLabel =- cached $- asciiAlphanumeric ||| oneOfChars "-_~"+ cached+ $ asciiAlphanumeric+ ||| oneOfChars "-_~" {- pchar = unreserved / pct-encoded / sub-delims / ":" / "@"@@ -125,24 +123,26 @@ {-# NOINLINE unencodedPathSegment #-} unencodedPathSegment :: Predicate unencodedPathSegment =- cached $- unreserved ||| subDelims ||| oneOfChars ":@"--{-|-Reference:--@-query = *( pchar / "/" / "?" )-@+ cached+ $ unreserved+ ||| subDelims+ ||| oneOfChars ":@" -Notice that we've added the "|" char, because some real life URIs seem to contain it.-Also we've excluded the '+' char, because it gets decoded as a space char.--}+-- |+-- Reference:+--+-- @+-- query = *( pchar / "/" / "?" )+-- @+--+-- Notice that we've added the "|" char, because some real life URIs seem to contain it.+-- Also we've excluded the '+' char, because it gets decoded as a space char. {-# NOINLINE unencodedQuery #-} unencodedQuery :: Predicate unencodedQuery =- cached $- (unencodedPathSegment ||| oneOfChars "/?|[]\"'") &&& (/= 43)+ cached+ $ (unencodedPathSegment ||| oneOfChars "/?|[]\"'")+ &&& (/= 43) unencodedFragment :: Predicate unencodedFragment =@@ -151,11 +151,14 @@ {-# NOINLINE unencodedQueryComponent #-} unencodedQueryComponent :: Predicate unencodedQueryComponent =- cached $- unencodedQuery &&& not . oneOfChars "=&;"+ cached+ $ unencodedQuery+ &&& not+ . oneOfChars "=&;" {-# NOINLINE unencodedUserInfoComponent #-} unencodedUserInfoComponent :: Predicate unencodedUserInfoComponent =- cached $- unreserved ||| subDelims+ cached+ $ unreserved+ ||| subDelims
library/Iri/CodePointPredicates/Rfc3987.hs view
@@ -1,125 +1,121 @@-{-|-References:-- <https://www.ietf.org/rfc/rfc3987 RFC3987>--@-The following rules are different from those in [RFC3986]:--IRI = scheme ":" ihier-part [ "?" iquery ]- [ "#" ifragment ]--ihier-part = "//" iauthority ipath-abempty- / ipath-absolute- / ipath-rootless- / ipath-empty--IRI-reference = IRI / irelative-ref--absolute-IRI = scheme ":" ihier-part [ "?" iquery ]--irelative-ref = irelative-part [ "?" iquery ] [ "#" ifragment ]--irelative-part = "//" iauthority ipath-abempty- / ipath-absolute-- / ipath-noscheme- / ipath-empty--iauthority = [ iuserinfo "@" ] ihost [ ":" port ]-iuserinfo = *( iunreserved / pct-encoded / sub-delims / ":" )-ihost = IP-literal / IPv4address / ireg-name--ireg-name = *( iunreserved / pct-encoded / sub-delims )--ipath = ipath-abempty ; begins with "/" or is empty- / ipath-absolute ; begins with "/" but not "//"- / ipath-noscheme ; begins with a non-colon segment- / ipath-rootless ; begins with a segment- / ipath-empty ; zero characters--ipath-abempty = *( "/" isegment )-ipath-absolute = "/" [ isegment-nz *( "/" isegment ) ]-ipath-noscheme = isegment-nz-nc *( "/" isegment )-ipath-rootless = isegment-nz *( "/" isegment )-ipath-empty = 0<ipchar>--isegment = *ipchar-isegment-nz = 1*ipchar-isegment-nz-nc = 1*( iunreserved / pct-encoded / sub-delims- / "@" )- ; non-zero-length segment without any colon ":"--ipchar = iunreserved / pct-encoded / sub-delims / ":"- / "@"--iquery = *( ipchar / iprivate / "/" / "?" )--ifragment = *( ipchar / "/" / "?" )--iunreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" / ucschar--ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF- / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD- / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD- / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD- / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD- / %xD0000-DFFFD / %xE1000-EFFFD--iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD--Some productions are ambiguous. The "first-match-wins" (a.k.a.-"greedy") algorithm applies. For details, see [RFC3986].--The following rules are the same as those in [RFC3986]:--scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )--port = *DIGIT--IP-literal = "[" ( IPv6address / IPvFuture ) "]"--IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )--IPv6address = 6( h16 ":" ) ls32- / "::" 5( h16 ":" ) ls32- / [ h16 ] "::" 4( h16 ":" ) ls32- / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32- / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32- / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32- / [ *4( h16 ":" ) h16 ] "::" ls32- / [ *5( h16 ":" ) h16 ] "::" h16- / [ *6( h16 ":" ) h16 ] "::"--h16 = 1*4HEXDIG-ls32 = ( h16 ":" h16 ) / IPv4address--IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet--dec-octet = DIGIT ; 0-9- / %x31-39 DIGIT ; 10-99- / "1" 2DIGIT ; 100-199- / "2" %x30-34 DIGIT ; 200-249- / "25" %x30-35 ; 250-255--pct-encoded = "%" HEXDIG HEXDIG--unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"-reserved = gen-delims / sub-delims-gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"-sub-delims = "!" / "$" / "&" / "'" / "(" / ")"- / "*" / "+" / "," / ";" / "="--This syntax does not support IPv6 scoped addressing zone identifiers.-@---}-module Iri.CodePointPredicates.Rfc3987-where+-- |+-- References:+-- - <https://www.ietf.org/rfc/rfc3987 RFC3987>+--+-- @+-- The following rules are different from those in [RFC3986]:+--+-- IRI = scheme ":" ihier-part [ "?" iquery ]+-- [ "#" ifragment ]+--+-- ihier-part = "//" iauthority ipath-abempty+-- / ipath-absolute+-- / ipath-rootless+-- / ipath-empty+--+-- IRI-reference = IRI / irelative-ref+--+-- absolute-IRI = scheme ":" ihier-part [ "?" iquery ]+--+-- irelative-ref = irelative-part [ "?" iquery ] [ "#" ifragment ]+--+-- irelative-part = "//" iauthority ipath-abempty+-- / ipath-absolute+--+-- / ipath-noscheme+-- / ipath-empty+--+-- iauthority = [ iuserinfo "@" ] ihost [ ":" port ]+-- iuserinfo = *( iunreserved / pct-encoded / sub-delims / ":" )+-- ihost = IP-literal / IPv4address / ireg-name+--+-- ireg-name = *( iunreserved / pct-encoded / sub-delims )+--+-- ipath = ipath-abempty ; begins with "/" or is empty+-- / ipath-absolute ; begins with "/" but not "//"+-- / ipath-noscheme ; begins with a non-colon segment+-- / ipath-rootless ; begins with a segment+-- / ipath-empty ; zero characters+--+-- ipath-abempty = *( "/" isegment )+-- ipath-absolute = "/" [ isegment-nz *( "/" isegment ) ]+-- ipath-noscheme = isegment-nz-nc *( "/" isegment )+-- ipath-rootless = isegment-nz *( "/" isegment )+-- ipath-empty = 0<ipchar>+--+-- isegment = *ipchar+-- isegment-nz = 1*ipchar+-- isegment-nz-nc = 1*( iunreserved / pct-encoded / sub-delims+-- / "@" )+-- ; non-zero-length segment without any colon ":"+--+-- ipchar = iunreserved / pct-encoded / sub-delims / ":"+-- / "@"+--+-- iquery = *( ipchar / iprivate / "/" / "?" )+--+-- ifragment = *( ipchar / "/" / "?" )+--+-- iunreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" / ucschar+--+-- ucschar = %xA0-D7FF / %xF900-FDCF / %xFDF0-FFEF+-- / %x10000-1FFFD / %x20000-2FFFD / %x30000-3FFFD+-- / %x40000-4FFFD / %x50000-5FFFD / %x60000-6FFFD+-- / %x70000-7FFFD / %x80000-8FFFD / %x90000-9FFFD+-- / %xA0000-AFFFD / %xB0000-BFFFD / %xC0000-CFFFD+-- / %xD0000-DFFFD / %xE1000-EFFFD+--+-- iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD+--+-- Some productions are ambiguous. The "first-match-wins" (a.k.a.+-- "greedy") algorithm applies. For details, see [RFC3986].+--+-- The following rules are the same as those in [RFC3986]:+--+-- scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )+--+-- port = *DIGIT+--+-- IP-literal = "[" ( IPv6address / IPvFuture ) "]"+--+-- IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )+--+-- IPv6address = 6( h16 ":" ) ls32+-- / "::" 5( h16 ":" ) ls32+-- / [ h16 ] "::" 4( h16 ":" ) ls32+-- / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32+-- / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32+-- / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32+-- / [ *4( h16 ":" ) h16 ] "::" ls32+-- / [ *5( h16 ":" ) h16 ] "::" h16+-- / [ *6( h16 ":" ) h16 ] "::"+--+-- h16 = 1*4HEXDIG+-- ls32 = ( h16 ":" h16 ) / IPv4address+--+-- IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet+--+-- dec-octet = DIGIT ; 0-9+-- / %x31-39 DIGIT ; 10-99+-- / "1" 2DIGIT ; 100-199+-- / "2" %x30-34 DIGIT ; 200-249+-- / "25" %x30-35 ; 250-255+--+-- pct-encoded = "%" HEXDIG HEXDIG+--+-- unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"+-- reserved = gen-delims / sub-delims+-- gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"+-- sub-delims = "!" / "$" / "&" / "'" / "(" / ")"+-- / "*" / "+" / "," / ";" / "="+--+-- This syntax does not support IPv6 scoped addressing zone identifiers.+-- @+module Iri.CodePointPredicates.Rfc3987 where -import Iri.Prelude hiding ((|||), (&&&), inRange, Predicate) import Iri.CodePointPredicates.Core-import qualified Iri.CodePointPredicates.Rfc3986 as A-+import Iri.CodePointPredicates.Rfc3986 qualified as A+import Iri.Prelude hiding (Predicate, inRange, (&&&), (|||)) scheme :: Predicate scheme =@@ -144,24 +140,22 @@ unencodedPathSegment = unreserved ||| A.subDelims ||| oneOfChars ":@" -{-|-Reference:--@-iquery = *( ipchar / iprivate / "/" / "?" )-@--Notice that we've added the "|" char, because some real life URIs seem to contain it.-Also we've excluded the '+' char, because it gets decoded as a space char.--}+-- |+-- Reference:+--+-- @+-- iquery = *( ipchar / iprivate / "/" / "?" )+-- @+--+-- Notice that we've added the "|" char, because some real life URIs seem to contain it.+-- Also we've excluded the '+' char, because it gets decoded as a space char. unencodedQuery :: Predicate unencodedQuery = (unencodedPathSegment ||| private ||| oneOfChars "/?|") &&& (/= 43) -{-|-Notice that we've added the "|" char, because some real life URIs seem to contain it.-Also we've excluded the '+' char, because it gets decoded as a space char.--}+-- |+-- Notice that we've added the "|" char, because some real life URIs seem to contain it.+-- Also we've excluded the '+' char, because it gets decoded as a space char. unencodedFragment :: Predicate unencodedFragment = (unencodedPathSegment ||| oneOfChars "/?|") &&& (/= 43)@@ -183,29 +177,89 @@ -} ucs :: Predicate ucs x =- x >= 0xA0 && x <= 0xD7FF ||- x >= 0xF900 && x <= 0xFDCF ||- x >= 0xFDF0 && x <= 0xFFEF ||- x >= 0x10000 && x <= 0x1FFFD ||- x >= 0x20000 && x <= 0x2FFFD ||- x >= 0x30000 && x <= 0x3FFFD ||- x >= 0x40000 && x <= 0x4FFFD ||- x >= 0x50000 && x <= 0x5FFFD ||- x >= 0x60000 && x <= 0x6FFFD ||- x >= 0x70000 && x <= 0x7FFFD ||- x >= 0x80000 && x <= 0x8FFFD ||- x >= 0x90000 && x <= 0x9FFFD ||- x >= 0xA0000 && x <= 0xAFFFD ||- x >= 0xB0000 && x <= 0xBFFFD ||- x >= 0xC0000 && x <= 0xCFFFD ||- x >= 0xD0000 && x <= 0xDFFFD ||- x >= 0xE1000 && x <= 0xEFFFD+ x+ >= 0xA0+ && x+ <= 0xD7FF+ || x+ >= 0xF900+ && x+ <= 0xFDCF+ || x+ >= 0xFDF0+ && x+ <= 0xFFEF+ || x+ >= 0x10000+ && x+ <= 0x1FFFD+ || x+ >= 0x20000+ && x+ <= 0x2FFFD+ || x+ >= 0x30000+ && x+ <= 0x3FFFD+ || x+ >= 0x40000+ && x+ <= 0x4FFFD+ || x+ >= 0x50000+ && x+ <= 0x5FFFD+ || x+ >= 0x60000+ && x+ <= 0x6FFFD+ || x+ >= 0x70000+ && x+ <= 0x7FFFD+ || x+ >= 0x80000+ && x+ <= 0x8FFFD+ || x+ >= 0x90000+ && x+ <= 0x9FFFD+ || x+ >= 0xA0000+ && x+ <= 0xAFFFD+ || x+ >= 0xB0000+ && x+ <= 0xBFFFD+ || x+ >= 0xC0000+ && x+ <= 0xCFFFD+ || x+ >= 0xD0000+ && x+ <= 0xDFFFD+ || x+ >= 0xE1000+ && x+ <= 0xEFFFD {- iprivate = %xE000-F8FF / %xF0000-FFFFD / %x100000-10FFFD -} private :: Predicate private x =- x >= 0xE000 && x <= 0xF8FF ||- x >= 0xF0000 && x <= 0xFFFFD ||- x >= 0x100000 && x <= 0x10FFFD+ x+ >= 0xE000+ && x+ <= 0xF8FF+ || x+ >= 0xF0000+ && x+ <= 0xFFFFD+ || x+ >= 0x100000+ && x+ <= 0x10FFFD
library/Iri/Data.hs view
@@ -1,22 +1,19 @@-{-|-References:--* <https://tools.ietf.org/rfc/rfc3986.txt URI RFC>-* <https://tools.ietf.org/rfc/rfc3987.txt IRI RFC>--}+-- |+-- References:+--+-- * <https://tools.ietf.org/rfc/rfc3986.txt URI RFC>+-- * <https://tools.ietf.org/rfc/rfc3987.txt IRI RFC> module Iri.Data-(- module Iri.Data.Types,- module Iri.Data.Functions,-)+ ( module Iri.Data.Types,+ module Iri.Data.Functions,+ ) where -import Iri.Data.Types import Iri.Data.Functions-import Iri.Data.Instances.Lift-import Iri.Data.Instances.Eq-import Iri.Data.Instances.Show-import Iri.Data.Instances.Ord-import Iri.Data.Instances.Hashable-import Iri.Data.Instances.Generic-+import Iri.Data.Instances.Eq ()+import Iri.Data.Instances.Generic ()+import Iri.Data.Instances.Hashable ()+import Iri.Data.Instances.Lift ()+import Iri.Data.Instances.Ord ()+import Iri.Data.Instances.Show ()+import Iri.Data.Types
library/Iri/Data/Functions.hs view
@@ -1,11 +1,9 @@-module Iri.Data.Functions-where+module Iri.Data.Functions where -import Iri.Prelude import Iri.Data.Types-+import Iri.Prelude -{-| Try to specialize a general IRI to HTTP -}+-- | Try to specialize a general IRI to HTTP httpIriFromIri :: Iri -> Either Text HttpIri httpIriFromIri (Iri (Scheme scheme) hierarchy query fragment) = do@@ -19,7 +17,7 @@ PresentUserInfo (User user) _ -> Left ("User Info is present") _ -> Left ("Not an authorised hierarchy") -{-| Generalize an HTTP IRI to IRI -}+-- | Generalize an HTTP IRI to IRI iriFromHttpIri :: HttpIri -> Iri iriFromHttpIri (HttpIri (Security secure) host port path query fragment) = Iri scheme hierarchy query fragment
library/Iri/Data/Instances/Eq.hs view
@@ -1,9 +1,9 @@-module Iri.Data.Instances.Eq-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude-import Iri.Data.Types+module Iri.Data.Instances.Eq where +import Iri.Data.Types+import Iri.Prelude deriving instance Eq Iri
library/Iri/Data/Instances/Generic.hs view
@@ -1,9 +1,9 @@-module Iri.Data.Instances.Generic-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude-import Iri.Data.Types+module Iri.Data.Instances.Generic where +import Iri.Data.Types+import Iri.Prelude deriving instance Generic Iri
library/Iri/Data/Instances/Hashable.hs view
@@ -1,11 +1,11 @@-module Iri.Data.Instances.Hashable-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude-import Iri.Data.Types-import Iri.Data.Instances.Generic-import qualified Net.IPv6 as B+module Iri.Data.Instances.Hashable where +import Iri.Data.Instances.Eq ()+import Iri.Data.Instances.Generic ()+import Iri.Data.Types+import Iri.Prelude instance Hashable Iri @@ -21,13 +21,7 @@ instance Hashable Password -instance Hashable Host where- hashWithSalt salt host =- hashWithSalt salt $- case host of- NamedHost regName -> hashWithSalt 0 regName- IpV4Host ip -> hashWithSalt 1 ip- IpV6Host (B.IPv6 a b) -> (hashWithSalt (hashWithSalt 2 a) b)+instance Hashable Host instance Hashable RegName
library/Iri/Data/Instances/Lift.hs view
@@ -1,41 +1,47 @@-module Iri.Data.Instances.Lift-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude+module Iri.Data.Instances.Lift where++import Data.WideWord.Word128 qualified import Iri.Data.Types+import Iri.Prelude import Language.Haskell.TH.Lift---deriveLift ''Iri--deriveLift ''Scheme--deriveLift ''Hierarchy--deriveLift ''Authority--deriveLift ''UserInfo--deriveLift ''User--deriveLift ''Password--deriveLift ''Host--deriveLift ''RegName--deriveLift ''DomainLabel--deriveLift ''Port--deriveLift ''Path--deriveLift ''PathSegment+import Language.Haskell.TH.Syntax+import Net.IPv6 qualified -deriveLift ''Query+fmap concat+ $ traverse deriveLift+ $ [ ''RegName,+ ''DomainLabel+ ] -deriveLift ''Fragment+instance Lift Host where+ lift = \case+ NamedHost regName ->+ AppE (ConE 'NamedHost) <$> lift regName+ IpV4Host ipV4 ->+ AppE (ConE 'IpV4Host) <$> $(makeLift ''IPv4) ipV4+ IpV6Host (Net.IPv6.IPv6 word128) -> do+ word128Exp <- $(makeLift ''Data.WideWord.Word128.Word128) word128+ pure (AppE (ConE 'IpV6Host) (AppE (ConE 'Net.IPv6.IPv6) word128Exp)) -deriveLift ''HttpIri+ liftTyped =+ Code . fmap TExp . lift -deriveLift ''Security+fmap concat+ $ traverse deriveLift+ $ [ ''Authority,+ ''Fragment,+ ''Hierarchy,+ ''HttpIri,+ ''Iri,+ ''Password,+ ''Path,+ ''PathSegment,+ ''Port,+ ''Query,+ ''Scheme,+ ''Security,+ ''User,+ ''UserInfo+ ]
library/Iri/Data/Instances/Ord.hs view
@@ -1,10 +1,10 @@-module Iri.Data.Instances.Ord-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude-import Iri.Data.Types-import Iri.Data.Instances.Eq+module Iri.Data.Instances.Ord where +import Iri.Data.Instances.Eq ()+import Iri.Data.Types+import Iri.Prelude deriving instance Ord Iri
library/Iri/Data/Instances/Show.hs view
@@ -1,19 +1,19 @@-module Iri.Data.Instances.Show-where+{-# OPTIONS_GHC -Wno-orphans #-} -import Iri.Prelude-import Iri.Data.Types-import qualified Iri.Rendering.Text.Internal as A-import qualified Data.Text as B+module Iri.Data.Instances.Show where +import Data.Text qualified as B+import Iri.Data.Types+import Iri.Prelude+import Iri.Rendering.Text.Internal qualified as A instance Show Iri where show =- B.unpack . A.iri+ mappend "\"" . flip mappend "\"" . B.unpack . A.iri instance Show HttpIri where show =- B.unpack . A.httpIri+ mappend "\"" . flip mappend "\"" . B.unpack . A.httpIri deriving instance Show Scheme @@ -44,4 +44,3 @@ deriving instance Show Fragment deriving instance Show Security-
library/Iri/Data/Types.hs view
@@ -1,98 +1,83 @@-{-|-References:--* <https://tools.ietf.org/rfc/rfc3986.txt URI RFC>-* <https://tools.ietf.org/rfc/rfc3987.txt IRI RFC>--} {-# OPTIONS_GHC -funbox-strict-fields #-}-module Iri.Data.Types-where -import Iri.Prelude+-- |+-- References:+--+-- * <https://tools.ietf.org/rfc/rfc3986.txt URI RFC>+-- * <https://tools.ietf.org/rfc/rfc3987.txt IRI RFC>+module Iri.Data.Types where +import Iri.Prelude -{-|-Thorough structure of IRI or URI.--}-data Iri =- Iri !Scheme !Hierarchy !Query !Fragment+-- |+-- Thorough structure of IRI or URI.+data Iri = Iri !Scheme !Hierarchy !Query !Fragment -newtype Scheme =- Scheme ByteString+newtype Scheme = Scheme ByteString -data Hierarchy =- AuthorisedHierarchy !Authority !Path |- AbsoluteHierarchy !Path |- RelativeHierarchy !Path+data Hierarchy+ = AuthorisedHierarchy !Authority !Path+ | AbsoluteHierarchy !Path+ | RelativeHierarchy !Path -data Authority =- Authority !UserInfo !Host !Port+data Authority = Authority !UserInfo !Host !Port -data UserInfo =- PresentUserInfo !User !Password |- MissingUserInfo+data UserInfo+ = PresentUserInfo !User !Password+ | MissingUserInfo -newtype User =- User ByteString+newtype User = User ByteString -data Password =- PresentPassword !ByteString |- MissingPassword+data Password+ = PresentPassword !ByteString+ | MissingPassword -data Host =- NamedHost !RegName |- IpV4Host !IPv4 |- IpV6Host !IPv6+data Host+ = NamedHost !RegName+ | IpV4Host !IPv4+ | IpV6Host !IPv6 -newtype RegName =- RegName (Vector DomainLabel)+newtype RegName = RegName (Vector DomainLabel) data DomainLabel = DomainLabel Text -data Port =- PresentPort !Word16 |- MissingPort--newtype Path =- Path (Vector PathSegment)--newtype PathSegment =- PathSegment ByteString+data Port+ = PresentPort !Word16+ | MissingPort -{-|-Since the exact structure of the query string is not standardised and-methods used to parse the query string may differ between websites,-we simply represent it as percent-decoded bytes.+newtype Path = Path (Vector PathSegment) -See <https://en.wikipedia.org/wiki/Query_string>.--}-newtype Query =- Query ByteString+newtype PathSegment = PathSegment ByteString -newtype Fragment =- Fragment ByteString+-- |+-- Since the exact structure of the query string is not standardised and+-- methods used to parse the query string may differ between websites,+-- we simply represent it as percent-decoded bytes.+--+-- See <https://en.wikipedia.org/wiki/Query_string>.+newtype Query = Query ByteString +newtype Fragment = Fragment ByteString -- * Special cases-------------------------- --- ** HTTP special case ------------------------- -{-|-HTTP being by far the most common use-case for resource identifiers,-it's been isolated into a dedicated data-type,-which is optimised for that particular case.+-- ** HTTP special case -Compared to the general URI definition it:+------------------------- -* only supports the HTTP and HTTPS schemes-* misses the Username and Password components-* requires the Host component-* requires the Path component to be absolute--}-data HttpIri =- HttpIri !Security !Host !Port !Path !Query !Fragment+-- |+-- HTTP being by far the most common use-case for resource identifiers,+-- it's been isolated into a dedicated data-type,+-- which is optimised for that particular case.+--+-- Compared to the general URI definition it:+--+-- * only supports the HTTP and HTTPS schemes+-- * misses the Username and Password components+-- * requires the Host component+-- * requires the Path component to be absolute+data HttpIri = HttpIri !Security !Host !Port !Path !Query !Fragment -newtype Security =- Security Bool+newtype Security = Security Bool
library/Iri/MonadPlus.hs view
@@ -1,41 +1,42 @@-module Iri.MonadPlus-where+module Iri.MonadPlus where import Iri.Prelude hiding (foldl)-import qualified Ptr.ByteString as ByteString-import qualified Ptr.Poking as Poking-+import Ptr.ByteString qualified as ByteString+import Ptr.Poking qualified as Poking {-# INLINE foldl #-}-foldl :: MonadPlus m => (a -> b -> a) -> a -> m b -> m a+foldl :: (MonadPlus m) => (a -> b -> a) -> a -> m b -> m a foldl step start elementParser = loop start where loop state = mplus- (do- element <- elementParser- loop $! step state element)+ ( do+ element <- elementParser+ loop $! step state element+ ) (return state) {-# INLINE foldlM #-}-foldlM :: MonadPlus m => (a -> b -> m a) -> a -> m b -> m a+foldlM :: (MonadPlus m) => (a -> b -> m a) -> a -> m b -> m a foldlM step start elementParser = loop start where loop state = join- (mplus- (do- element <- elementParser- return (step state element >>= loop))- (return (return state)))+ ( mplus+ ( do+ element <- elementParser+ return (step state element >>= loop)+ )+ (return (return state))+ ) {-# INLINE foldByteString #-}-foldByteString :: MonadPlus m => m ByteString -> m ByteString+foldByteString :: (MonadPlus m) => m ByteString -> m ByteString foldByteString =- fmap ByteString.poking .- foldl (\ poking -> mappend poking . Poking.bytes) mempty+ fmap ByteString.poking+ . foldl (\poking -> mappend poking . Poking.bytes) mempty {-# INLINE fold #-} fold :: (MonadPlus m, Monoid a) => m a -> m a
library/Iri/Optics.hs view
@@ -1,14 +1,12 @@-{-|-These are the beginnings of a Lens API.-It is compatible with the general Van Laarhoven lens libraries, such as \"lens\".--Many more definitions can be implemented, so do PRs if you miss any!--}+-- |+-- These are the beginnings of a Lens API.+-- It is compatible with the general Van Laarhoven lens libraries, such as \"lens\".+--+-- Many more definitions can be implemented, so do PRs if you miss any! module Iri.Optics-(- module Basics,- module Defs,-)+ ( module Basics,+ module Defs,+ ) where import Iri.Optics.Basics as Basics (Lens, Lens', Prism, Prism', Traversal, Traversal')
library/Iri/Optics/Basics.hs view
@@ -1,10 +1,8 @@-module Iri.Optics.Basics-where+module Iri.Optics.Basics where import Iri.Prelude --type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t+type Lens s t a b = forall f. (Functor f) => (a -> f b) -> s -> f t type Lens' s a = Lens s s a a @@ -12,7 +10,7 @@ type Prism' s a = Prism s s a a -type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t+type Traversal s t a b = forall f. (Applicative f) => (a -> f b) -> s -> f t type Traversal' s a = Traversal s s a a
library/Iri/Optics/Defs.hs view
@@ -1,36 +1,37 @@-module Iri.Optics.Defs-where+module Iri.Optics.Defs where -import Iri.Prelude+import Data.Text.Encoding qualified as Text import Iri.Data import Iri.Optics.Basics-import qualified Iri.Rendering.ByteString as A-import qualified Iri.Parsing.ByteString as B-import qualified Iri.Rendering.Text as C-import qualified Iri.Parsing.Text as D-import qualified Data.Text.Encoding as Text-+import Iri.Parsing.ByteString qualified as B+import Iri.Parsing.Text qualified as D+import Iri.Prelude+import Iri.Rendering.ByteString qualified as A+import Iri.Rendering.Text qualified as C -- * Definitions by source+ ------------------------- -- ** Text+ ------------------------- textIriIri :: Prism' Text Iri textIriIri =- prism C.iri (\ text -> either (const (Left text)) Right (D.iri text))+ prism C.iri (\text -> either (const (Left text)) Right (D.iri text)) textIriHttpIri :: Prism' Text HttpIri textIriHttpIri = textIriIri . iriHttpIri -- ** ByteString+ ------------------------- byteStringIri :: Prism' ByteString Iri byteStringIri =- prism A.uri (\ bytes -> either (const (Left bytes)) Right (B.uri bytes))+ prism A.uri (\bytes -> either (const (Left bytes)) Right (B.uri bytes)) byteStringHttpIri :: Prism' ByteString HttpIri byteStringHttpIri =@@ -40,31 +41,34 @@ byteStringTextInUtf8 = prism' Text.encodeUtf8 (either (const Nothing) Just . Text.decodeUtf8') -- ** IRI+ ------------------------- iriHttpIri :: Prism' Iri HttpIri iriHttpIri = prism' iriFromHttpIri (either (const Nothing) Just . httpIriFromIri) iriScheme :: Lens' Iri Scheme-iriScheme = lens (\ (Iri x _ _ _) -> x) (\ (Iri _ hierarchy query fragment) x -> Iri x hierarchy query fragment)+iriScheme = lens (\(Iri x _ _ _) -> x) (\(Iri _ hierarchy query fragment) x -> Iri x hierarchy query fragment) iriHierarchy :: Lens' Iri Hierarchy-iriHierarchy = lens (\ (Iri _ x _ _) -> x) (\ (Iri scheme _ query fragment) x -> Iri scheme x query fragment)+iriHierarchy = lens (\(Iri _ x _ _) -> x) (\(Iri scheme _ query fragment) x -> Iri scheme x query fragment) iriQuery :: Lens' Iri Query-iriQuery = lens (\ (Iri _ _ x _) -> x) (\ (Iri scheme hierarchy _ fragment) x -> Iri scheme hierarchy x fragment)+iriQuery = lens (\(Iri _ _ x _) -> x) (\(Iri scheme hierarchy _ fragment) x -> Iri scheme hierarchy x fragment) iriFragment :: Lens' Iri Fragment-iriFragment = lens (\ (Iri _ _ _ x) -> x) (\ (Iri scheme hierarchy query _) x -> Iri scheme hierarchy query x)+iriFragment = lens (\(Iri _ _ _ x) -> x) (\(Iri scheme hierarchy query _) x -> Iri scheme hierarchy query x) -- ** Scheme+ ------------------------- schemeByteString :: Lens' Scheme ByteString-schemeByteString = lens (\ (Scheme x) -> x) (const Scheme)+schemeByteString = lens (\(Scheme x) -> x) (const Scheme) -- ** Fragment+ ------------------------- fragmentByteString :: Lens' Fragment ByteString-fragmentByteString = lens (\ (Fragment x) -> x) (const Fragment)+fragmentByteString = lens (\(Fragment x) -> x) (const Fragment)
library/Iri/Parsing/Attoparsec/ByteString.hs view
@@ -1,34 +1,28 @@+{-# OPTIONS_GHC -Wno-unused-top-binds #-}+ module Iri.Parsing.Attoparsec.ByteString-(- uri,- httpUri,- regName,-)+ ( uri,+ httpUri,+ regName,+ ) where -import Iri.Prelude hiding (foldl, hash)-import Iri.Data import Data.Attoparsec.ByteString hiding (try)-import qualified Data.Attoparsec.ByteString.Char8 as F-import qualified Data.ByteString as K-import qualified Data.Text as T-import qualified Data.Text.Punycode as A-import qualified Data.Text.Encoding as B-import qualified Data.Text.Encoding.Error as L-import qualified Data.HashMap.Strict as O-import qualified Data.Vector as S-import qualified VectorBuilder.Builder as P-import qualified VectorBuilder.Vector as Q-import qualified VectorBuilder.MonadPlus as E-import qualified Iri.PercentEncoding as I-import qualified Iri.CodePointPredicates.Rfc3986 as C-import qualified Iri.MonadPlus as R-import qualified Ptr.Poking as G-import qualified Ptr.ByteString as H-import qualified Text.Builder as J-import qualified Net.IPv4 as M-import qualified Net.IPv6 as N-+import Data.Attoparsec.ByteString.Char8 qualified as F+import Data.ByteString qualified as K+import Data.Text.Encoding qualified as B+import Data.Text.Encoding.Error qualified as L+import Data.Text.Punycode qualified as A+import Data.Vector qualified as S+import Iri.CodePointPredicates.Rfc3986 qualified as C+import Iri.Data+import Iri.MonadPlus qualified as R+import Iri.PercentEncoding qualified as I+import Iri.Prelude hiding (foldl, hash)+import Net.IPv4 qualified as M+import Net.IPv6 qualified as N+import Text.Builder qualified as J+import VectorBuilder.MonadPlus qualified as E {-# INLINE percent #-} percent :: Parser Word8@@ -85,11 +79,10 @@ labeled label parser = parser <?> label -{-|-Parser of a well-formed URI conforming to the RFC3986 or RFC3987 standards.-Performs URL- and Punycode-decoding.--}-{-# INLINABLE uri #-}+-- |+-- Parser of a well-formed URI conforming to the RFC3986 or RFC3987 standards.+-- Performs URL- and Punycode-decoding.+{-# INLINEABLE uri #-} uri :: Parser Iri uri = labeled "URI" $ do@@ -100,18 +93,17 @@ parsedFragment <- fragment return (Iri parsedScheme parsedHierarchy parsedQuery parsedFragment) -{-|-Same as 'uri', but optimized specifially for the case of HTTP URIs.--}-{-# INLINABLE httpUri #-}+-- |+-- Same as 'uri', but optimized specifially for the case of HTTP URIs.+{-# INLINEABLE httpUri #-} httpUri :: Parser HttpIri httpUri = labeled "HTTP URI" $ do- satisfy (\ x -> x == 104 || x == 72)- satisfy (\ x -> x == 116 || x == 84)- satisfy (\ x -> x == 116 || x == 84)- satisfy (\ x -> x == 112 || x == 80)- secure <- satisfy (\ b -> b == 115 || b == 83) $> True <|> pure False+ satisfy (\x -> x == 104 || x == 72)+ satisfy (\x -> x == 116 || x == 84)+ satisfy (\x -> x == 116 || x == 84)+ satisfy (\x -> x == 112 || x == 80)+ secure <- satisfy (\b -> b == 115 || b == 83) $> True <|> pure False string "://" parsedHost <- host parsedPort <- PresentPort <$> (colon *> port) <|> pure MissingPort@@ -146,31 +138,33 @@ {-# INLINE scheme #-} scheme :: Parser Scheme scheme =- labeled "Scheme" $- fmap Scheme (takeWhile1 (C.scheme . fromIntegral))+ labeled "Scheme"+ $ fmap Scheme (takeWhile1 (C.scheme . fromIntegral)) -{-# INLINABLE presentUserInfo #-}+{-# INLINEABLE presentUserInfo #-} presentUserInfo :: (User -> Password -> a) -> Parser a presentUserInfo result =- labeled "User info" $- do- user <- User <$> urlEncodedString (C.unencodedUserInfoComponent . fromIntegral)- passwordFollows <- True <$ colon <|> pure False- if passwordFollows- then do- password <- PresentPassword <$> urlEncodedString (C.unencodedUserInfoComponent . fromIntegral)- return (result user password)- else return (result user MissingPassword)+ labeled "User info"+ $ do+ user <- User <$> urlEncodedString (C.unencodedUserInfoComponent . fromIntegral)+ passwordFollows <- True <$ colon <|> pure False+ if passwordFollows+ then do+ password <- PresentPassword <$> urlEncodedString (C.unencodedUserInfoComponent . fromIntegral)+ return (result user password)+ else return (result user MissingPassword) {-# INLINE host #-} host :: Parser Host host =- labeled "Host" $- IpV6Host <$> ipV6 <|>- IpV4Host <$> M.parserUtf8 <|>- NamedHost <$> regName+ labeled "Host"+ $ asum+ [ IpV6Host <$> ipV6,+ IpV4Host <$> M.parserUtf8,+ NamedHost <$> regName+ ] -{-# INLINABLE ipV6 #-}+{-# INLINEABLE ipV6 #-} ipV6 :: Parser IPv6 ipV6 = do@@ -183,27 +177,28 @@ d <- F.hexadecimal colon mplus- (do- e <- F.hexadecimal- colon- f <- F.hexadecimal- colon- g <- F.hexadecimal- colon- h <- F.hexadecimal- return (N.fromWord16s a b c d e f g h))- (do- colon- return (N.fromWord16s a b c d 0 0 0 0))+ ( do+ e <- F.hexadecimal+ colon+ f <- F.hexadecimal+ colon+ g <- F.hexadecimal+ colon+ h <- F.hexadecimal+ return (N.fromWord16s a b c d e f g h)+ )+ ( do+ colon+ return (N.fromWord16s a b c d 0 0 0 0)+ ) {-# INLINE regName #-} regName :: Parser RegName regName = fmap RegName (E.sepBy1 domainLabel (word8 46)) -{-|-Domain label with Punycode decoding applied if need be.--}+-- |+-- Domain label with Punycode decoding applied if need be. {-# INLINE domainLabel #-} domainLabel :: Parser DomainLabel domainLabel =@@ -231,19 +226,21 @@ else return (Path segments) where segmentsAreEmpty segments =- S.length segments == 1 &&- (case S.unsafeHead segments of PathSegment headSegment -> K.null headSegment)+ S.length segments+ == 1+ && (case S.unsafeHead segments of PathSegment headSegment -> K.null headSegment) {-# INLINE pathSegment #-} pathSegment :: Parser PathSegment pathSegment = fmap PathSegment (urlEncodedString (C.unencodedPathSegment . fromIntegral)) -{-# INLINABLE utf8Chunks #-}+{-# INLINEABLE utf8Chunks #-} utf8Chunks :: Parser ByteString -> Parser Text utf8Chunks chunk =- labeled "UTF8 chunks" $- R.foldlM progress (mempty, mempty, B.streamDecodeUtf8) chunk >>= finish+ labeled "UTF8 chunks"+ $ R.foldlM progress (mempty, mempty, B.streamDecodeUtf8) chunk+ >>= finish where progress (!builder, _, decode) bytes = case unsafeDupablePerformIO (try (evaluate (decode bytes))) of@@ -251,17 +248,20 @@ return (builder <> J.text decodedChunk, undecodedBytes, newDecode) Left (L.DecodeError error _) -> fail (showString "UTF8 decoding: " error)+ Left _ ->+ fail "Unexpected decoding error" finish (builder, undecodedBytes, _) = if K.null undecodedBytes then return (J.run builder) else fail (showString "UTF8 decoding: Bytes remaining: " (show undecodedBytes)) -{-# INLINABLE urlEncodedString #-}+{-# INLINEABLE urlEncodedString #-} urlEncodedString :: (Word8 -> Bool) -> Parser ByteString urlEncodedString unencodedBytesPredicate =- labeled "URL-encoded string" $- R.foldByteString $- takeWhile1 unencodedBytesPredicate <|> encoded+ labeled "URL-encoded string"+ $ R.foldByteString+ $ takeWhile1 unencodedBytesPredicate+ <|> encoded where encoded = K.singleton <$> percentEncodedByte@@ -270,7 +270,7 @@ percentEncodedByte :: Parser Word8 percentEncodedByte = labeled "Percent-encoded byte" $ do- percent + percent byte1 <- anyWord8 byte2 <- anyWord8 I.matchPercentEncodedBytes (fail "Broken percent encoding") return byte1 byte2@@ -278,22 +278,25 @@ {-# INLINE query #-} query :: Parser Query query =- labeled "Query" $- (question *> (Query <$> queryOrFragmentBody)) <|> pure (Query mempty)+ labeled "Query"+ $ (question *> (Query <$> queryOrFragmentBody))+ <|> pure (Query mempty) {-# INLINE fragment #-} fragment :: Parser Fragment fragment =- labeled "Fragment" $- (hash *> (Fragment <$> queryOrFragmentBody)) <|> pure (Fragment mempty)+ labeled "Fragment"+ $ (hash *> (Fragment <$> queryOrFragmentBody))+ <|> pure (Fragment mempty) -{-|-The stuff after the question or the hash mark.--}-{-# INLINABLE queryOrFragmentBody #-}+-- |+-- The stuff after the question or the hash mark.+{-# INLINEABLE queryOrFragmentBody #-} queryOrFragmentBody :: Parser ByteString queryOrFragmentBody =- R.foldByteString $- takeWhile1 (C.unencodedQuery . fromIntegral) <|>- " " <$ plus <|>- K.singleton <$> percentEncodedByte+ R.foldByteString+ $ takeWhile1 (C.unencodedQuery . fromIntegral)+ <|> " "+ <$ plus+ <|> K.singleton+ <$> percentEncodedByte
library/Iri/Parsing/Attoparsec/Text.hs view
@@ -1,38 +1,46 @@+{-# OPTIONS_GHC -Wno-unused-top-binds #-}+ module Iri.Parsing.Attoparsec.Text-(- iri,- httpIri,-)+ ( iri,+ httpIri,+ hierarchy,+ scheme,+ host,+ regName,+ domainLabel,+ port,+ path,+ pathSegment,+ query,+ fragment,+ ) where -import Iri.Prelude-import Iri.Data import Data.Attoparsec.Text hiding (try)-import qualified Data.ByteString as K-import qualified Data.Text as T-import qualified Data.Text.Encoding as B-import qualified Data.Text.Encoding.Error as L-import qualified Data.Vector as S-import qualified VectorBuilder.MonadPlus as E-import qualified Iri.CodePointPredicates.Rfc3987 as C-import qualified Iri.MonadPlus as R-import qualified Text.Builder as J-import qualified Net.IPv4 as M-import qualified Net.IPv6 as N-import qualified Ptr.ByteString as ByteString-import qualified Ptr.Poking as Poking-+import Data.ByteString qualified as K+import Data.Text.Encoding qualified as B+import Data.Text.Encoding.Error qualified as L+import Data.Vector qualified as S+import Iri.CodePointPredicates.Rfc3987 qualified as C+import Iri.Data+import Iri.MonadPlus qualified as R+import Iri.Prelude+import Net.IPv4 qualified as M+import Net.IPv6 qualified as N+import Ptr.ByteString qualified as ByteString+import Ptr.Poking qualified as Poking+import Text.Builder qualified as J+import VectorBuilder.MonadPlus qualified as E {-# INLINE labeled #-} labeled :: String -> Parser a -> Parser a labeled label parser = parser <?> label -{-|-Parser of a well-formed IRI conforming to the RFC3987 standard into 'Iri'.-Performs URL-decoding.--}-{-# INLINABLE iri #-}+-- |+-- Parser of a well-formed IRI conforming to the RFC3987 standard into 'Iri'.+-- Performs URL-decoding.+{-# INLINEABLE iri #-} iri :: Parser Iri iri = labeled "IRI" $ do@@ -43,15 +51,14 @@ parsedFragment <- fragment return (Iri parsedScheme parsedHierarchy parsedQuery parsedFragment) -{-|-Same as 'iri', but optimized specifially for the case of HTTP IRIs.--}-{-# INLINABLE httpIri #-}+-- |+-- Same as 'iri', but optimized specifially for the case of HTTP IRIs.+{-# INLINEABLE httpIri #-} httpIri :: Parser HttpIri httpIri = labeled "HTTP IRI" $ do asciiCI "http"- secure <- satisfy (\ x -> x == 's' || x == 'S') $> True <|> pure False+ secure <- satisfy (\x -> x == 's' || x == 'S') $> True <|> pure False string "://" parsedHost <- host parsedPort <- PresentPort <$> (char ':' *> port) <|> pure MissingPort@@ -86,43 +93,46 @@ {-# INLINE scheme #-} scheme :: Parser Scheme scheme =- labeled "Scheme" $- fmap (Scheme . B.encodeUtf8) (takeWhile1 (C.scheme . ord))+ labeled "Scheme"+ $ fmap (Scheme . B.encodeUtf8) (takeWhile1 (C.scheme . ord)) -{-# INLINABLE presentUserInfo #-}+{-# INLINEABLE presentUserInfo #-} presentUserInfo :: (User -> Password -> a) -> Parser a presentUserInfo result =- labeled "User info" $- do- user <- User <$> urlEncodedComponent (C.unencodedUserInfoComponent . ord)- passwordFollows <- True <$ char ':' <|> pure False- if passwordFollows- then do- password <- PresentPassword <$> urlEncodedComponent (C.unencodedUserInfoComponent . ord)- return (result user password)- else return (result user MissingPassword)+ labeled "User info"+ $ do+ user <- User <$> urlEncodedComponent (C.unencodedUserInfoComponent . ord)+ passwordFollows <- True <$ char ':' <|> pure False+ if passwordFollows+ then do+ password <- PresentPassword <$> urlEncodedComponent (C.unencodedUserInfoComponent . ord)+ return (result user password)+ else return (result user MissingPassword) {-# INLINE host #-} host :: Parser Host host =- labeled "Host" $- IpV6Host <$> N.parser <|>- IpV4Host <$> M.parser <|>- NamedHost <$> domainName+ labeled "Host"+ $ IpV6Host+ <$> N.parser+ <|> IpV4Host+ <$> M.parser+ <|> NamedHost+ <$> regName -{-# INLINE domainName #-}-domainName :: Parser RegName-domainName =+{-# INLINE regName #-}+regName :: Parser RegName+regName = fmap RegName (E.sepBy1 domainLabel (char '.')) -{-|-Domain label with Punycode decoding applied.--}+-- |+-- Domain label with Punycode decoding applied. {-# INLINE domainLabel #-} domainLabel :: Parser DomainLabel domainLabel =- labeled "Domain label" $- DomainLabel <$> takeWhile1 (C.unencodedRegName . ord)+ labeled "Domain label"+ $ DomainLabel+ <$> takeWhile1 (C.unencodedRegName . ord) {-# INLINE port #-} port :: Parser Word16@@ -139,31 +149,34 @@ else return (Path segments) where segmentsAreEmpty segments =- S.length segments == 1 &&- (case S.unsafeHead segments of PathSegment headSegment -> K.null headSegment)+ S.length segments+ == 1+ && (case S.unsafeHead segments of PathSegment headSegment -> K.null headSegment) {-# INLINE pathSegment #-} pathSegment :: Parser PathSegment pathSegment = fmap PathSegment (urlEncodedComponent (C.unencodedPathSegment . ord)) -{-# INLINABLE urlEncodedComponent #-}+{-# INLINEABLE urlEncodedComponent #-} urlEncodedComponent :: (Char -> Bool) -> Parser ByteString urlEncodedComponent unencodedCharPredicate =- labeled "URL-encoded component" $- fmap ByteString.poking $- R.fold $- (Poking.bytes . B.encodeUtf8 <$> takeWhile1 unencodedCharPredicate) <|> (Poking.word8 <$> urlEncodedByte)+ labeled "URL-encoded component"+ $ fmap ByteString.poking+ $ R.fold+ $ (Poking.bytes . B.encodeUtf8 <$> takeWhile1 unencodedCharPredicate)+ <|> (Poking.word8 <$> urlEncodedByte) -{-# INLINABLE urlEncodedComponentText #-}+{-# INLINEABLE urlEncodedComponentText #-} urlEncodedComponentText :: (Char -> Bool) -> Parser Text urlEncodedComponentText unencodedCharPredicate =- labeled "URL-encoded component" $- fmap J.run $- R.foldl mappend mempty $- (J.text <$> takeWhile1 unencodedCharPredicate) <|> urlEncodedSequenceTextBuilder+ labeled "URL-encoded component"+ $ fmap J.run+ $ R.foldl mappend mempty+ $ (J.text <$> takeWhile1 unencodedCharPredicate)+ <|> urlEncodedSequenceTextBuilder -{-# INLINABLE urlEncodedSequenceTextBuilder #-}+{-# INLINEABLE urlEncodedSequenceTextBuilder #-} urlEncodedSequenceTextBuilder :: Parser J.Builder urlEncodedSequenceTextBuilder = labeled "URL-encoded sequence" $ do@@ -176,6 +189,8 @@ return (builder <> J.text decodedChunk, undecodedBytes, newDecode) Left (L.DecodeError error _) -> fail (showString "UTF8 decoding: " error)+ Left _ ->+ fail "Unexpected decoding error" finish (builder, undecodedBytes, _) = if K.null undecodedBytes then return builder@@ -185,7 +200,7 @@ urlEncodedByte :: Parser Word8 urlEncodedByte = do- char '%' + char '%' digit1 <- fromIntegral <$> hexadecimalDigit digit2 <- fromIntegral <$> hexadecimalDigit return (shiftL digit1 4 .|. digit2)@@ -198,29 +213,31 @@ let x = ord c if x >= 48 && x < 58 then return (x - 48)- else if x >= 65 && x < 71- then return (x - 55)- else if x >= 97 && x < 103- then return (x - 97)- else fail ("Not a hexadecimal digit: " <> show c)+ else+ if x >= 65 && x < 71+ then return (x - 55)+ else+ if x >= 97 && x < 103+ then return (x - 97)+ else fail ("Not a hexadecimal digit: " <> show c) -{-# INLINABLE query #-}+{-# INLINEABLE query #-} query :: Parser Query query =- labeled "Query" $- (char '?' *> queryBody) <|> pure (Query mempty)+ labeled "Query"+ $ (char '?' *> queryBody)+ <|> pure (Query mempty) -{-|-The stuff after the question mark.--}-{-# INLINABLE queryBody #-}+-- |+-- The stuff after the question mark.+{-# INLINEABLE queryBody #-} queryBody :: Parser Query queryBody = fmap Query (urlEncodedComponent (C.unencodedQuery . ord)) -{-# INLINABLE fragment #-}+{-# INLINEABLE fragment #-} fragment :: Parser Fragment fragment =- labeled "Fragment" $- (char '#' *> (Fragment <$> urlEncodedComponent (C.unencodedFragment . ord))) <|>- pure (Fragment mempty)+ labeled "Fragment"+ $ (char '#' *> (Fragment <$> urlEncodedComponent (C.unencodedFragment . ord)))+ <|> pure (Fragment mempty)
library/Iri/Parsing/ByteString.hs view
@@ -1,57 +1,55 @@+{-# OPTIONS_GHC -Wno-unused-top-binds #-}+ module Iri.Parsing.ByteString-(- uri,- httpUri,- regName,- uriQuery,-)+ ( uri,+ httpUri,+ regName,+ uriQuery,+ ) where -import Iri.Prelude+import Data.Attoparsec.ByteString qualified as B+import Data.ByteString qualified as ByteString import Iri.Data-import qualified Iri.Parsing.Attoparsec.ByteString as A-import qualified Data.Attoparsec.ByteString as B-import qualified Data.ByteString as ByteString-+import Iri.Parsing.Attoparsec.ByteString qualified as A+import Iri.Prelude +parser :: B.Parser a -> ByteString -> Either Text a parser parser =- either (Left . fromString) Right .- B.parseOnly (parser <* B.endOfInput)+ either (Left . fromString) Right+ . B.parseOnly (parser <* B.endOfInput) -{-|-Parser of a well-formed URI conforming to the RFC3986 standard into IRI.-Performs URL- and Punycode-decoding.--}+-- |+-- Parser of a well-formed URI conforming to the RFC3986 standard into IRI.+-- Performs URL- and Punycode-decoding. uri :: ByteString -> Either Text Iri uri = parser A.uri -{-|-Same as 'uri', but optimized specifially for the case of HTTP URIs.--}+-- |+-- Same as 'uri', but optimized specifially for the case of HTTP URIs. httpUri :: ByteString -> Either Text HttpIri httpUri = parser A.httpUri -{-|-Domain name parser.--}+-- |+-- Domain name parser. regName :: ByteString -> Either Text RegName regName = parser A.regName -{-|-Assuming we have a valid URI as input, extract the query part from it.--}-uriQuery :: ByteString -> Query+-- |+-- Assuming we have a valid URI as input, extract the query part from it.+uriQuery :: ByteString -> Either Text Query uriQuery x = case ByteString.break (== 63) x of (beforeQuestion, questionAndAfterQuestion) -> case ByteString.uncons questionAndAfterQuestion of Just (_, afterQuestion) -> case ByteString.break (== 35) afterQuestion of- (beforeHash, hashAndAfterHash) -> Query beforeHash+ (beforeHash, hashAndAfterHash) -> Right (Query beforeHash)+ Nothing ->+ Left "Does not start with a question mark" -{-|-Assuming we have a valid URI as input, extract the fragment part from it.--}+-- |+-- Assuming we have a valid URI as input, extract the fragment part from it. uriFragment :: ByteString -> Fragment uriFragment = ByteString.break (== 35) >>> snd >>> ByteString.drop 1 >>> Fragment
library/Iri/Parsing/Text.hs view
@@ -1,29 +1,66 @@ module Iri.Parsing.Text-(- iri,- httpIri,-)+ ( iri,+ httpIri,+ hierarchy,+ scheme,+ host,+ regName,+ domainLabel,+ port,+ path,+ pathSegment,+ query,+ fragment,+ ) where -import Iri.Prelude+import Data.Attoparsec.Text qualified as B import Iri.Data-import qualified Iri.Parsing.Attoparsec.Text as A-import qualified Data.Attoparsec.Text as B+import Iri.Parsing.Attoparsec.Text qualified as A+import Iri.Prelude +fromParser :: B.Parser a -> Text -> Either Text a+fromParser parser =+ either (Left . fromString) Right+ . B.parseOnly (parser <* B.endOfInput) -{-|-Parser of a well-formed IRI conforming to the RFC3987 standard into 'Iri'.-Performs URL-decoding.--}+-- |+-- Parser of a well-formed IRI conforming to the RFC3987 standard into 'Iri'.+-- Performs URL-decoding. iri :: Text -> Either Text Iri-iri =- either (Left . fromString) Right .- B.parseOnly (A.iri <* B.endOfInput)+iri = fromParser A.iri -{-|-Same as 'iri', but optimized specifially for the case of HTTP IRIs.--}+-- |+-- Same as 'iri', but optimized specifially for the case of HTTP IRIs. httpIri :: Text -> Either Text HttpIri-httpIri =- either (Left . fromString) Right .- B.parseOnly (A.httpIri <* B.endOfInput)+httpIri = fromParser A.httpIri++hierarchy :: Text -> Either Text Hierarchy+hierarchy = fromParser A.hierarchy++scheme :: Text -> Either Text Scheme+scheme = fromParser A.scheme++host :: Text -> Either Text Host+host = fromParser A.host++regName :: Text -> Either Text RegName+regName = fromParser A.regName++domainLabel :: Text -> Either Text DomainLabel+domainLabel = fromParser A.domainLabel++port :: Text -> Either Text Word16+port = fromParser A.port++path :: Text -> Either Text Path+path = fromParser A.path++pathSegment :: Text -> Either Text PathSegment+pathSegment = fromParser A.pathSegment++query :: Text -> Either Text Query+query = fromParser A.query++fragment :: Text -> Either Text Fragment+fragment = fromParser A.fragment
library/Iri/PercentEncoding.hs view
@@ -2,17 +2,18 @@ import Iri.Prelude - {-# INLINE matchHexByte #-} matchHexByte :: a -> (Word8 -> a) -> Word8 -> a matchHexByte failure success x = if x >= 48 && x <= 57 then success (x - 48)- else if x >= 65 && x <= 70- then success (x - 55)- else if x >= 97 && x <= 102- then success (x - 87)- else failure+ else+ if x >= 65 && x <= 70+ then success (x - 55)+ else+ if x >= 97 && x <= 102+ then success (x - 87)+ else failure {-# INLINE matchPercentEncodedBytes #-} matchPercentEncodedBytes :: a -> (Word8 -> a) -> Word8 -> Word8 -> a
library/Iri/Prelude.hs view
@@ -1,23 +1,22 @@+{-# OPTIONS_GHC -Wno-dodgy-imports #-}+ module Iri.Prelude-(- module Exports,-)+ ( module Exports,+ ) where ---- base-------------------------- import Control.Applicative as Exports import Control.Arrow as Exports import Control.Category as Exports import Control.Concurrent as Exports import Control.Exception as Exports-import Control.Monad as Exports hiding (mapM_, sequence_, forM_, msum, mapM, sequence, forM)-import Control.Monad.IO.Class as Exports+import Control.Monad as Exports hiding (forM, forM_, mapM, mapM_, msum, sequence, sequence_) import Control.Monad.Fix as Exports hiding (fix)+import Control.Monad.IO.Class as Exports import Control.Monad.ST as Exports import Data.Bits as Exports import Data.Bool as Exports+import Data.ByteString as Exports (ByteString) import Data.Char as Exports import Data.Coerce as Exports import Data.Complex as Exports@@ -27,35 +26,48 @@ import Data.Fixed as Exports import Data.Foldable as Exports import Data.Function as Exports hiding (id, (.))-import Data.Functor as Exports+import Data.Functor as Exports hiding (unzip)+import Data.Functor.Contravariant as Exports+import Data.Functor.Contravariant.Divisible as Exports import Data.Functor.Identity as Exports-import Data.Int as Exports+import Data.HashMap.Strict as Exports (HashMap)+import Data.Hashable as Exports import Data.IORef as Exports+import Data.Int as Exports import Data.Ix as Exports-import Data.List as Exports hiding (sortOn, isSubsequenceOf, uncons, concat, foldr, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, find, maximumBy, minimumBy, mapAccumL, mapAccumR, foldl')+import Data.List as Exports hiding (all, and, any, concat, concatMap, elem, find, foldl, foldl', foldl1, foldr, foldr1, isSubsequenceOf, mapAccumL, mapAccumR, maximum, maximumBy, minimum, minimumBy, notElem, or, product, sortOn, sum, uncons) import Data.Maybe as Exports-import Data.Monoid as Exports hiding (Last(..), First(..))+import Data.Monoid as Exports hiding (First (..), Last (..)) import Data.Ord as Exports+import Data.Profunctor.Choice as Exports+import Data.Profunctor.Strong as Exports+import Data.Profunctor.Unsafe as Exports import Data.Proxy as Exports import Data.Ratio as Exports import Data.STRef as Exports+import Data.Semigroup as Exports import Data.String as Exports+import Data.Text as Exports (Text) import Data.Traversable as Exports import Data.Tuple as Exports import Data.Unique as Exports+import Data.Vector as Exports (Vector)+import Data.Vector.Instances () import Data.Version as Exports import Data.Word as Exports import Debug.Trace as Exports import Foreign.ForeignPtr as Exports import Foreign.Ptr as Exports import Foreign.StablePtr as Exports-import Foreign.Storable as Exports hiding (sizeOf, alignment)-import GHC.Conc as Exports hiding (withMVar, threadWaitWriteSTM, threadWaitWrite, threadWaitReadSTM, threadWaitRead)-import GHC.Exts as Exports (lazy, inline, sortWith, groupWith)+import Foreign.Storable as Exports hiding (alignment, sizeOf)+import GHC.Conc as Exports hiding (threadWaitRead, threadWaitReadSTM, threadWaitWrite, threadWaitWriteSTM, withMVar)+import GHC.Exts as Exports (groupWith, inline, lazy, sortWith) import GHC.Generics as Exports (Generic) import GHC.IO.Exception as Exports+import Instances.TH.Lift ()+import Net.IPv4 as Exports (IPv4)+import Net.IPv6 as Exports (IPv6) import Numeric as Exports-import Prelude as Exports hiding (concat, foldr, mapM_, sequence_, foldl1, maximum, minimum, product, sum, all, and, any, concatMap, elem, foldl, foldr1, notElem, or, mapM, sequence, id, (.)) import System.Environment as Exports import System.Exit as Exports import System.IO as Exports@@ -64,62 +76,7 @@ import System.Mem as Exports import System.Mem.StableName as Exports import System.Timeout as Exports-import Text.ParserCombinators.ReadP as Exports (ReadP, ReadS, readP_to_S, readS_to_P)-import Text.ParserCombinators.ReadPrec as Exports (ReadPrec, readPrec_to_P, readP_to_Prec, readPrec_to_S, readS_to_Prec)-import Text.Printf as Exports (printf, hPrintf)-import Text.Read as Exports (Read(..), readMaybe, readEither)+import Text.Printf as Exports (hPrintf, printf)+import Text.Read as Exports (Read (..), readEither, readMaybe) import Unsafe.Coerce as Exports---- contravariant---------------------------import Data.Functor.Contravariant as Exports-import Data.Functor.Contravariant.Divisible as Exports---- profunctors---------------------------import Data.Profunctor.Unsafe as Exports-import Data.Profunctor.Choice as Exports-import Data.Profunctor.Strong as Exports---- semigroups---------------------------import Data.Semigroup as Exports---- hashable---------------------------import Data.Hashable as Exports---- vector-instances---------------------------import Data.Vector.Instances ()---- bytestring---------------------------import Data.ByteString as Exports (ByteString)---- text---------------------------import Data.Text as Exports (Text)---- ip---------------------------import Net.IPv4 as Exports (IPv4)-import Net.IPv6 as Exports (IPv6)---- vector---------------------------import Data.Vector as Exports (Vector)---- unordered-containers---------------------------import Data.HashMap.Strict as Exports (HashMap)---- th-lift-instances---------------------------import Instances.TH.Lift as Exports------------------------------------------------------------------------------------import qualified Language.Haskell.TH.Lift as A-A.deriveLift ''IPv4-A.deriveLift ''IPv6+import Prelude as Exports hiding (all, and, any, concat, concatMap, elem, foldl, foldl1, foldr, foldr1, id, mapM, mapM_, maximum, minimum, notElem, or, product, sequence, sequence_, sum, (.))
library/Iri/QuasiQuoter.hs view
@@ -1,21 +1,18 @@ module Iri.QuasiQuoter-(- uri,- httpUri,- iri,- httpIri,-)+ ( uri,+ httpUri,+ iri,+ httpIri,+ ) where +import Data.Attoparsec.ByteString qualified as B+import Data.Attoparsec.Text qualified as C+import Iri.Parsing.Attoparsec.ByteString qualified as A+import Iri.Parsing.Attoparsec.Text qualified as D import Iri.Prelude hiding (exp)-import Iri.Data-import Language.Haskell.TH.Syntax import Language.Haskell.TH.Quote-import qualified Iri.Parsing.Attoparsec.ByteString as A-import qualified Data.Attoparsec.ByteString as B-import qualified Data.Attoparsec.Text as C-import qualified Iri.Parsing.Attoparsec.Text as D-+import Language.Haskell.TH.Syntax exp :: (String -> Q Exp) -> QuasiQuoter exp exp =@@ -24,42 +21,38 @@ unsupported _ = fail "Not supported" -{-|-'Iri' literal from ASCII representation.--}+-- |+-- 'Iri' literal from ASCII representation. uri :: QuasiQuoter uri =- exp $ \ string ->- case B.parseOnly (A.uri <* B.endOfInput) (fromString string) of- Right uri -> lift uri- Left error -> fail (showString "URI parsing: " error)+ exp $ \string ->+ case B.parseOnly (A.uri <* B.endOfInput) (fromString string) of+ Right uri -> lift uri+ Left error -> fail (showString "URI parsing: " error) -{-|-'HttpIri' literal from ASCII representation.--}+-- |+-- 'HttpIri' literal from ASCII representation. httpUri :: QuasiQuoter httpUri =- exp $ \ string ->- case B.parseOnly (A.httpUri <* B.endOfInput) (fromString string) of- Right uri -> lift uri- Left error -> fail (showString "HTTP URI parsing: " error)+ exp $ \string ->+ case B.parseOnly (A.httpUri <* B.endOfInput) (fromString string) of+ Right uri -> lift uri+ Left error -> fail (showString "HTTP URI parsing: " error) -{-|-'Iri' literal from IRI representation.--}+-- |+-- 'Iri' literal from IRI representation. iri :: QuasiQuoter iri =- exp $ \ string ->- case C.parseOnly (D.iri <* C.endOfInput) (fromString string) of- Right iri -> lift iri- Left error -> fail (showString "IRI parsing: " error)+ exp $ \string ->+ case C.parseOnly (D.iri <* C.endOfInput) (fromString string) of+ Right iri -> lift iri+ Left error -> fail (showString "IRI parsing: " error) -{-|-'HttpIri' literal from IRI representation.--}+-- |+-- 'HttpIri' literal from IRI representation. httpIri :: QuasiQuoter httpIri =- exp $ \ string ->- case C.parseOnly (D.httpIri <* C.endOfInput) (fromString string) of- Right iri -> lift iri- Left error -> fail (showString "HTTP IRI parsing: " error)+ exp $ \string ->+ case C.parseOnly (D.httpIri <* C.endOfInput) (fromString string) of+ Right iri -> lift iri+ Left error -> fail (showString "HTTP IRI parsing: " error)
library/Iri/Rendering/ByteString.hs view
@@ -1,18 +1,16 @@-module Iri.Rendering.ByteString-where+module Iri.Rendering.ByteString where -import Iri.Prelude import Iri.Data-import qualified Iri.Rendering.Ptr.Poking as A-import qualified Ptr.ByteString as F-+import Iri.Prelude+import Iri.Rendering.Ptr.Poking qualified as A+import Ptr.ByteString qualified as F -{-| Render as URI ASCII bytes -}+-- | Render as URI ASCII bytes uri :: Iri -> ByteString uri = F.poking . A.uri -{-| Render as URI ASCII bytes -}+-- | Render as URI ASCII bytes httpUri :: HttpIri -> ByteString httpUri = F.poking . A.httpUri
library/Iri/Rendering/Ptr/Poke.hs view
@@ -1,14 +1,12 @@-module Iri.Rendering.Ptr.Poke-where+module Iri.Rendering.Ptr.Poke where import Iri.Prelude-import Iri.Data import Ptr.Poke - {-# NOINLINE urlEncodedByte #-} urlEncodedByte :: Poke Word8 urlEncodedByte =- divide (\byte -> ('%', byte))+ divide+ (\byte -> ('%', byte)) asciiChar (divide (flip divMod 16) asciiHexDigit asciiHexDigit)
library/Iri/Rendering/Ptr/Poking.hs view
@@ -1,53 +1,52 @@+{-# OPTIONS_GHC -Wno-unused-top-binds #-}+ module Iri.Rendering.Ptr.Poking-(- uri,- httpUri,- scheme,- host,- path,- query,-)+ ( uri,+ httpUri,+ scheme,+ host,+ path,+ query,+ ) where -import Iri.Prelude hiding (null, poke)+import Data.ByteString qualified as ByteString+import Data.Text qualified as C+import Data.Text.Encoding qualified as A+import Data.Text.Punycode qualified as B+import Iri.CodePointPredicates.Core qualified as I+import Iri.CodePointPredicates.Rfc3986 qualified as I import Iri.Data+import Iri.Prelude hiding (null, poke)+import Iri.Rendering.Ptr.Poke qualified as L+import Iri.Utf8CodePoint qualified as K+import Iri.Vector qualified as F+import Net.IPv4 qualified as D+import Net.IPv6 qualified as E import Ptr.Poking-import qualified Data.Text.Encoding as A-import qualified Data.Text.Encoding.Error as A-import qualified Data.Text.Punycode as B-import qualified Data.Text as C-import qualified Data.ByteString as ByteString-import qualified Data.HashMap.Strict as G-import qualified Data.Vector as H-import qualified Net.IPv4 as D-import qualified Net.IPv6 as E-import qualified Iri.Vector as F-import qualified Iri.CodePointPredicates.Core as I-import qualified Iri.CodePointPredicates.Rfc3986 as I-import qualified Iri.Utf8CodePoint as K-import qualified Iri.Rendering.Ptr.Poke as L - uri :: Iri -> Poking uri (Iri schemeValue hierarchyValue queryValue fragmentValue) =- scheme schemeValue <> - asciiChar ':' <>- hierarchy hierarchyValue <>- (prependIfNotNull- (asciiChar '?')- (query queryValue)) <>- (prependIfNotNull- (asciiChar '#')- (fragment fragmentValue))+ scheme schemeValue+ <> asciiChar ':'+ <> hierarchy hierarchyValue+ <> ( prependIfNotNull+ (asciiChar '?')+ (query queryValue)+ )+ <> ( prependIfNotNull+ (asciiChar '#')+ (fragment fragmentValue)+ ) httpUri :: HttpIri -> Poking httpUri (HttpIri (Security secure) hostValue portValue pathValue queryValue fragmentValue) =- (if secure then "https://" else "http://") <>- host hostValue <>- prependIfNotNull (asciiChar ':') (port portValue) <>- prependIfNotNull (asciiChar '/') (path pathValue) <>- prependIfNotNull (asciiChar '?') (query queryValue) <>- prependIfNotNull (asciiChar '#') (fragment fragmentValue)+ (if secure then "https://" else "http://")+ <> host hostValue+ <> prependIfNotNull (asciiChar ':') (port portValue)+ <> prependIfNotNull (asciiChar '/') (path pathValue)+ <> prependIfNotNull (asciiChar '?') (query queryValue)+ <> prependIfNotNull (asciiChar '#') (fragment fragmentValue) scheme :: Scheme -> Poking scheme (Scheme value) =@@ -55,7 +54,7 @@ hierarchy :: Hierarchy -> Poking hierarchy =- \ case+ \case AuthorisedHierarchy authorityValue pathValue -> bytes "//" <> authority authorityValue <> prependIfNotNull (asciiChar '/') (path pathValue) AbsoluteHierarchy pathValue ->@@ -65,13 +64,13 @@ authority :: Authority -> Poking authority (Authority userInfoValue hostValue portValue) =- appendIfNotNull (asciiChar '@') (userInfo userInfoValue) <>- host hostValue <>- prependIfNotNull (asciiChar ':') (port portValue)+ appendIfNotNull (asciiChar '@') (userInfo userInfoValue)+ <> host hostValue+ <> prependIfNotNull (asciiChar ':') (port portValue) userInfo :: UserInfo -> Poking userInfo =- \ case+ \case PresentUserInfo (User user) password -> case password of PresentPassword password -> userInfoComponent user <> asciiChar ':' <> userInfoComponent password MissingPassword -> userInfoComponent user@@ -83,7 +82,7 @@ host :: Host -> Poking host =- \ case+ \case NamedHost value -> domainName value IpV4Host value -> ipV4 value IpV6Host value -> ipV6 value@@ -108,7 +107,7 @@ port :: Port -> Poking port =- \ case+ \case PresentPort value -> asciiIntegral value MissingPort -> mempty @@ -130,25 +129,26 @@ urlEncodedBytes :: I.Predicate -> ByteString -> Poking urlEncodedBytes unencodedPredicate =- ByteString.foldl' (\ poking -> mappend poking . byte) mempty+ ByteString.foldl' (\poking -> mappend poking . byte) mempty where byte x = if unencodedPredicate (fromIntegral x) then word8 x else urlEncodedByte x -{-| Apply URL-encoding to text -}+-- | Apply URL-encoding to text urlEncodedText :: I.Predicate -> Text -> Poking urlEncodedText unencodedPredicate =- C.foldl' (\ poking -> mappend poking . urlEncodedUnicodeCodePoint unencodedPredicate . ord) mempty+ C.foldl' (\poking -> mappend poking . urlEncodedUnicodeCodePoint unencodedPredicate . ord) mempty urlEncodedUnicodeCodePoint :: I.Predicate -> Int -> Poking urlEncodedUnicodeCodePoint unencodedPredicate codePoint =- K.unicodeCodePoint codePoint- (\ b1 -> if unencodedPredicate codePoint then word8 b1 else urlEncodedByte b1)- (\ b1 b2 -> urlEncodedByte b1 <> urlEncodedByte b2)- (\ b1 b2 b3 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3)- (\ b1 b2 b3 b4 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3 <> urlEncodedByte b4)+ K.unicodeCodePoint+ codePoint+ (\b1 -> if unencodedPredicate codePoint then word8 b1 else urlEncodedByte b1)+ (\b1 b2 -> urlEncodedByte b1 <> urlEncodedByte b2)+ (\b1 b2 b3 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3)+ (\b1 b2 b3 b4 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3 <> urlEncodedByte b4) urlEncodedByte :: Word8 -> Poking urlEncodedByte =
library/Iri/Rendering/Text.hs view
@@ -1,8 +1,6 @@ module Iri.Rendering.Text-(- module Iri.Rendering.Text.Internal,-)+ ( module Iri.Rendering.Text.Internal,+ ) where import Iri.Rendering.Text.Internal-import Iri.Data
library/Iri/Rendering/Text/Internal.hs view
@@ -1,18 +1,16 @@-module Iri.Rendering.Text.Internal-where+module Iri.Rendering.Text.Internal where -import Iri.Prelude import Iri.Data.Types-import qualified Iri.Rendering.TextBuilder.Internal as A-import qualified Text.Builder as B-+import Iri.Prelude+import Iri.Rendering.TextBuilder.Internal qualified as A+import Text.Builder qualified as B -{-| Render as a Unicode IRI text -}+-- | Render as a Unicode IRI text iri :: Iri -> Text iri = B.run . A.iri -{-| Render as a Unicode IRI text -}+-- | Render as a Unicode IRI text httpIri :: HttpIri -> Text httpIri = B.run . A.httpIri
library/Iri/Rendering/TextBuilder.hs view
@@ -1,8 +1,6 @@ module Iri.Rendering.TextBuilder-(- module Iri.Rendering.TextBuilder.Internal,-)+ ( module Iri.Rendering.TextBuilder.Internal,+ ) where import Iri.Rendering.TextBuilder.Internal-import Iri.Data.Types
library/Iri/Rendering/TextBuilder/Internal.hs view
@@ -1,49 +1,46 @@ module Iri.Rendering.TextBuilder.Internal-(- iri,- httpIri,-)+ ( iri,+ httpIri,+ ) where -import Iri.Prelude hiding (null)+import Data.ByteString qualified as ByteString+import Data.Text qualified as C+import Data.Text.Encoding qualified as A+import Data.Text.Encoding.Error qualified as A+import Iri.CodePointPredicates.Core qualified as CorePredicates+import Iri.CodePointPredicates.Rfc3986 qualified as Rfc3986Predicates+import Iri.CodePointPredicates.Rfc3987 qualified as Rfc3987Predicates import Iri.Data.Types+import Iri.Prelude hiding (null)+import Iri.Utf8CodePoint qualified as K+import Iri.Vector qualified as F+import Net.IPv4 qualified as D+import Net.IPv6 qualified as E import Text.Builder-import qualified Data.Text.Encoding as A-import qualified Data.Text.Encoding.Error as A-import qualified Data.Text.Punycode as B-import qualified Data.Text as C-import qualified Data.HashMap.Strict as G-import qualified Data.Vector as H-import qualified Net.IPv4 as D-import qualified Net.IPv6 as E-import qualified Iri.Vector as F-import qualified Iri.CodePointPredicates.Core as CorePredicates-import qualified Iri.CodePointPredicates.Rfc3987 as Rfc3987Predicates-import qualified Iri.CodePointPredicates.Rfc3986 as Rfc3986Predicates-import qualified Iri.Utf8CodePoint as K-import qualified Data.ByteString as ByteString - iri :: Iri -> Builder iri (Iri schemeValue hierarchyValue queryValue fragmentValue) =- scheme schemeValue <> - char ':' <>- hierarchy hierarchyValue <>- (prependIfNotNull- (char '?')- (query queryValue)) <>- (prependIfNotNull- (char '#')- (fragment fragmentValue))+ scheme schemeValue+ <> char ':'+ <> hierarchy hierarchyValue+ <> ( prependIfNotNull+ (char '?')+ (query queryValue)+ )+ <> ( prependIfNotNull+ (char '#')+ (fragment fragmentValue)+ ) httpIri :: HttpIri -> Builder httpIri (HttpIri (Security secure) hostValue portValue pathValue queryValue fragmentValue) =- (if secure then string "https://" else string "http://") <>- host hostValue <>- prependIfNotNull (char ':') (port portValue) <>- prependIfNotNull (char '/') (path pathValue) <>- prependIfNotNull (char '?') (query queryValue) <>- prependIfNotNull (char '#') (fragment fragmentValue)+ (if secure then string "https://" else string "http://")+ <> host hostValue+ <> prependIfNotNull (char ':') (port portValue)+ <> prependIfNotNull (char '/') (path pathValue)+ <> prependIfNotNull (char '?') (query queryValue)+ <> prependIfNotNull (char '#') (fragment fragmentValue) scheme :: Scheme -> Builder scheme (Scheme bytes) =@@ -51,7 +48,7 @@ hierarchy :: Hierarchy -> Builder hierarchy =- \ case+ \case AuthorisedHierarchy authorityValue pathValue -> string "//" <> authority authorityValue <> prependIfNotNull (char '/') (path pathValue) AbsoluteHierarchy pathValue ->@@ -61,15 +58,15 @@ authority :: Authority -> Builder authority (Authority userInfoValue hostValue portValue) =- appendIfNotNull (char '@') (userInfo userInfoValue) <>- host hostValue <>- prependIfNotNull (char ':') (port portValue)+ appendIfNotNull (char '@') (userInfo userInfoValue)+ <> host hostValue+ <> prependIfNotNull (char ':') (port portValue) userInfo :: UserInfo -> Builder userInfo =- \ case+ \case PresentUserInfo (User user) password -> case password of- PresentPassword password -> userInfoComponent user <> char ':' <> userInfoComponent password+ PresentPassword password -> userInfoComponent user <> char ':' <> userInfoComponent password MissingPassword -> userInfoComponent user MissingUserInfo -> mempty @@ -79,7 +76,7 @@ host :: Host -> Builder host =- \ case+ \case NamedHost value -> domainName value IpV4Host value -> ipV4 value IpV6Host value -> ipV6 value@@ -102,7 +99,7 @@ port :: Port -> Builder port =- \ case+ \case PresentPort value -> unsignedDecimal value MissingPort -> mempty @@ -128,31 +125,34 @@ Right text -> urlEncodedText unencodedPredicate1 text Left _ -> urlEncodedBytes unencodedPredicate2 bytes -{-| Apply URL-encoding to text -}+-- | Apply URL-encoding to text urlEncodedBytes :: CorePredicates.Predicate -> ByteString -> Builder urlEncodedBytes unencodedPredicate = ByteString.foldl'- (\ builder -> mappend builder . \ byte -> if unencodedPredicate (fromIntegral byte)- then utf8CodeUnits1 byte- else urlEncodedByte byte)+ ( \builder ->+ mappend builder . \byte ->+ if unencodedPredicate (fromIntegral byte)+ then utf8CodeUnits1 byte+ else urlEncodedByte byte+ ) mempty -{-| Apply URL-encoding to text -}+-- | Apply URL-encoding to text urlEncodedText :: CorePredicates.Predicate -> Text -> Builder urlEncodedText unencodedPredicate =- C.foldl' (\ builder -> mappend builder . urlEncodedUnicodeCodePoint unencodedPredicate . ord) mempty+ C.foldl' (\builder -> mappend builder . urlEncodedUnicodeCodePoint unencodedPredicate . ord) mempty urlEncodedUnicodeCodePoint :: CorePredicates.Predicate -> Int -> Builder urlEncodedUnicodeCodePoint unencodedPredicate codePoint = if unencodedPredicate codePoint- then- unicodeCodePoint codePoint+ then unicodeCodePoint codePoint else- K.unicodeCodePoint codePoint- (\ b1 -> urlEncodedByte b1)- (\ b1 b2 -> urlEncodedByte b1 <> urlEncodedByte b2)- (\ b1 b2 b3 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3)- (\ b1 b2 b3 b4 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3 <> urlEncodedByte b4)+ K.unicodeCodePoint+ codePoint+ (\b1 -> urlEncodedByte b1)+ (\b1 b2 -> urlEncodedByte b1 <> urlEncodedByte b2)+ (\b1 b2 b3 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3)+ (\b1 b2 b3 b4 -> urlEncodedByte b1 <> urlEncodedByte b2 <> urlEncodedByte b3 <> urlEncodedByte b4) urlEncodedByte :: Word8 -> Builder urlEncodedByte x =
library/Iri/Utf8CodePoint.hs view
@@ -1,14 +1,11 @@-{- |-Utilities for the UTF-8 encoding.--}+-- |+-- Utilities for the UTF-8 encoding. module Iri.Utf8CodePoint where import Iri.Prelude --{-|-Church encoding of a UTF8-encoded character.--}+-- |+-- Church encoding of a UTF8-encoded character. type Utf8CodePoint = forall a. (Word8 -> a) ->@@ -19,31 +16,30 @@ {-# INLINE char #-} char :: Char -> Utf8CodePoint-char =- unicodeCodePoint . ord+char a =+ unicodeCodePoint (ord a) {-# INLINE unicodeCodePoint #-} unicodeCodePoint :: Int -> Utf8CodePoint unicodeCodePoint x f1 f2 f3 f4 = if x <= 0x7F- then- f1 (fromIntegral x)- else + then f1 (fromIntegral x)+ else if x <= 0x07FF then f2- (fromIntegral ((x `shiftR` 6) + 0xC0))- (fromIntegral ((x .&. 0x3F) + 0x80))+ (fromIntegral ((x `shiftR` 6) + 0xC0))+ (fromIntegral ((x .&. 0x3F) + 0x80)) else if x <= 0xFFFF then f3- (fromIntegral (x `shiftR` 12) + 0xE0)- (fromIntegral ((x `shiftR` 6) .&. 0x3F) + 0x80)- (fromIntegral (x .&. 0x3F) + 0x80)+ (fromIntegral (x `shiftR` 12) + 0xE0)+ (fromIntegral ((x `shiftR` 6) .&. 0x3F) + 0x80)+ (fromIntegral (x .&. 0x3F) + 0x80) else f4- (fromIntegral (x `shiftR` 18) + 0xF0)- (fromIntegral ((x `shiftR` 12) .&. 0x3F) + 0x80)- (fromIntegral ((x `shiftR` 6) .&. 0x3F) + 0x80)- (fromIntegral (x .&. 0x3F) + 0x80)+ (fromIntegral (x `shiftR` 18) + 0xF0)+ (fromIntegral ((x `shiftR` 12) .&. 0x3F) + 0x80)+ (fromIntegral ((x `shiftR` 6) .&. 0x3F) + 0x80)+ (fromIntegral (x .&. 0x3F) + 0x80)
library/Iri/Vector.hs view
@@ -1,12 +1,10 @@-module Iri.Vector-where+module Iri.Vector where -import Iri.Prelude hiding (null, length) import Data.Vector-+import Iri.Prelude hiding (length, null) {-# INLINE intercalate #-}-intercalate :: (Semigroup monoid, Monoid monoid) => (element -> monoid) -> monoid -> Vector element -> monoid+intercalate :: (Monoid monoid) => (element -> monoid) -> monoid -> Vector element -> monoid intercalate project separator vector = if null vector then mempty
+ punycode/Data/Text/Punycode.hs view
@@ -0,0 +1,4 @@+module Data.Text.Punycode (encode, PunycodeDecodeException (..), decode) where++import Data.Text.Punycode.Decode (PunycodeDecodeException (..), decode)+import Data.Text.Punycode.Encode (encode)
+ punycode/Data/Text/Punycode/Decode.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE DeriveDataTypeable #-}++module Data.Text.Punycode.Decode (PunycodeDecodeException (..), decode) where++import Control.Exception.Base+import qualified Data.ByteString as BS+import Data.Char+import Data.Serialize hiding (decode)+import qualified Data.Text as T+import Data.Text.Punycode.Shared+import Data.Typeable+import Data.Word++data PunycodeDecodeException+ = GenericDecodeException+ | InternalStringTooShort+ | InputTooShort+ | RightOfHyphenShouldBeAlphanumeric+ | LeftOfHyphenShouldBeBasic+ | CantStartWithDash+ | InvalidCodePoint+ deriving (Eq, Show, Typeable)++instance Exception PunycodeDecodeException++-- | Decode a string into its unicode form+decode :: BS.ByteString -> Either PunycodeDecodeException T.Text+decode input+ | input == BS.pack [45, 45] = Right $ T.pack "-"+ | not (BS.null input) && BS.length (BS.filter (== 45) input) == 1 && BS.head input == 45 = Left CantStartWithDash+ | T.any (not . isExtendedBasic) before = Left LeftOfHyphenShouldBeBasic+ | otherwise = case runGet (inner2 initial_n 0 initial_bias before) after of+ Right out -> out+ Left _ -> Left InputTooShort+ where+ (before, after)+ | BS.any f input = (T.pack $ map (chr . fromIntegral) $ BS.unpack $ BS.init b1, a1)+ | otherwise = (T.empty, input)+ f = (== (fromIntegral $ ord '-'))+ (b1, a1) = BS.breakEnd f input++inner2 :: Int -> Int -> Int -> T.Text -> Get (Either PunycodeDecodeException T.Text)+inner2 n oldi bias output = do+ b <- isEmpty+ helper b+ where+ helper False = do+ i <- inner base 1 oldi bias+ helper' i+ where+ helper' Nothing = return $ Left RightOfHyphenShouldBeAlphanumeric+ helper' (Just i) = case output' of+ Right output'' -> inner2 n' (i' + 1) bias' output''+ Left err -> return $ Left err+ where+ bias' = adapt (i - oldi) (T.length output + 1) (oldi == 0)+ n' = n + i `div` (T.length output + 1)+ i' = i `mod` (T.length output + 1)+ output' = insertInto output n' i'+ helper True = return $ Right output++inner :: Int -> Int -> Int -> Int -> Get (Maybe Int)+inner k w i bias = do+ word8 <- getWord8+ helper $ word8ToDigit word8+ where+ helper Nothing = return Nothing+ helper (Just digit)+ | digit < t = return $ Just i'+ | otherwise = inner (k + base) w' i' bias+ where+ w' = w * (base - t)+ i' = i + digit * w+ t+ | k <= bias + tmin = tmin+ | k >= bias + tmax = tmax+ | otherwise = k - bias++insertInto :: T.Text -> Int -> Int -> Either PunycodeDecodeException T.Text+insertInto input n i+ | T.length input < i = Left InternalStringTooShort+ | otherwise = case n' of+ Just n'' -> Right $ T.concat [T.take i input, T.singleton n'', T.drop i input]+ Nothing -> Left InvalidCodePoint+ where+ n' = safeChr n++safeChr :: Int -> Maybe Char+safeChr x+ | x >= 0 && x <= fromEnum (maxBound :: Char) = Just $ chr x+ | otherwise = Nothing++word8ToDigit :: Word8 -> Maybe Int+word8ToDigit = helper . fromIntegral+ where+ helper word8+ | word8 >= ord 'a' && word8 <= ord 'z' = Just $ word8 - (ord 'a')+ | word8 >= ord 'A' && word8 <= ord 'Z' = Just $ word8 - (ord 'A')+ | word8 >= ord '0' && word8 <= ord '9' = Just $ 26 + word8 - (ord '0')+ | otherwise = Nothing++isExtendedBasic :: Char -> Bool+isExtendedBasic x+ | isBasic x = True+ | ord x == 128 = True+ | otherwise = False
+ punycode/Data/Text/Punycode/Encode.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE FlexibleContexts #-}++module Data.Text.Punycode.Encode (encode) where++import Control.Monad+import Control.Monad.State hiding (state)+import Control.Monad.Writer+import qualified Data.ByteString as BS+import Data.Char+import qualified Data.Text as T+import qualified Data.Text.Encoding as TE+import Data.Text.Punycode.Shared+import Data.Word++data PunycodeState = PunycodeState+ { n :: Int,+ delta :: Int,+ bias :: Int,+ h :: Int+ }++-- | Encode a string into its ascii form+encode :: T.Text -> BS.ByteString+encode = execWriter . initialWriter++initialWriter :: (MonadWriter BS.ByteString m) => T.Text -> m ()+initialWriter input = do+ tell basics+ when (b > 0) $ tell $ BS.singleton $ fromIntegral $ ord '-'+ evalStateT (inner3 (map ord $ T.unpack input) b) $+ PunycodeState+ { n = initial_n,+ delta = 0,+ bias = initial_bias,+ h = b+ }+ where+ basics = TE.encodeUtf8 $ T.filter isBasic input+ b = BS.length basics++inner3 :: (MonadState PunycodeState m, MonadWriter BS.ByteString m) => [Int] -> Int -> m ()+inner3 input b = do+ state <- get+ helper state+ where+ helper state+ | h' < length input = do+ put $ state {n = m, delta = delta'}+ mapM_ (inner2 b) input+ state' <- get+ put $ state' {delta = (delta state') + 1, n = (n state') + 1}+ inner3 input b+ | otherwise = return ()+ where+ m = minimum $ filter (>= n') input+ n' = n state+ h' = h state+ delta' = (delta state) + (m - n') * (h' + 1)++inner2 :: (MonadState PunycodeState m, MonadWriter BS.ByteString m) => Int -> Int -> m ()+inner2 b c = do+ state <- get+ helper state+ where+ helper state+ | c == n' = do+ q <- inner delta' base bias'+ tell $ BS.singleton $ baseToAscii q+ put $ state {bias = adapt delta' (h' + 1) (h' == b), delta = 0, h = (h state) + 1}+ | otherwise = put $ state {delta = delta'}+ where+ delta' = (delta state) + d+ where+ d+ | c < n' = 1+ | otherwise = 0+ n' = n state+ bias' = bias state+ h' = h state++inner :: (MonadWriter BS.ByteString m) => Int -> Int -> Int -> m Int+inner q k bias'+ | q < t = return q+ | otherwise = do+ tell $ BS.singleton $ baseToAscii $ t + ((q - t) `mod` (base - t))+ inner ((q - t) `div` (base - t)) (k + base) bias'+ where+ t+ | k <= bias' + tmin = tmin+ | k >= bias' + tmax = tmax+ | otherwise = k - bias'++baseToAscii :: Int -> Word8+baseToAscii i+ | i < 26 = fromIntegral $ i + (ord 'a')+ | otherwise = fromIntegral $ (i - 26) + (ord '0')
@@ -0,0 +1,39 @@+module Data.Text.Punycode.Shared where++import Data.Char (ord)++base :: Int+base = 36++tmin :: Int+tmin = 1++tmax :: Int+tmax = 26++skew :: Int+skew = 38++damp :: Int+damp = 700++initial_bias :: Int+initial_bias = 72++initial_n :: Int+initial_n = 128++adapt :: Int -> Int -> Bool -> Int+adapt delta numpoints firsttime = helper+ where+ helper = loop 0 $ delta' + (delta' `div` numpoints)+ where+ delta'+ | firsttime = delta `div` damp+ | otherwise = delta `div` 2+ loop k delta'+ | delta' > ((base - tmin) * tmax) `div` 2 = loop (k + base) $ delta' `div` (base - tmin)+ | otherwise = k + (((base - tmin + 1) * delta') `div` (delta' + skew))++isBasic :: Char -> Bool+isBasic = (< initial_n) . ord
test/Main.hs view
@@ -1,119 +1,102 @@ module Main where -import Prelude-import Test.QuickCheck.Instances+import Iri.Parsing.ByteString qualified as D+import Iri.Parsing.Text qualified as F+import Iri.QuasiQuoter+import Iri.Rendering.ByteString qualified as E+import Iri.Rendering.Text qualified as C import Test.Tasty-import Test.Tasty.Runners import Test.Tasty.HUnit-import Test.Tasty.QuickCheck-import Iri.QuasiQuoter-import qualified Iri.Data as A-import qualified Iri.Parsing.ByteString as D-import qualified Iri.Parsing.Text as F-import qualified Iri.Rendering.Text as C-import qualified Iri.Rendering.ByteString as E-+import Prelude +main :: IO () main =- defaultMain $- testGroup "All tests" $- [- testCase "No path" $- assertEqual ""- (Right "https://ru.wikipedia.org?query")- (fmap C.iri- (D.uri "https://ru.wikipedia.org?query"))- ,- testCase "Cyrillic path" $ do- assertEqual ""- (Right "https://ru.wikipedia.org/wiki/Баренцбург")- (fmap C.iri- (D.uri "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3"))- ,- testCase "Complex query" $ do- assertEqual ""- (Right "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb")- (fmap C.iri- (D.uri "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb"))- ,- testCase "Rendering" $- let- inputs =- [- "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3"- ,- "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb"- ]- in- forM_ inputs $ \ input ->- let- Right iri = D.uri input- in assertEqual "" input (E.uri iri)- ,- testCase "about:blank" $ assertEqual "" "about:blank" (E.uri [uri|about:blank|])- ,- testCase "Empty hierarchy" $ assertEqual "" "about:" (E.uri [uri|about:|])- ,- testCase "HTTP URI Text Rendering" $- assertEqual ""- "https://ru.wikipedia.org/wiki/Баренцбург"- (C.httpIri [httpUri|https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3|])- ,- testCase "HTTP URI Show" $- assertEqual ""- "https://ru.wikipedia.org/wiki/Баренцбург"- (show [httpUri|https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3|])- ,- testCase "Messed up URIs" $- let- testUri uri =- assertEqual "Original and parsed URIs are not equal" (Right uri) (fmap E.uri (D.uri uri))- in traverse_ testUri- [- "http://m.ru.hellomagazine.com/krasota-i-zdorove/ukhod-za-kozhey-i-volosami/11373-5-prichesok-kotorye-sdelayut-vas-molozhe.html?utm_medium=teaser&utm_campaign=gnezdo1&utm_term=15376&utm_content=[TID",- "https://m.tsargrad.tv/news/komediju_113156?%90\"%20"- ]- ,- testCase "User Info" $- assertEqual "" (Right "http://user:password@localhost:993") (fmap E.uri (D.uri "http://user:password@localhost:993"))- ,- testGroup "IRI parser vs. URI parser" $ let- testUriIri iri uri =- testCase (iri <> " vs. " <> uri) $- assertEqual "" (F.iri (fromString iri)) (D.uri (fromString uri))- in- [- testUriIri+ defaultMain+ $ testGroup "All tests"+ $ [ testCase "No path"+ $ assertEqual+ ""+ (Right "https://ru.wikipedia.org?query")+ ( fmap+ C.iri+ (D.uri "https://ru.wikipedia.org?query")+ ),+ testCase "Cyrillic path" $ do+ assertEqual+ ""+ (Right "https://ru.wikipedia.org/wiki/Баренцбург")+ ( fmap+ C.iri+ (D.uri "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3")+ ),+ testCase "Complex query" $ do+ assertEqual+ ""+ (Right "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb")+ ( fmap+ C.iri+ (D.uri "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb")+ ),+ testCase "Rendering"+ $ let inputs =+ [ "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3",+ "https://news.yandex.ru/yandsearch?cl4url=iz.ru/669426/2017-11-10/smi-inoagenty-obiazhut-soobshchat-ob-etom-v-sotcsetiakh&lang=ru&from=main_portal&stid=5bdMOjSopWu34pdT-391&lr=213&msid=1510328052.50316.22874.7658&mlid=1510327228.glob_225.904af5bb"+ ]+ in forM_ inputs $ \input ->+ assertEqual "" (Right input) (fmap E.uri (D.uri input)),+ testCase "about:blank" $ assertEqual "" "about:blank" (E.uri [uri|about:blank|]),+ testCase "Empty hierarchy" $ assertEqual "" "about:" (E.uri [uri|about:|]),+ testCase "HTTP URI Text Rendering"+ $ assertEqual+ "" "https://ru.wikipedia.org/wiki/Баренцбург"- "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3"- ,- testUriIri- "https://www.w3.org/International/articles/idn-and-iri/JP納豆/引き割り納豆.html"- "https://www.w3.org/International/articles/idn-and-iri/JP%E7%B4%8D%E8%B1%86/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A%E7%B4%8D%E8%B1%86.html"- ,- testUriIri- "http://点心和烤鸭.w3.mag.keio.ac.jp"- "http://xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp/"- ]- ,- testGroup "Mess" $- [- testCase "1" $- assertEqual ""- (Right "https://www.kupivip.ru/catalog/muzhchinam/odezhda?srcid=goo-tm-open&lpu=|source:google|medium:cpc|adposition:1t1|creative:195388077752|term:%2B%D0%B2%D0%B8%D0%BF%20%2B%D0%BA%D1%83%D0%BF%D0%B8|campaignid:801742449|campaign:goo_tm_mob_s_male|other:m|ad:1|&gclid=CjwKEAjwgb3OBRDNi_2TwZ6u7D4SJADsmW8QKiRxDZZ0hRAnyspAcVW582c7zzQSA7CC0FavPR63dBoCrKPw_wcB")- (fmap E.uri (D.uri "https://www.kupivip.ru/catalog/muzhchinam/odezhda?srcid=goo-tm-open&lpu=|source:google|medium:cpc|adposition:1t1|creative:195388077752|term:%2B%D0%B2%D0%B8%D0%BF%20%2B%D0%BA%D1%83%D0%BF%D0%B8|campaignid:801742449|campaign:goo_tm_mob_s_male|other:m|ad:1|&gclid=CjwKEAjwgb3OBRDNi_2TwZ6u7D4SJADsmW8QKiRxDZZ0hRAnyspAcVW582c7zzQSA7CC0FavPR63dBoCrKPw_wcB"))- ,- testGroup "2" $- [- testCase "show" $- assertEqual ""- (Right "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html")- (fmap show (D.uri "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html"))- ,- testCase "Text rendering" $- assertEqual ""- (Right "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html")- (fmap C.iri (D.uri "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html"))+ (C.httpIri [httpUri|https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3|]),+ testCase "HTTP URI Show"+ $ assertEqual+ ""+ "\"https://ru.wikipedia.org/wiki/Баренцбург\""+ (show [httpUri|https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3|]),+ testCase "Messed up URIs"+ $ let testUri uri =+ assertEqual "Original and parsed URIs are not equal" (Right uri) (fmap E.uri (D.uri uri))+ in traverse_+ testUri+ [ "http://m.ru.hellomagazine.com/krasota-i-zdorove/ukhod-za-kozhey-i-volosami/11373-5-prichesok-kotorye-sdelayut-vas-molozhe.html?utm_medium=teaser&utm_campaign=gnezdo1&utm_term=15376&utm_content=[TID",+ "https://m.tsargrad.tv/news/komediju_113156?%90\"%20"+ ],+ testCase "User Info"+ $ assertEqual "" (Right "http://user:password@localhost:993") (fmap E.uri (D.uri "http://user:password@localhost:993")),+ testGroup "IRI parser vs. URI parser"+ $ let testUriIri iri uri =+ testCase (iri <> " vs. " <> uri)+ $ assertEqual "" (F.iri (fromString iri)) (D.uri (fromString uri))+ in [ testUriIri+ "https://ru.wikipedia.org/wiki/Баренцбург"+ "https://ru.wikipedia.org/wiki/%D0%91%D0%B0%D1%80%D0%B5%D0%BD%D1%86%D0%B1%D1%83%D1%80%D0%B3",+ testUriIri+ "https://www.w3.org/International/articles/idn-and-iri/JP納豆/引き割り納豆.html"+ "https://www.w3.org/International/articles/idn-and-iri/JP%E7%B4%8D%E8%B1%86/%E5%BC%95%E3%81%8D%E5%89%B2%E3%82%8A%E7%B4%8D%E8%B1%86.html",+ testUriIri+ "http://点心和烤鸭.w3.mag.keio.ac.jp"+ "http://xn--0trv4xfvn8el34t.w3.mag.keio.ac.jp/"+ ],+ testGroup "Mess"+ $ [ testCase "1"+ $ assertEqual+ ""+ (Right "https://www.kupivip.ru/catalog/muzhchinam/odezhda?srcid=goo-tm-open&lpu=|source:google|medium:cpc|adposition:1t1|creative:195388077752|term:%2B%D0%B2%D0%B8%D0%BF%20%2B%D0%BA%D1%83%D0%BF%D0%B8|campaignid:801742449|campaign:goo_tm_mob_s_male|other:m|ad:1|&gclid=CjwKEAjwgb3OBRDNi_2TwZ6u7D4SJADsmW8QKiRxDZZ0hRAnyspAcVW582c7zzQSA7CC0FavPR63dBoCrKPw_wcB")+ (fmap E.uri (D.uri "https://www.kupivip.ru/catalog/muzhchinam/odezhda?srcid=goo-tm-open&lpu=|source:google|medium:cpc|adposition:1t1|creative:195388077752|term:%2B%D0%B2%D0%B8%D0%BF%20%2B%D0%BA%D1%83%D0%BF%D0%B8|campaignid:801742449|campaign:goo_tm_mob_s_male|other:m|ad:1|&gclid=CjwKEAjwgb3OBRDNi_2TwZ6u7D4SJADsmW8QKiRxDZZ0hRAnyspAcVW582c7zzQSA7CC0FavPR63dBoCrKPw_wcB")),+ testGroup "2"+ $ [ testCase "show"+ $ assertEqual+ ""+ (Right "\"https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html\"")+ (fmap show (D.uri "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html")),+ testCase "Text rendering"+ $ assertEqual+ ""+ (Right "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html")+ (fmap C.iri (D.uri "https://www.pleer.ru/search_%e4%eb%ff+%e1%e5%eb%fc%ff+%f1%f3%f8%e8%eb%ea%e0.html"))+ ]+ ] ]- ]- ]