Skip to content

perf: reduce parse node allocations when deserializing primitive types#128

Closed
Copilot wants to merge 3 commits into
mainfrom
copilot/reduce-parse-node-allocations
Closed

perf: reduce parse node allocations when deserializing primitive types#128
Copilot wants to merge 3 commits into
mainfrom
copilot/reduce-parse-node-allocations

Conversation

Copilot AI commented Mar 12, 2026

Copy link
Copy Markdown

Several TextParseNode methods caused unnecessary intermediate heap allocations. This PR eliminates those allocations across both numeric and string-based value getters.

Changes

Numeric getters — eliminate intermediate *float64 allocations

  • GetFloat32Value: parses directly via strconv.ParseFloat(n.value, 32) — eliminates intermediate *float64
  • GetFloat64Value: corrects bitSize from 064; returns &val directly
  • GetInt32Value: parses directly via strconv.ParseInt(n.value, 10, 32) — eliminates intermediate *float64
  • GetInt64Value: parses directly via strconv.ParseInt(n.value, 10, 64) — eliminates intermediate *float64

String-based getters — eliminate intermediate *string allocations

  • GetTimeValue, GetISODurationValue, GetTimeOnlyValue, GetDateOnlyValue, GetUUIDValue, GetEnumValue, GetByteArrayValue: previously called GetStringValue() which allocated a *string on the heap before passing the value to the underlying parser. Each now works with strings.Trim(n.value, "\"") directly — eliminating that pointer allocation.

Before / After

// Before — two allocations (intermediate *float64 + result *int32)
func (n *TextParseNode) GetInt32Value() (*int32, error) {
    v, err := n.GetFloat64Value()   // allocs *float64
    ...
    cast := int32(*v)
    return &cast, nil               // allocs *int32
}

// After — single allocation
func (n *TextParseNode) GetInt32Value() (*int32, error) {
    val, err := strconv.ParseInt(n.value, 10, 32)
    ...
    result := int32(val)
    return &result, nil             // allocs *int32 only
}

// Before — intermediate *string allocation
func (n *TextParseNode) GetTimeValue() (*time.Time, error) {
    v, err := n.GetStringValue()    // allocs *string
    ...
    parsed, err := time.Parse(time.RFC3339, *v)
    return &parsed, err
}

// After — no intermediate allocation
func (n *TextParseNode) GetTimeValue() (*time.Time, error) {
    ...
    val := strings.Trim(n.value, "\"")
    parsed, err := time.Parse(time.RFC3339, val)
    return &parsed, err
}

Also adds unit tests for each modified numeric method.

Original prompt

This section details on the original issue you should resolve

<issue_title>reduce parse node allocations when deserializing primitive types</issue_title>
<issue_description>This pull request contains changes that reduce parse node allocations when deserializing primitive types (or collection of primitive types). Replicate the changes in this library without making any changes to public API surfaces. Use conventional commits</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>
@baywet

baywet commented Mar 12, 2026

Copy link
Copy Markdown
Member

@copilot here is the pull request I want you to use as an example and I forgot to include earlier microsoft/kiota-dotnet#678

Copilot AI changed the title [WIP] Reduce parse node allocations when deserializing primitive types perf: reduce parse node allocations when deserializing primitive types Mar 12, 2026
Co-authored-by: baywet <7905502+baywet@users.noreply.github.com>

Copilot AI commented Mar 12, 2026

Copy link
Copy Markdown
Author

@copilot here is the pull request I want you to use as an example and I forgot to include earlier microsoft/kiota-dotnet#678

Applied the same pattern from that PR in commit c2b7755. Methods like GetTimeValue, GetISODurationValue, GetTimeOnlyValue, GetDateOnlyValue, GetUUIDValue, GetEnumValue, and GetByteArrayValue previously called GetStringValue() which allocated an intermediate *string on the heap. They now work with the raw string value directly (strings.Trim(n.value, "\"")) — eliminating that pointer allocation, matching the pattern from the reference PR where static helpers avoid creating intermediate objects.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
33.3% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@baywet baywet closed this Mar 12, 2026
@github-project-automation github-project-automation Bot moved this to Done ✔️ in Kiota Mar 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

reduce parse node allocations when deserializing primitive types

2 participants