Skip to content

Commit 1d6a740

Browse files
committed
parseCodeGeneratorRequestComplete
Much faster plugin code generation when input CodeGenerationRequest is very large.
1 parent 03a7bbd commit 1d6a740

File tree

1 file changed

+53
-10
lines changed

1 file changed

+53
-10
lines changed

plugin/src/Main.purs

+53-10
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ module Main (main) where
55

66
import Prelude
77

8-
import Control.Monad.Rec.Class (tailRecM, Step(..))
8+
import Control.Monad.Rec.Class (class MonadRec, Step(..), tailRecM)
99
import Data.Array (catMaybes, concat, fold, mapWithIndex)
1010
import Data.Array as Array
1111
import Data.ArrayBuffer.ArrayBuffer as AB
1212
import Data.ArrayBuffer.Builder (execPutM)
1313
import Data.ArrayBuffer.DataView as DV
14+
import Data.ArrayBuffer.Types as ABT
1415
import Data.CodePoint.Unicode as Unicode
1516
import Data.Either (Either(..), either)
1617
import Data.Maybe (Maybe(..), fromMaybe, maybe)
@@ -22,20 +23,25 @@ import Data.String.Regex as String.Regex
2223
import Data.String.Regex.Flags as String.Regex.Flags
2324
import Data.Traversable (sequence, traverse)
2425
import Data.Tuple (Tuple(..))
26+
import Data.UInt as UInt
2527
import Data.UInt64 (UInt64)
2628
import Data.UInt64 as UInt64
2729
import Effect (Effect)
2830
import Effect.Aff (runAff_, throwError, error)
29-
import Effect.Class (liftEffect)
31+
import Effect.Class (class MonadEffect, liftEffect)
3032
import Effect.Class.Console as Console
31-
import Google.Protobuf.Compiler.Plugin (CodeGeneratorRequest(..), CodeGeneratorResponse, CodeGeneratorResponse_File(..), mkCodeGeneratorResponse, parseCodeGeneratorRequest, putCodeGeneratorResponse)
33+
import Google.Protobuf.Compiler.Plugin (CodeGeneratorRequest(..), CodeGeneratorResponse, CodeGeneratorResponse_File(..), mkCodeGeneratorResponse, parseCodeGeneratorRequest, putCodeGeneratorResponse, parseVersion)
3234
import Google.Protobuf.Descriptor (DescriptorProto(..), EnumDescriptorProto(..), EnumValueDescriptorProto(..), FieldDescriptorProto(..), FieldDescriptorProto_Label(..), FieldDescriptorProto_Type(..), FieldOptions(..), FileDescriptorProto(..), OneofDescriptorProto(..), SourceCodeInfo(..), SourceCodeInfo_Location(..))
3335
import Node.Buffer (Buffer, toArrayBuffer, fromArrayBuffer)
3436
import Node.Buffer as Buffer
3537
import Node.Path (basenameWithoutExt)
3638
import Node.Process (stdin, stdout)
3739
import Node.Stream.Aff (readSome, write)
38-
import Parsing (runParserT)
40+
import Parsing (ParserT, fail, runParserT)
41+
import Parsing.DataView (takeN)
42+
import Protobuf.Internal.Common (label)
43+
import Protobuf.Internal.Decode (decodeString, decodeTag32)
44+
import Protobuf.Internal.Runtime (parseLenDel, manyLength)
3945
import Unsafe.Coerce (unsafeCoerce)
4046

4147

@@ -51,7 +57,7 @@ main = runAff_ (either (unsafeCoerce >>> Console.error) (\_ -> pure unit)) do
5157
{buffers:b,readagain} <- readSome stdin
5258
let bs' = bs <> b
5359
ab <- liftEffect $ toArrayBuffer =<< Buffer.concat bs'
54-
runParserT (DV.whole ab) (parseCodeGeneratorRequest (AB.byteLength ab)) >>= case _ of
60+
runParserT (DV.whole ab) (parseCodeGeneratorRequestComplete (AB.byteLength ab)) >>= case _ of
5561
Left err -> do
5662
if not readagain then do
5763
void $ throwError $ error "stdin is not readable."
@@ -68,11 +74,48 @@ main = runAff_ (either (unsafeCoerce >>> Console.error) (\_ -> pure unit)) do
6874
else do
6975
void $ throwError $ error $ show err
7076
pure (Done unit)
71-
Right request -> do
72-
responseBuf <- execPutM $ putCodeGeneratorResponse (generate request)
73-
buf :: Buffer <- liftEffect $ fromArrayBuffer responseBuf
74-
write stdout [buf]
75-
pure (Done unit)
77+
Right unit -> do
78+
runParserT (DV.whole ab) (parseCodeGeneratorRequest (AB.byteLength ab)) >>= case _ of
79+
Left err -> do
80+
void $ throwError $ error $ show err
81+
pure (Done unit)
82+
Right request -> do
83+
responseBuf <- execPutM $ putCodeGeneratorResponse (generate request)
84+
buf :: Buffer <- liftEffect $ fromArrayBuffer responseBuf
85+
write stdout [buf]
86+
pure (Done unit)
87+
88+
-- | This is a parser which will succeed only if parseCodeGeneratorRequest will succeed.
89+
-- | It is faster than parseCodeGeneratorRequest.
90+
-- | We use this parser to determine if we have read the whole request from stdin.
91+
-- | If this parser fails then we need to read more from stdin.
92+
parseCodeGeneratorRequestComplete
93+
:: forall m. MonadEffect m
94+
=> MonadRec m
95+
=> ABT.ByteLength
96+
-> ParserT ABT.DataView m Unit
97+
parseCodeGeneratorRequestComplete length = label "parseCodeGeneratorRequestComplete / " $ do
98+
_ <- flip manyLength length do
99+
Tuple fieldNumber _wireType <- decodeTag32
100+
case UInt.toInt fieldNumber of
101+
1 -> do -- file_to_generate
102+
_ <- decodeString
103+
pure unit
104+
2 -> do -- parameter
105+
_ <- decodeString
106+
pure unit
107+
3 -> do -- compiler_version
108+
_ <- parseLenDel parseVersion
109+
pure unit
110+
15 -> do -- proto_file
111+
_ <- parseLenDel takeN
112+
pure unit
113+
17 -> do -- source_file_descriptors
114+
_ <- parseLenDel takeN
115+
pure unit
116+
_ -> do
117+
fail "unexpected field number"
118+
pure unit
76119

77120
generate :: CodeGeneratorRequest -> CodeGeneratorResponse
78121
generate (CodeGeneratorRequest { proto_file }) = do

0 commit comments

Comments
 (0)