fix(tl): support multiple usages of the same flag

This commit is contained in:
alina 🌸 2023-10-04 02:45:11 +03:00
parent e4e51f7d90
commit 62815d26d7
Signed by: teidesu
SSH key fingerprint: SHA256:uNeCpw6aTSU4aIObXLvHfLkDa82HWH9EiOj9AXOIRpI
2 changed files with 53 additions and 18 deletions

View file

@ -1,6 +1,6 @@
import { calculateStaticSizes } from '../calculator'
import { computeConstructorIdFromEntry } from '../ctor-id'
import { TL_PRIMITIVES, TlEntry } from '../types'
import { TL_PRIMITIVES, TlArgument, TlEntry } from '../types'
import { snakeToCamel } from './utils'
export interface WriterCodegenOptions {
@ -70,39 +70,60 @@ export function generateWriterCodeForTlEntry(entry: TlEntry, params = DEFAULT_OP
if (!bare) ret += `w.uint(${entry.id});`
const flagsFields: Record<string, 1> = {}
const fieldConditions: Record<string, string> = {}
entry.arguments.forEach((arg) => {
if (arg.type === '#') {
ret += `var ${arg.name}=${includeFlags ? `v.${arg.name}` : '0'};`
entry.arguments.forEach((arg1) => {
const predicate = arg1.typeModifiers?.predicate
const usedByArgs = entry.arguments.filter((a) => a.typeModifiers?.predicate?.startsWith(arg.name + '.'))
const indexUsage: Record<string, TlArgument[]> = {}
let s
usedByArgs.forEach((arg1) => {
const index = arg1.typeModifiers!.predicate!.split('.')[1]
if (!indexUsage[index]) indexUsage[index] = []
indexUsage[index].push(arg1)
})
if (!predicate || (s = predicate.split('.'))[0] !== arg.name) {
return
}
const arg1Name = snakeToCamel(arg1.name)
const bitIndex = parseInt(s[1])
Object.entries(indexUsage).forEach(([index, args]) => {
const bitIndex = parseInt(index)
if (isNaN(bitIndex) || bitIndex < 0 || bitIndex > 32) {
throw new Error(`Invalid predicate: ${predicate} - invalid bit`)
throw new Error(`Invalid predicate: ${arg.name}.${bitIndex} - invalid bit`)
}
const action = `${arg.name}|=${1 << bitIndex};`
const conditions: string[] = []
args.forEach((arg1) => {
const arg1Name = snakeToCamel(arg1.name)
if (arg1.type === 'true') {
ret += `if(v.${arg1Name}===true)${action}`
conditions.push(`v.${arg1Name}===true`)
} else if (arg1.typeModifiers?.isVector || arg1.typeModifiers?.isBareVector) {
ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;if(_${arg1Name})${action}`
ret += `var _${arg1Name}=v.${arg1Name}&&v.${arg1Name}.length;`
conditions.push(`_${arg1Name}`)
} else {
ret += `var _${arg1Name}=v.${arg1Name}!==undefined;if(_${arg1Name})${action}`
ret += `var _${arg1Name}=v.${arg1Name}!==undefined;`
conditions.push(`_${arg1Name}`)
}
})
const action = `${arg.name}|=${1 << bitIndex};`
let condition: string
if (conditions.length > 1) {
condition = `_${arg.name}_${bitIndex}`
ret += `var ${condition}=${conditions.join('||')};`
} else {
condition = conditions[0]
}
ret += `if(${condition})${action}`
args.forEach((arg) => {
fieldConditions[arg.name] = condition
})
})
ret += `w.uint(${arg.name});`
flagsFields[arg.name] = 1
@ -118,7 +139,7 @@ export function generateWriterCodeForTlEntry(entry: TlEntry, params = DEFAULT_OP
if (arg.typeModifiers?.predicate) {
if (type === 'true') return // included in flags
ret += `if(_${argName})`
ret += `if(${fieldConditions[arg.name]})`
} else {
accessor = `h(v,'${argName}')`
}

View file

@ -74,6 +74,20 @@ describe('generateWriterCodeForTlEntry', () => {
)
})
it('generates code for constructors with multiple fields using the same flag', () => {
test(
'inputMediaPoll#f94e5f1 flags:# solution:flags.1?string solution_entities:flags.1?Vector<MessageEntity> = InputMedia;',
'var flags=0;',
'var _solution=v.solution!==undefined;',
'var _solutionEntities=v.solutionEntities&&v.solutionEntities.length;',
'var _flags_1=_solution||_solutionEntities;',
'if(_flags_1)flags|=2;',
'w.uint(flags);',
'if(_flags_1)w.string(v.solution);',
'if(_flags_1)w.vector(w.object,v.solutionEntities);',
)
})
it('generates code for constructors with vector arguments', () => {
test(
'contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector<Chat> users:Vector<User> = contacts.ResolvedPeer;',