-- |
-- 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.CodePointPredicates.Core
import Iri.Prelude hiding (Predicate, inRange, (&&&), (|||))

-- |
-- Reference:
--
-- @
-- unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
-- @
unreserved :: Predicate
unreserved :: Predicate
unreserved =
  Predicate
asciiAlphanumeric Predicate -> Predicate -> Predicate
||| [Char] -> Predicate
oneOfChars [Char]
"-._~"

subDelims :: Predicate
subDelims :: Predicate
subDelims =
  [Char] -> Predicate
oneOfChars [Char]
"!$&'()*+,;="

{-# NOINLINE scheme #-}
scheme :: Predicate
scheme :: Predicate
scheme =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ Predicate
asciiAlphanumeric
    Predicate -> Predicate -> Predicate
||| [Char] -> Predicate
oneOfChars [Char]
"+.-"

{-# NOINLINE domainLabel #-}
domainLabel :: Predicate
domainLabel :: Predicate
domainLabel =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ Predicate
asciiAlphanumeric
    Predicate -> Predicate -> Predicate
||| [Char] -> Predicate
oneOfChars [Char]
"-_~"

{-
pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
-}
{-# NOINLINE unencodedPathSegment #-}
unencodedPathSegment :: Predicate
unencodedPathSegment :: Predicate
unencodedPathSegment =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ Predicate
unreserved
    Predicate -> Predicate -> Predicate
||| Predicate
subDelims
    Predicate -> Predicate -> Predicate
||| [Char] -> Predicate
oneOfChars [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 :: Predicate
unencodedQuery =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ (Predicate
unencodedPathSegment Predicate -> Predicate -> Predicate
||| [Char] -> Predicate
oneOfChars [Char]
"/?|[]\"'")
    Predicate -> Predicate -> Predicate
&&& (Int -> Predicate
forall a. Eq a => a -> a -> Bool
/= Int
43)

unencodedFragment :: Predicate
unencodedFragment :: Predicate
unencodedFragment =
  Predicate
unencodedQuery

{-# NOINLINE unencodedQueryComponent #-}
unencodedQueryComponent :: Predicate
unencodedQueryComponent :: Predicate
unencodedQueryComponent =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ Predicate
unencodedQuery
    Predicate -> Predicate -> Predicate
&&& Bool -> Bool
not
    (Bool -> Bool) -> Predicate -> Predicate
forall b c a. (b -> c) -> (a -> b) -> a -> c
forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. [Char] -> Predicate
oneOfChars [Char]
"=&;"

{-# NOINLINE unencodedUserInfoComponent #-}
unencodedUserInfoComponent :: Predicate
unencodedUserInfoComponent :: Predicate
unencodedUserInfoComponent =
  Predicate -> Predicate
cached
    (Predicate -> Predicate) -> Predicate -> Predicate
forall a b. (a -> b) -> a -> b
$ Predicate
unreserved
    Predicate -> Predicate -> Predicate
||| Predicate
subDelims