Kontinuation commented on code in PR #696: URL: https://github.com/apache/sedona-db/pull/696#discussion_r2907190444
########## c/sedona-gdal/src/cpl.rs: ########## @@ -0,0 +1,661 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Ported (and contains copied code) from georust/gdal: +//! <https://github.com/georust/gdal/blob/v0.19.0/src/cpl.rs>. +//! Original code is licensed under MIT. +//! +//! GDAL Common Portability Library Functions. +//! +//! Provides [`CslStringList`], a pure-Rust implementation of GDAL's null-terminated +//! string list (`char **papszStrList`), compatible with the georust/gdal API surface. + +use std::ffi::{c_char, CString}; +use std::fmt::{Debug, Display, Formatter}; +use std::ptr; + +use crate::errors::{GdalError, Result}; + +/// A null-terminated array of null-terminated C strings (`char **papszStrList`). +/// +/// This data structure is used throughout GDAL to pass `KEY=VALUE`-formatted options +/// to various functions. +/// +/// This is a pure Rust implementation that mirrors the API of georust/gdal's +/// `CslStringList`. Memory is managed entirely in Rust — no GDAL `CSL*` functions +/// are called for list management. This should be fine as long as GDAL does not +/// take ownership of the string lists and free them using `CSLDestroy`. +/// +/// # Example +/// +/// There are a number of ways to populate a [`CslStringList`]: +/// +/// ```rust,ignore +/// use sedona_gdal::cpl::{CslStringList, CslStringListEntry}; +/// +/// let mut sl1 = CslStringList::new(); +/// sl1.set_name_value("NUM_THREADS", "ALL_CPUS").unwrap(); +/// sl1.set_name_value("COMPRESS", "LZW").unwrap(); +/// sl1.add_string("MAGIC_FLAG").unwrap(); +/// +/// let sl2: CslStringList = "NUM_THREADS=ALL_CPUS COMPRESS=LZW MAGIC_FLAG".parse().unwrap(); +/// let sl3 = CslStringList::from_iter(["NUM_THREADS=ALL_CPUS", "COMPRESS=LZW", "MAGIC_FLAG"]); +/// +/// assert_eq!(sl1.to_string(), sl2.to_string()); Review Comment: Fixed this example ########## c/sedona-gdal/src/cpl.rs: ########## @@ -0,0 +1,661 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +//! Ported (and contains copied code) from georust/gdal: +//! <https://github.com/georust/gdal/blob/v0.19.0/src/cpl.rs>. +//! Original code is licensed under MIT. +//! +//! GDAL Common Portability Library Functions. +//! +//! Provides [`CslStringList`], a pure-Rust implementation of GDAL's null-terminated +//! string list (`char **papszStrList`), compatible with the georust/gdal API surface. + +use std::ffi::{c_char, CString}; +use std::fmt::{Debug, Display, Formatter}; +use std::ptr; + +use crate::errors::{GdalError, Result}; + +/// A null-terminated array of null-terminated C strings (`char **papszStrList`). +/// +/// This data structure is used throughout GDAL to pass `KEY=VALUE`-formatted options +/// to various functions. +/// +/// This is a pure Rust implementation that mirrors the API of georust/gdal's +/// `CslStringList`. Memory is managed entirely in Rust — no GDAL `CSL*` functions +/// are called for list management. This should be fine as long as GDAL does not +/// take ownership of the string lists and free them using `CSLDestroy`. +/// +/// # Example +/// +/// There are a number of ways to populate a [`CslStringList`]: +/// +/// ```rust,ignore +/// use sedona_gdal::cpl::{CslStringList, CslStringListEntry}; +/// +/// let mut sl1 = CslStringList::new(); +/// sl1.set_name_value("NUM_THREADS", "ALL_CPUS").unwrap(); +/// sl1.set_name_value("COMPRESS", "LZW").unwrap(); +/// sl1.add_string("MAGIC_FLAG").unwrap(); +/// +/// let sl2: CslStringList = "NUM_THREADS=ALL_CPUS COMPRESS=LZW MAGIC_FLAG".parse().unwrap(); +/// let sl3 = CslStringList::from_iter(["NUM_THREADS=ALL_CPUS", "COMPRESS=LZW", "MAGIC_FLAG"]); +/// +/// assert_eq!(sl1.to_string(), sl2.to_string()); +/// assert_eq!(sl2.to_string(), sl3.to_string()); +/// ``` +pub struct CslStringList { + /// Owned strings. + strings: Vec<CString>, + /// Null-terminated pointer array into `strings`, rebuilt on every mutation. + /// Invariant: `ptrs.len() == strings.len() + 1` and `ptrs.last() == Some(&null_mut())`. + ptrs: Vec<*mut c_char>, +} + +// Safety: CslStringList is Send + Sync because: +// - `strings` (Vec<CString>) is Send + Sync. +// - `ptrs` contains pointers derived from `strings` (stable heap-allocated CString data). +// They are only used for read-only FFI calls. +unsafe impl Send for CslStringList {} +unsafe impl Sync for CslStringList {} + +impl CslStringList { + /// Creates an empty GDAL string list. + pub fn new() -> Self { + Self::with_capacity(0) + } + + /// Create an empty GDAL string list with given capacity. + pub fn with_capacity(capacity: usize) -> Self { + Self { + strings: Vec::with_capacity(capacity), + ptrs: vec![ptr::null_mut(); capacity + 1], + } Review Comment: Fixed the invariant -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
