content: module Rattletrap.Type.List where
  
  import qualified Control.Monad as Monad
  import qualified Rattletrap.ByteGet as ByteGet
  import qualified Rattletrap.BytePut as BytePut
  import qualified Rattletrap.Schema as Schema
  import qualified Rattletrap.Type.U32 as U32
  import qualified Rattletrap.Utility.Json as Json
  
  newtype List a
    = List [a]
    deriving (Eq, Show)
  
  instance (Json.FromJSON a) => Json.FromJSON (List a) where
    parseJSON = fmap fromList . Json.parseJSON
  
  instance (Json.ToJSON a) => Json.ToJSON (List a) where
    toJSON = Json.toJSON . toList
  
  schema :: Schema.Schema -> Schema.Schema
  schema = Schema.array
  
  fromList :: [a] -> List a
  fromList = List
  
  empty :: List a
  empty = fromList []
  
  toList :: List a -> [a]
  toList (List x) = x
  
  bytePut :: (a -> BytePut.BytePut) -> List a -> BytePut.BytePut
  bytePut f x =
    let v = toList x
     in (U32.bytePut . U32.fromWord32 . fromIntegral $ length v) <> foldMap f v
  
  byteGet :: ByteGet.ByteGet a -> ByteGet.ByteGet (List a)
  byteGet f = ByteGet.label "List" $ do
    size <- ByteGet.label "size" U32.byteGet
    generateM (fromIntegral $ U32.toWord32 size) $
      \i -> ByteGet.label ("element (" <> show i <> ")") f
  
  generateM :: (Monad m) => Int -> (Int -> m a) -> m (List a)
  generateM n f = fmap fromList $ mapM f [0 .. n - 1]
  
  replicateM :: (Monad m) => Int -> m a -> m (List a)
  replicateM n = fmap fromList . Monad.replicateM n
  
  untilM :: (Monad m) => m (Maybe a) -> m (List a)
  untilM f = untilMWith f 0 []
  
  untilMWith :: (Monad m) => m (Maybe a) -> Int -> [(Int, a)] -> m (List a)
  untilMWith f i xs = do
    m <- f
    case m of
      Nothing -> pure . fromList . reverse $ fmap snd xs
      Just x -> untilMWith f (i + 1) ((i, x) : xs)
  